xref: /titanic_41/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 0a701b1ec2b55bddc48b62124df936152ff820f7)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"@(#)smb_share.c	1.7	08/08/07 SMI"
27 
28 /*
29  * Lan Manager (SMB/CIFS) share interface implementation. This interface
30  * returns Win32 error codes, usually network error values (lmerr.h).
31  */
32 
33 #include <errno.h>
34 #include <synch.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <syslog.h>
39 #include <thread.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <netdb.h>
43 #include <synch.h>
44 #include <pthread.h>
45 #include <ctype.h>
46 #include <assert.h>
47 #include <sys/mnttab.h>
48 #include <sys/stat.h>
49 #include <sys/types.h>
50 
51 #include <smbsrv/libsmb.h>
52 #include <smbsrv/libsmbns.h>
53 
54 #include <libshare.h>
55 
56 #include <smbsrv/lm.h>
57 #include <smbsrv/smb_share.h>
58 #include <smbsrv/cifs.h>
59 
60 #include <smbsrv/ctype.h>
61 #include <smbsrv/smb_vops.h>
62 #include <smbsrv/nterror.h>
63 
64 /*
65  * Cache functions and vars
66  */
67 #define	SMB_SHARE_HTAB_SZ	1024
68 
69 static HT_HANDLE *smb_shr_handle = NULL;
70 static rwlock_t smb_shr_lock;
71 static pthread_t smb_shr_populate_thr;
72 
73 static uint32_t smb_shr_cache_create(void);
74 static void smb_shr_cache_destroy(void);
75 static void *smb_shr_cache_populate(void *);
76 static uint32_t smb_shr_cache_addent(smb_share_t *);
77 static void smb_shr_cache_delent(char *);
78 static uint32_t smb_shr_cache_chgent(smb_share_t *);
79 static void smb_shr_cache_freent(HT_ITEM *);
80 static uint32_t smb_shr_cache_loadent(sa_share_t, sa_resource_t);
81 static void smb_shr_cache_loadgrp(sa_group_t);
82 
83 static void smb_shr_set_ahcnt(char *, int);
84 static void smb_shr_set_oemname(smb_share_t *);
85 static uint32_t smb_shr_create_autohome(smb_share_t *);
86 static uint32_t smb_shr_create_ipc(void);
87 
88 /*
89  * sharemgr functions
90  */
91 static uint32_t smb_shr_sa_delent(smb_share_t *);
92 static uint32_t smb_shr_sa_addent(smb_share_t *);
93 static uint32_t smb_shr_sa_getent(sa_share_t, sa_resource_t, smb_share_t *);
94 static sa_group_t smb_shr_sa_getdefgrp(sa_handle_t);
95 
96 /*
97  * share publishing
98  */
99 #define	SMB_SHR_PUBLISH		0
100 #define	SMB_SHR_UNPUBLISH	1
101 
102 typedef struct smb_shr_pitem {
103 	list_node_t	spi_lnd;
104 	char		spi_name[MAXNAMELEN];
105 	char		spi_container[MAXPATHLEN];
106 	char		spi_op;
107 } smb_shr_pitem_t;
108 
109 /*
110  * publish queue states
111  */
112 #define	SMB_SHR_PQS_NOQUEUE	0
113 #define	SMB_SHR_PQS_READY	1	/* the queue is ready */
114 #define	SMB_SHR_PQS_PUBLISHING	2	/* publisher thread is running */
115 #define	SMB_SHR_PQS_STOPPING	3
116 
117 /*
118  * share publishing queue
119  */
120 typedef struct smb_shr_pqueue {
121 	int		spq_cnt;
122 	list_t		spq_list;
123 	mutex_t		spq_mtx;
124 	cond_t		spq_cv;
125 	uint32_t	spq_state;
126 } smb_shr_pqueue_t;
127 
128 static smb_shr_pqueue_t ad_queue;
129 static pthread_t smb_shr_publish_thr;
130 
131 static int smb_shr_publisher_start(void);
132 static void smb_shr_publisher_stop(void);
133 static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
134 static void *smb_shr_publisher(void *);
135 static void smb_shr_publish(const char *, const char *, char);
136 
137 
138 /*
139  * smb_shr_start
140  *
141  * Starts the publisher thread and another thread which
142  * populates the share cache by share information stored
143  * by sharemgr
144  */
145 int
146 smb_shr_start(void)
147 {
148 	pthread_attr_t tattr;
149 	int rc;
150 
151 	if ((rc = smb_shr_publisher_start()) != 0)
152 		return (rc);
153 
154 	(void) pthread_attr_init(&tattr);
155 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
156 	rc = pthread_create(&smb_shr_populate_thr, &tattr,
157 	    smb_shr_cache_populate, 0);
158 	(void) pthread_attr_destroy(&tattr);
159 
160 	return (rc);
161 }
162 
163 void
164 smb_shr_stop(void)
165 {
166 	smb_shr_cache_destroy();
167 	smb_shr_publisher_stop();
168 }
169 
170 /*
171  * smb_shr_count
172  *
173  * Return the total number of shares
174  */
175 int
176 smb_shr_count(void)
177 {
178 	int n_shares;
179 
180 	(void) rw_rdlock(&smb_shr_lock);
181 	n_shares = ht_get_total_items(smb_shr_handle);
182 	(void) rw_unlock(&smb_shr_lock);
183 
184 	return (n_shares);
185 }
186 
187 /*
188  * smb_shr_iterinit
189  *
190  * Initialize given iterator for traversing hash table.
191  */
192 void
193 smb_shr_iterinit(smb_shriter_t *shi)
194 {
195 	bzero(shi, sizeof (smb_shriter_t));
196 	shi->si_first = B_TRUE;
197 }
198 
199 /*
200  * smb_shr_iterate
201  *
202  * Iterate on the shares in the hash table. The iterator must be initialized
203  * before the first iteration. On subsequent calls, the iterator must be
204  * passed unchanged.
205  *
206  * Returns NULL on failure or when all shares are visited, otherwise
207  * returns information of visited share.
208  */
209 smb_share_t *
210 smb_shr_iterate(smb_shriter_t *shi)
211 {
212 	HT_ITEM *item;
213 	smb_share_t *share = NULL;
214 
215 	if (smb_shr_handle == NULL || shi == NULL)
216 		return (NULL);
217 
218 	(void) rw_rdlock(&smb_shr_lock);
219 	if (shi->si_first) {
220 		item = ht_findfirst(smb_shr_handle, &shi->si_hashiter);
221 		shi->si_first = B_FALSE;
222 	} else {
223 		item = ht_findnext(&shi->si_hashiter);
224 	}
225 
226 	if (item && item->hi_data) {
227 		share = &shi->si_share;
228 		bcopy(item->hi_data, share, sizeof (smb_share_t));
229 	}
230 	(void) rw_unlock(&smb_shr_lock);
231 
232 	return (share);
233 }
234 
235 /*
236  * smb_shr_create
237  *
238  * Adds the given to cache and if 'store' is B_TRUE it's also
239  * added to sharemgr
240  */
241 uint32_t
242 smb_shr_create(smb_share_t *si, boolean_t store)
243 {
244 	uint32_t status = NERR_Success;
245 	int rc;
246 
247 	assert(si != NULL);
248 
249 	if (!smb_shr_chkname(si->shr_name))
250 		return (ERROR_INVALID_NAME);
251 
252 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
253 		return (smb_shr_create_autohome(si));
254 
255 	if (smb_shr_exists(si->shr_name))
256 		return (NERR_DuplicateShare);
257 
258 	if ((status = smb_shr_cache_addent(si)) != NERR_Success)
259 		return (status);
260 
261 	if (store && (si->shr_flags & SMB_SHRF_PERM)) {
262 		if ((status = smb_shr_sa_addent(si)) != NERR_Success) {
263 			(void) smb_shr_cache_delent(si->shr_name);
264 			return (status);
265 		}
266 	}
267 
268 	rc = smb_dwncall_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
269 
270 	if (rc == 0) {
271 		smb_shr_publish(si->shr_name, si->shr_container,
272 		    SMB_SHR_PUBLISH);
273 		return (status);
274 	}
275 
276 	smb_shr_cache_delent(si->shr_name);
277 	if (store && (si->shr_flags & SMB_SHRF_PERM))
278 		(void) smb_shr_sa_delent(si);
279 
280 	/*
281 	 * rc == ENOENT means the shared directory doesn't exist
282 	 */
283 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
284 }
285 
286 /*
287  * smb_shr_delete
288  *
289  * Removes the specified share.
290  */
291 uint32_t
292 smb_shr_delete(char *sharename, boolean_t store)
293 {
294 	smb_share_t si;
295 	uint32_t status = NERR_Success;
296 
297 	assert(sharename != NULL);
298 
299 	if ((status = smb_shr_get(sharename, &si)) != NERR_Success)
300 		return (status);
301 
302 	if (si.shr_type & STYPE_IPC)
303 		return (ERROR_ACCESS_DENIED);
304 
305 	if (si.shr_flags & SMB_SHRF_AUTOHOME) {
306 		si.shr_refcnt--;
307 		if (si.shr_refcnt > 0) {
308 			smb_shr_set_ahcnt(si.shr_name, si.shr_refcnt);
309 			return (status);
310 		}
311 	}
312 
313 	if (store && (si.shr_flags & SMB_SHRF_PERM)) {
314 		if (smb_shr_sa_delent(&si) != NERR_Success)
315 			return (NERR_InternalError);
316 	}
317 
318 	smb_shr_cache_delent(si.shr_name);
319 	smb_shr_publish(si.shr_name, si.shr_container, SMB_SHR_UNPUBLISH);
320 	(void) smb_dwncall_share(SMB_SHROP_DELETE, si.shr_path, si.shr_name);
321 
322 	return (NERR_Success);
323 }
324 
325 /*
326  * smb_shr_rename
327  *
328  * Rename a share. Check that the current name exists and the new name
329  * doesn't exist. The rename is performed by deleting the current share
330  * definition and creating a new share with the new name.
331  */
332 uint32_t
333 smb_shr_rename(char *from_name, char *to_name)
334 {
335 	smb_share_t si;
336 	uint32_t status;
337 
338 	assert((from_name != NULL) && (to_name != NULL));
339 
340 	if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name))
341 		return (ERROR_INVALID_NAME);
342 
343 	if (!smb_shr_exists(from_name))
344 		return (NERR_NetNameNotFound);
345 
346 	if (smb_shr_exists(to_name))
347 		return (NERR_DuplicateShare);
348 
349 	if ((status = smb_shr_get(from_name, &si)) != NERR_Success)
350 		return (status);
351 
352 	if (si.shr_type & STYPE_IPC)
353 		return (ERROR_ACCESS_DENIED);
354 
355 	(void) strlcpy(si.shr_name, to_name, sizeof (si.shr_name));
356 	if ((status = smb_shr_cache_addent(&si)) != NERR_Success)
357 		return (status);
358 
359 	smb_shr_cache_delent(from_name);
360 	smb_shr_publish(from_name, si.shr_container, SMB_SHR_UNPUBLISH);
361 	smb_shr_publish(to_name, si.shr_container, SMB_SHR_PUBLISH);
362 
363 	return (NERR_Success);
364 }
365 
366 /*
367  * smb_shr_get
368  *
369  * Load the information for the specified share into the supplied share
370  * info structure.
371  */
372 uint32_t
373 smb_shr_get(char *sharename, smb_share_t *si)
374 {
375 	HT_ITEM *item;
376 
377 	(void) utf8_strlwr(sharename);
378 
379 	(void) rw_rdlock(&smb_shr_lock);
380 	item = ht_find_item(smb_shr_handle, sharename);
381 	if (item == NULL || item->hi_data == NULL) {
382 		(void) rw_unlock(&smb_shr_lock);
383 		return (NERR_NetNameNotFound);
384 	}
385 
386 	bcopy(item->hi_data, si, sizeof (smb_share_t));
387 	(void) rw_unlock(&smb_shr_lock);
388 
389 	return (NERR_Success);
390 }
391 
392 /*
393  * smb_shr_modify
394  *
395  * Modifies an existing share. Properties that can be modified are:
396  *
397  *   o comment
398  *   o AD container
399  */
400 uint32_t
401 smb_shr_modify(char *sharename, const char *cmnt,
402     const char *ad_container, boolean_t store)
403 {
404 	smb_share_t si;
405 	uint32_t status;
406 	boolean_t cmnt_changed = B_FALSE;
407 	boolean_t adc_changed = B_FALSE;
408 	char shr_container[MAXPATHLEN];
409 
410 	assert(sharename != NULL);
411 
412 	if ((cmnt == NULL) && (ad_container == NULL))
413 		/* no changes */
414 		return (NERR_Success);
415 
416 	if ((status = smb_shr_get(sharename, &si)) != NERR_Success)
417 		return (status);
418 
419 	if (si.shr_type & STYPE_IPC)
420 		return (ERROR_ACCESS_DENIED);
421 
422 	if (cmnt) {
423 		cmnt_changed = (strcmp(cmnt, si.shr_cmnt) != 0);
424 		if (cmnt_changed)
425 			(void) strlcpy(si.shr_cmnt, cmnt, sizeof (si.shr_cmnt));
426 	}
427 
428 	if (ad_container) {
429 		adc_changed = (strcmp(ad_container, si.shr_container) != 0);
430 		if (adc_changed) {
431 			/* save current container needed for unpublishing */
432 			(void) strlcpy(shr_container, si.shr_container,
433 			    sizeof (shr_container));
434 			(void) strlcpy(si.shr_container, ad_container,
435 			    sizeof (si.shr_container));
436 		}
437 	}
438 
439 	if (!cmnt_changed && !adc_changed)
440 		/* no changes */
441 		return (NERR_Success);
442 
443 	if (store && (si.shr_flags & SMB_SHRF_PERM)) {
444 		if (smb_shr_sa_addent(&si) != NERR_Success)
445 			return (NERR_InternalError);
446 	}
447 
448 	(void) smb_shr_cache_chgent(&si);
449 
450 	if (adc_changed) {
451 		smb_shr_publish(si.shr_name, shr_container,
452 		    SMB_SHR_UNPUBLISH);
453 		smb_shr_publish(si.shr_name, si.shr_container,
454 		    SMB_SHR_PUBLISH);
455 	}
456 
457 	return (NERR_Success);
458 }
459 
460 void
461 smb_shr_list(int offset, smb_shrlist_t *list)
462 {
463 	smb_shriter_t iterator;
464 	smb_share_t *si;
465 	int n = 0;
466 
467 	bzero(list, sizeof (smb_shrlist_t));
468 	smb_shr_iterinit(&iterator);
469 
470 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
471 		if (--offset > 0)
472 			continue;
473 
474 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
475 		    ((si->shr_type & STYPE_IPC) == 0)) {
476 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
477 			if (++n == LMSHARES_PER_REQUEST)
478 				break;
479 		}
480 	}
481 
482 	list->sl_cnt = n;
483 }
484 
485 
486 /*
487  * smb_shr_exists
488  *
489  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
490  */
491 boolean_t
492 smb_shr_exists(char *sharename)
493 {
494 	boolean_t exists;
495 
496 	if (sharename == NULL || *sharename == '\0')
497 		return (B_FALSE);
498 
499 	(void) utf8_strlwr(sharename);
500 
501 	(void) rw_rdlock(&smb_shr_lock);
502 	exists = (ht_find_item(smb_shr_handle, sharename) != NULL);
503 	(void) rw_unlock(&smb_shr_lock);
504 
505 	return (exists);
506 }
507 
508 /*
509  * smb_shr_is_special
510  *
511  * Special share reserved for interprocess communication (IPC$) or
512  * remote administration of the server (ADMIN$). Can also refer to
513  * administrative shares such as C$, D$, E$, and so forth.
514  */
515 int
516 smb_shr_is_special(char *sharename)
517 {
518 	int len;
519 
520 	if (sharename == NULL)
521 		return (0);
522 
523 	if ((len = strlen(sharename)) == 0)
524 		return (0);
525 
526 	if (sharename[len - 1] == '$')
527 		return (STYPE_SPECIAL);
528 
529 	return (0);
530 }
531 
532 /*
533  * smb_shr_is_restricted
534  *
535  * Check whether or not there is a restriction on a share. Restricted
536  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
537  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
538  * if the share is restricted. Otherwise B_FALSE is returned to indicate
539  * that there are no restrictions.
540  */
541 boolean_t
542 smb_shr_is_restricted(char *sharename)
543 {
544 	static char *restricted[] = {
545 		"IPC$"
546 	};
547 
548 	int i;
549 
550 	if (sharename == NULL)
551 		return (B_FALSE);
552 
553 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
554 		if (utf8_strcasecmp(restricted[i], sharename) == 0)
555 			return (B_TRUE);
556 	}
557 
558 	return (smb_shr_is_admin(sharename));
559 }
560 
561 /*
562  * smb_shr_is_admin
563  *
564  * Check whether or not access to the share should be restricted to
565  * administrators. This is a bit of a hack because what we're doing
566  * is checking for the default admin shares: C$, D$ etc.. There are
567  * other shares that have restrictions: see smb_shr_is_restricted().
568  *
569  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
570  * is returned to indicate that there are no restrictions.
571  */
572 boolean_t
573 smb_shr_is_admin(char *sharename)
574 {
575 	if (sharename == NULL)
576 		return (B_FALSE);
577 
578 	if (strlen(sharename) == 2 &&
579 	    mts_isalpha(sharename[0]) && sharename[1] == '$') {
580 		return (B_TRUE);
581 	}
582 
583 	return (B_FALSE);
584 }
585 
586 /*
587  * smb_shr_chkname
588  *
589  * Check if any invalid char is present in share name. According to
590  * MSDN article #236388: "Err Msg: The Share Name Contains Invalid
591  * Characters", the list of invalid character is:
592  *
593  * " / \ [ ] : | < > + ; , ? * =
594  *
595  * Also rejects if control characters are embedded.
596  */
597 boolean_t
598 smb_shr_chkname(char *sharename)
599 {
600 	char *invalid = "\"/\\[]:|<>+;,?*=";
601 	char *cp;
602 
603 	if (sharename == NULL)
604 		return (B_FALSE);
605 
606 	if (strpbrk(sharename, invalid))
607 		return (B_FALSE);
608 
609 	for (cp = sharename; *cp != '\0'; cp++) {
610 		if (iscntrl(*cp))
611 			return (B_FALSE);
612 	}
613 
614 	return (B_TRUE);
615 }
616 
617 /*
618  * smb_shr_get_realpath
619  *
620  * Derive the real path of a share from the path provided by a
621  * Windows client application during the share addition.
622  *
623  * For instance, the real path of C:\ is /cvol and the
624  * real path of F:\home is /vol1/home.
625  *
626  * clipath  - path provided by the Windows client is in the
627  *            format of <drive letter>:\<dir>
628  * realpath - path that will be stored as the directory field of
629  *            the smb_share_t structure of the share.
630  * maxlen   - maximum length fo the realpath buffer
631  *
632  * Return LAN Manager network error code.
633  */
634 /*ARGSUSED*/
635 uint32_t
636 smb_shr_get_realpath(const char *clipath, char *realpath, int maxlen)
637 {
638 	/* XXX do this translation */
639 	return (NERR_Success);
640 }
641 
642 /*
643  * ============================================
644  * Cache management functions
645  * ============================================
646  */
647 
648 /*
649  * smb_shr_cache_create
650  *
651  * Create the share hash table.
652  */
653 static uint32_t
654 smb_shr_cache_create(void)
655 {
656 	if (smb_shr_handle == NULL) {
657 		(void) rwlock_init(&smb_shr_lock, USYNC_THREAD, 0);
658 		(void) rw_wrlock(&smb_shr_lock);
659 
660 		smb_shr_handle = ht_create_table(SMB_SHARE_HTAB_SZ,
661 		    MAXNAMELEN, 0);
662 		if (smb_shr_handle == NULL) {
663 			(void) rw_unlock(&smb_shr_lock);
664 			return (NERR_InternalError);
665 		}
666 
667 		(void) ht_register_callback(smb_shr_handle,
668 		    smb_shr_cache_freent);
669 		(void) rw_unlock(&smb_shr_lock);
670 	}
671 
672 	return (NERR_Success);
673 }
674 
675 /*
676  * smb_shr_cache_destroy
677  *
678  * Destroys the share hash table.
679  */
680 static void
681 smb_shr_cache_destroy(void)
682 {
683 	if (smb_shr_handle) {
684 		(void) rw_wrlock(&smb_shr_lock);
685 		ht_destroy_table(smb_shr_handle);
686 		(void) rw_unlock(&smb_shr_lock);
687 		(void) rwlock_destroy(&smb_shr_lock);
688 		smb_shr_handle = NULL;
689 	}
690 }
691 
692 /*
693  * smb_shr_cache_populate
694  *
695  * Load shares from sharemgr
696  */
697 /*ARGSUSED*/
698 static void *
699 smb_shr_cache_populate(void *args)
700 {
701 	sa_handle_t handle;
702 	sa_group_t group, subgroup;
703 	char *gstate;
704 	boolean_t gdisabled;
705 
706 	if (smb_shr_cache_create() != NERR_Success) {
707 		syslog(LOG_ERR, "share: failed creating the cache");
708 		return (NULL);
709 	}
710 
711 	if (smb_shr_create_ipc() != NERR_Success) {
712 		syslog(LOG_ERR, "share: failed creating IPC$");
713 		return (NULL);
714 	}
715 
716 	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) {
717 		syslog(LOG_ERR, "share: failed connecting to backend");
718 		return (NULL);
719 	}
720 
721 	for (group = sa_get_group(handle, NULL);
722 	    group != NULL; group = sa_get_next_group(group)) {
723 		gstate = sa_get_group_attr(group, "state");
724 		if (gstate == NULL)
725 			continue;
726 
727 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
728 		sa_free_attr_string(gstate);
729 		if (gdisabled)
730 			continue;
731 
732 		smb_shr_cache_loadgrp(group);
733 		for (subgroup = sa_get_sub_group(group);
734 		    subgroup != NULL;
735 		    subgroup = sa_get_next_group(subgroup)) {
736 			smb_shr_cache_loadgrp(subgroup);
737 		}
738 
739 	}
740 
741 	sa_fini(handle);
742 	return (NULL);
743 }
744 
745 static uint32_t
746 smb_shr_cache_addent(smb_share_t *si)
747 {
748 	smb_share_t *cache_ent;
749 	uint32_t status = NERR_Success;
750 
751 	/*
752 	 * allocate memory for the entry that needs to be cached.
753 	 */
754 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
755 		return (ERROR_NOT_ENOUGH_MEMORY);
756 
757 	bcopy(si, cache_ent, sizeof (smb_share_t));
758 
759 	(void) utf8_strlwr(cache_ent->shr_name);
760 	smb_shr_set_oemname(cache_ent);
761 	if ((si->shr_type & STYPE_IPC) == 0)
762 		cache_ent->shr_type = STYPE_DISKTREE;
763 	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
764 
765 	(void) rw_wrlock(&smb_shr_lock);
766 	if (ht_add_item(smb_shr_handle, cache_ent->shr_name, cache_ent)
767 	    == NULL) {
768 		syslog(LOG_DEBUG, "share: failed adding %s to cache",
769 		    cache_ent->shr_name);
770 		free(cache_ent);
771 		status = NERR_InternalError;
772 	}
773 	(void) rw_unlock(&smb_shr_lock);
774 
775 	return (status);
776 }
777 
778 static void
779 smb_shr_cache_delent(char *sharename)
780 {
781 	(void) utf8_strlwr(sharename);
782 	(void) rw_wrlock(&smb_shr_lock);
783 	(void) ht_remove_item(smb_shr_handle, sharename);
784 	(void) rw_unlock(&smb_shr_lock);
785 }
786 
787 static uint32_t
788 smb_shr_cache_chgent(smb_share_t *si)
789 {
790 	smb_share_t *cache_ent;
791 	uint32_t status = NERR_Success;
792 
793 	/*
794 	 * allocate memory for the entry that needs to be cached.
795 	 */
796 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
797 		return (ERROR_NOT_ENOUGH_MEMORY);
798 
799 	bcopy(si, cache_ent, sizeof (smb_share_t));
800 	(void) utf8_strlwr(cache_ent->shr_name);
801 
802 	(void) rw_wrlock(&smb_shr_lock);
803 	if (ht_replace_item(smb_shr_handle, cache_ent->shr_name, cache_ent)
804 	    == NULL) {
805 		syslog(LOG_DEBUG, "share: failed modifying %s",
806 		    cache_ent->shr_name);
807 		free(cache_ent);
808 		status = NERR_InternalError;
809 	}
810 	(void) rw_unlock(&smb_shr_lock);
811 
812 	return (status);
813 }
814 
815 static uint32_t
816 smb_shr_create_autohome(smb_share_t *si)
817 {
818 	uint32_t status = NERR_Success;
819 	int rc;
820 
821 	if (si->shr_refcnt == 0) {
822 		if ((status = smb_shr_cache_addent(si)) != NERR_Success)
823 			return (status);
824 
825 		rc = smb_dwncall_share(SMB_SHROP_ADD, si->shr_path,
826 		    si->shr_name);
827 
828 		if (rc != 0) {
829 			smb_shr_cache_delent(si->shr_name);
830 			return ((rc == ENOENT)
831 			    ? NERR_UnknownDevDir : NERR_InternalError);
832 		}
833 
834 		smb_shr_publish(si->shr_name, si->shr_container,
835 		    SMB_SHR_PUBLISH);
836 	}
837 
838 	si->shr_refcnt++;
839 	smb_shr_set_ahcnt(si->shr_name, si->shr_refcnt);
840 	return (status);
841 }
842 
843 static uint32_t
844 smb_shr_create_ipc(void)
845 {
846 	smb_share_t ipc;
847 
848 	bzero(&ipc, sizeof (smb_share_t));
849 	(void) strcpy(ipc.shr_name, "IPC$");
850 	(void) strcpy(ipc.shr_cmnt, "Remote IPC");
851 	ipc.shr_flags = SMB_SHRF_TRANS;
852 	ipc.shr_type = STYPE_IPC;
853 	return (smb_shr_cache_addent(&ipc));
854 }
855 
856 /*
857  * loads the given resource
858  */
859 static uint32_t
860 smb_shr_cache_loadent(sa_share_t share, sa_resource_t resource)
861 {
862 	smb_share_t si;
863 	uint32_t status;
864 
865 	if ((status = smb_shr_sa_getent(share, resource, &si)) != NERR_Success)
866 		return (status);
867 
868 	if ((status = smb_shr_cache_addent(&si)) == NERR_Success)
869 		smb_shr_publish(si.shr_name, si.shr_container, SMB_SHR_PUBLISH);
870 
871 	if (status != NERR_Success) {
872 		syslog(LOG_ERR, "share: failed loading %s (%d)", si.shr_name,
873 		    status);
874 	}
875 
876 	return (status);
877 }
878 
879 /*
880  * smb_shr_cache_loadgrp
881  *
882  * Helper function for smb_shr_cache_populate.
883  * It attempts to load the shares contained in the given group.
884  * It will check to see if "smb" protocol is enabled or
885  * not on the given group. This is needed in the ZFS case where
886  * the top level ZFS group won't have "smb" protocol
887  * enabled but the sub-groups will.
888  */
889 static void
890 smb_shr_cache_loadgrp(sa_group_t group)
891 {
892 	sa_share_t share;
893 	sa_resource_t resource;
894 
895 	/* Don't bother if "smb" isn't set on the group */
896 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
897 		return;
898 
899 	for (share = sa_get_share(group, NULL);
900 	    share != NULL; share = sa_get_next_share(share)) {
901 		for (resource = sa_get_share_resource(share, NULL);
902 		    resource != NULL;
903 		    resource = sa_get_next_resource(resource)) {
904 			(void) smb_shr_cache_loadent(share, resource);
905 		}
906 	}
907 }
908 
909 /*
910  * smb_shr_cache_freent
911  *
912  * Call back to free given cache entry
913  */
914 static void
915 smb_shr_cache_freent(HT_ITEM *item)
916 {
917 	if (item && item->hi_data)
918 		free(item->hi_data);
919 }
920 
921 /*
922  * smb_shr_set_ahcnt
923  *
924  * sets the autohome reference count for the given share
925  */
926 static void
927 smb_shr_set_ahcnt(char *sharename, int refcnt)
928 {
929 	smb_share_t *si;
930 	HT_ITEM *item;
931 
932 	(void) rw_wrlock(&smb_shr_lock);
933 	item = ht_find_item(smb_shr_handle, sharename);
934 	if (item == NULL || item->hi_data == NULL) {
935 		(void) rw_unlock(&smb_shr_lock);
936 		return;
937 	}
938 
939 	si = (smb_share_t *)item->hi_data;
940 	si->shr_refcnt = refcnt;
941 	(void) rw_unlock(&smb_shr_lock);
942 }
943 
944 /*
945  * smb_shr_set_oemname
946  *
947  * Generates the OEM name of the given share. If it's
948  * shorter than 13 chars it'll be saved in si->shr_oemname.
949  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME
950  * will be set in si->shr_flags.
951  */
952 static void
953 smb_shr_set_oemname(smb_share_t *si)
954 {
955 	unsigned int cpid = oem_get_smb_cpid();
956 	mts_wchar_t *unibuf;
957 	char *oem_name;
958 	int length;
959 
960 	length = strlen(si->shr_name) + 1;
961 
962 	oem_name = malloc(length);
963 	unibuf = malloc(length * sizeof (mts_wchar_t));
964 	if ((oem_name == NULL) || (unibuf == NULL)) {
965 		free(oem_name);
966 		free(unibuf);
967 		return;
968 	}
969 
970 	(void) mts_mbstowcs(unibuf, si->shr_name, length);
971 
972 	if (unicodestooems(oem_name, unibuf, length, cpid) == 0)
973 		(void) strcpy(oem_name, si->shr_name);
974 
975 	free(unibuf);
976 
977 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
978 		si->shr_flags |= SMB_SHRF_LONGNAME;
979 		*si->shr_oemname = '\0';
980 	} else {
981 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
982 		(void) strlcpy(si->shr_oemname, oem_name,
983 		    SMB_SHARE_OEMNAME_MAX);
984 	}
985 
986 	free(oem_name);
987 }
988 
989 /*
990  * ============================================
991  * Interfaces to sharemgr
992  * ============================================
993  */
994 
995 /*
996  * Stores the given share in sharemgr
997  */
998 static uint32_t
999 smb_shr_sa_addent(smb_share_t *si)
1000 {
1001 	sa_handle_t handle;
1002 	sa_share_t share;
1003 	sa_group_t group;
1004 	sa_resource_t resource;
1005 	boolean_t share_created = B_FALSE;
1006 	int err;
1007 
1008 	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
1009 		return (NERR_InternalError);
1010 
1011 	share = sa_find_share(handle, si->shr_path);
1012 	if (share == NULL) {
1013 		group = smb_shr_sa_getdefgrp(handle);
1014 		if (group == NULL) {
1015 			sa_fini(handle);
1016 			return (NERR_InternalError);
1017 		}
1018 
1019 		share = sa_add_share(group, si->shr_path, SA_SHARE_PERMANENT,
1020 		    &err);
1021 		if (share == NULL) {
1022 			sa_fini(handle);
1023 			return (NERR_InternalError);
1024 		}
1025 		share_created = B_TRUE;
1026 	}
1027 
1028 	resource = sa_get_share_resource(share, si->shr_name);
1029 	if (resource == NULL) {
1030 		resource = sa_add_resource(share, si->shr_name,
1031 		    SA_SHARE_PERMANENT, &err);
1032 		if (resource == NULL)
1033 			goto failure;
1034 	}
1035 
1036 	if (sa_set_resource_attr(resource, "description", si->shr_cmnt)
1037 	    != SA_OK) {
1038 		goto failure;
1039 	}
1040 
1041 	if (sa_set_resource_attr(resource, SMB_SHROPT_AD_CONTAINER,
1042 	    si->shr_container) != SA_OK) {
1043 		goto failure;
1044 	}
1045 
1046 	sa_fini(handle);
1047 	return (NERR_Success);
1048 
1049 failure:
1050 	if (share_created && (share != NULL))
1051 		(void) sa_remove_share(share);
1052 
1053 	if (resource != NULL)
1054 		(void) sa_remove_resource(resource);
1055 
1056 	sa_fini(handle);
1057 	return (NERR_InternalError);
1058 }
1059 
1060 static uint32_t
1061 smb_shr_sa_getent(sa_share_t share, sa_resource_t resource, smb_share_t *si)
1062 {
1063 	sa_property_t prop;
1064 	sa_optionset_t opts;
1065 	char *val = NULL;
1066 	char *path;
1067 	char *rname;
1068 
1069 	if ((path = sa_get_share_attr(share, "path")) == NULL)
1070 		return (NERR_InternalError);
1071 
1072 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
1073 		sa_free_attr_string(path);
1074 		return (NERR_InternalError);
1075 	}
1076 
1077 	bzero(si, sizeof (smb_share_t));
1078 	/* Share is read from SMF so it should be permanent */
1079 	si->shr_flags = SMB_SHRF_PERM;
1080 
1081 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
1082 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
1083 
1084 	sa_free_attr_string(path);
1085 	sa_free_attr_string(rname);
1086 
1087 	val = sa_get_resource_description(resource);
1088 	if (val == NULL)
1089 		val = sa_get_share_description(share);
1090 
1091 	if (val != NULL) {
1092 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
1093 		sa_free_share_description(val);
1094 	}
1095 
1096 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
1097 	if (opts == NULL)
1098 		return (NERR_Success);
1099 
1100 	prop = (sa_property_t)sa_get_property(opts, SMB_SHROPT_AD_CONTAINER);
1101 	if (prop != NULL) {
1102 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1103 			(void) strlcpy(si->shr_container, val,
1104 			    sizeof (si->shr_container));
1105 			free(val);
1106 		}
1107 	}
1108 	sa_free_derived_optionset(opts);
1109 
1110 	return (NERR_Success);
1111 }
1112 
1113 /*
1114  * Removes the share from sharemgr
1115  */
1116 static uint32_t
1117 smb_shr_sa_delent(smb_share_t *si)
1118 {
1119 	sa_handle_t handle;
1120 	sa_share_t share;
1121 	sa_resource_t resource;
1122 
1123 	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
1124 		return (NERR_InternalError);
1125 
1126 	if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
1127 		sa_fini(handle);
1128 		return (NERR_InternalError);
1129 	}
1130 
1131 	if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) {
1132 		sa_fini(handle);
1133 		return (NERR_InternalError);
1134 	}
1135 
1136 	if (sa_remove_resource(resource) != SA_OK) {
1137 		sa_fini(handle);
1138 		return (NERR_InternalError);
1139 	}
1140 
1141 	sa_fini(handle);
1142 	return (NERR_Success);
1143 }
1144 
1145 /*
1146  * smb_shr_sa_getdefgrp
1147  *
1148  * If default group for CIFS shares (i.e. "smb") exists
1149  * then it will return the group handle, otherwise it will
1150  * create the group and return the handle.
1151  *
1152  * All the shares created by CIFS clients (this is only possible
1153  * via RPC) will be added to "smb" groups.
1154  */
1155 static sa_group_t
1156 smb_shr_sa_getdefgrp(sa_handle_t handle)
1157 {
1158 	sa_group_t group = NULL;
1159 	int err;
1160 
1161 	group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
1162 	if (group != NULL)
1163 		return (group);
1164 
1165 	group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
1166 	if (group == NULL)
1167 		return (NULL);
1168 
1169 	if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) {
1170 		(void) sa_remove_group(group);
1171 		group = NULL;
1172 	}
1173 
1174 	return (group);
1175 }
1176 
1177 /*
1178  * ============================================
1179  * Share publishing functions
1180  * ============================================
1181  */
1182 
1183 /*
1184  * Put the share on publish queue.
1185  */
1186 static void
1187 smb_shr_publish(const char *sharename, const char *container, char op)
1188 {
1189 	smb_shr_pitem_t *item = NULL;
1190 
1191 	if (container == NULL || *container == '\0')
1192 		return;
1193 
1194 	(void) mutex_lock(&ad_queue.spq_mtx);
1195 	switch (ad_queue.spq_state) {
1196 	case SMB_SHR_PQS_READY:
1197 	case SMB_SHR_PQS_PUBLISHING:
1198 		break;
1199 	default:
1200 		(void) mutex_unlock(&ad_queue.spq_mtx);
1201 		return;
1202 	}
1203 	(void) mutex_unlock(&ad_queue.spq_mtx);
1204 
1205 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL) {
1206 		syslog(LOG_DEBUG, "failed allocating share publish item");
1207 		return;
1208 	}
1209 
1210 	item->spi_op = op;
1211 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
1212 	(void) strlcpy(item->spi_container, container,
1213 	    sizeof (item->spi_container));
1214 
1215 	(void) mutex_lock(&ad_queue.spq_mtx);
1216 	list_insert_tail(&ad_queue.spq_list, item);
1217 	ad_queue.spq_cnt++;
1218 	(void) cond_signal(&ad_queue.spq_cv);
1219 	(void) mutex_unlock(&ad_queue.spq_mtx);
1220 }
1221 
1222 static int
1223 smb_shr_publisher_start(void)
1224 {
1225 	pthread_attr_t tattr;
1226 	int rc;
1227 
1228 	(void) mutex_lock(&ad_queue.spq_mtx);
1229 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
1230 		(void) mutex_unlock(&ad_queue.spq_mtx);
1231 		errno = EINVAL;
1232 		return (-1);
1233 	}
1234 
1235 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
1236 	    offsetof(smb_shr_pitem_t, spi_lnd));
1237 	ad_queue.spq_state = SMB_SHR_PQS_READY;
1238 	(void) mutex_unlock(&ad_queue.spq_mtx);
1239 
1240 	(void) pthread_attr_init(&tattr);
1241 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1242 	rc = pthread_create(&smb_shr_publish_thr, &tattr,
1243 	    smb_shr_publisher, 0);
1244 	(void) pthread_attr_destroy(&tattr);
1245 
1246 	return (rc);
1247 }
1248 
1249 static void
1250 smb_shr_publisher_stop(void)
1251 {
1252 	(void) mutex_lock(&ad_queue.spq_mtx);
1253 	switch (ad_queue.spq_state) {
1254 	case SMB_SHR_PQS_READY:
1255 	case SMB_SHR_PQS_PUBLISHING:
1256 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
1257 		(void) cond_signal(&ad_queue.spq_cv);
1258 		break;
1259 	default:
1260 		break;
1261 	}
1262 	(void) mutex_unlock(&ad_queue.spq_mtx);
1263 }
1264 
1265 /*
1266  * This functions waits to be signaled and once running
1267  * will publish/unpublish any items in the ad_queue
1268  */
1269 /*ARGSUSED*/
1270 static void *
1271 smb_shr_publisher(void *arg)
1272 {
1273 	smb_ads_handle_t *ah;
1274 	smb_shr_pitem_t *shr;
1275 	list_t publist;
1276 	char hostname[MAXHOSTNAMELEN];
1277 
1278 	(void) mutex_lock(&ad_queue.spq_mtx);
1279 	if (ad_queue.spq_state == SMB_SHR_PQS_READY) {
1280 		ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
1281 	} else {
1282 		(void) mutex_unlock(&ad_queue.spq_mtx);
1283 		return (NULL);
1284 	}
1285 	(void) mutex_unlock(&ad_queue.spq_mtx);
1286 
1287 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
1288 	list_create(&publist, sizeof (smb_shr_pitem_t),
1289 	    offsetof(smb_shr_pitem_t, spi_lnd));
1290 
1291 	for (;;) {
1292 		(void) mutex_lock(&ad_queue.spq_mtx);
1293 		while ((ad_queue.spq_cnt == 0) &&
1294 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING))
1295 			(void) cond_wait(&ad_queue.spq_cv, &ad_queue.spq_mtx);
1296 
1297 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
1298 			(void) mutex_unlock(&ad_queue.spq_mtx);
1299 			break;
1300 		}
1301 
1302 		if ((ah = smb_ads_open()) == NULL) {
1303 			(void) mutex_unlock(&ad_queue.spq_mtx);
1304 			continue;
1305 		}
1306 
1307 		/*
1308 		 * Transfer queued items to the local list so the mutex
1309 		 * can be quickly released
1310 		 */
1311 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
1312 			list_remove(&ad_queue.spq_list, shr);
1313 			ad_queue.spq_cnt--;
1314 			list_insert_tail(&publist, shr);
1315 		}
1316 		(void) mutex_unlock(&ad_queue.spq_mtx);
1317 
1318 		smb_shr_publisher_send(ah, &publist, hostname);
1319 		smb_ads_close(ah);
1320 	}
1321 
1322 	/* Remove any leftover items from publishing queue */
1323 	(void) mutex_lock(&ad_queue.spq_mtx);
1324 	while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
1325 		list_remove(&ad_queue.spq_list, shr);
1326 		free(shr);
1327 	}
1328 	ad_queue.spq_cnt = 0;
1329 	list_destroy(&ad_queue.spq_list);
1330 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
1331 	(void) mutex_unlock(&ad_queue.spq_mtx);
1332 
1333 	list_destroy(&publist);
1334 	return (NULL);
1335 }
1336 
1337 /*
1338  * Takes item from the given list and [un]publish them one by one.
1339  * In each iteration it checks the status of the publisher thread
1340  * and if it's been stopped then it continues to just empty the list
1341  */
1342 static void
1343 smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
1344 {
1345 	smb_shr_pitem_t *shr;
1346 	boolean_t publish = B_TRUE;
1347 
1348 	while ((shr = list_head(publist)) != NULL) {
1349 		list_remove(publist, shr);
1350 		if (publish) {
1351 			(void) mutex_unlock(&ad_queue.spq_mtx);
1352 			if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING)
1353 				publish = B_FALSE;
1354 			(void) mutex_unlock(&ad_queue.spq_mtx);
1355 
1356 			if (shr->spi_op == SMB_SHR_PUBLISH)
1357 				(void) smb_ads_publish_share(ah, shr->spi_name,
1358 				    NULL, shr->spi_container, host);
1359 			else
1360 				(void) smb_ads_remove_share(ah, shr->spi_name,
1361 				    NULL, shr->spi_container, host);
1362 		}
1363 		free(shr);
1364 	}
1365 }
1366