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