xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 7052:efa04b030974)
1*7052Samw /*
2*7052Samw  * CDDL HEADER START
3*7052Samw  *
4*7052Samw  * The contents of this file are subject to the terms of the
5*7052Samw  * Common Development and Distribution License (the "License").
6*7052Samw  * You may not use this file except in compliance with the License.
7*7052Samw  *
8*7052Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7052Samw  * or http://www.opensolaris.org/os/licensing.
10*7052Samw  * See the License for the specific language governing permissions
11*7052Samw  * and limitations under the License.
12*7052Samw  *
13*7052Samw  * When distributing Covered Code, include this CDDL HEADER in each
14*7052Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7052Samw  * If applicable, add the following below this CDDL HEADER, with the
16*7052Samw  * fields enclosed by brackets "[]" replaced with your own identifying
17*7052Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7052Samw  *
19*7052Samw  * CDDL HEADER END
20*7052Samw  */
21*7052Samw /*
22*7052Samw  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7052Samw  * Use is subject to license terms.
24*7052Samw  */
25*7052Samw 
26*7052Samw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7052Samw 
28*7052Samw /*
29*7052Samw  * Lan Manager (SMB/CIFS) share interface implementation. This interface
30*7052Samw  * returns Win32 error codes, usually network error values (lmerr.h).
31*7052Samw  */
32*7052Samw 
33*7052Samw #include <errno.h>
34*7052Samw #include <synch.h>
35*7052Samw #include <stdio.h>
36*7052Samw #include <stdlib.h>
37*7052Samw #include <strings.h>
38*7052Samw #include <syslog.h>
39*7052Samw #include <thread.h>
40*7052Samw #include <fcntl.h>
41*7052Samw #include <unistd.h>
42*7052Samw #include <netdb.h>
43*7052Samw #include <synch.h>
44*7052Samw #include <pthread.h>
45*7052Samw #include <sys/mnttab.h>
46*7052Samw #include <sys/stat.h>
47*7052Samw #include <sys/types.h>
48*7052Samw #include <sys/queue.h>
49*7052Samw #include <ctype.h>
50*7052Samw 
51*7052Samw #include <smbsrv/libsmb.h>
52*7052Samw #include <smbsrv/libsmbns.h>
53*7052Samw 
54*7052Samw #include <libshare.h>
55*7052Samw 
56*7052Samw #include <smbsrv/lm.h>
57*7052Samw #include <smbsrv/smb_share.h>
58*7052Samw #include <smbsrv/cifs.h>
59*7052Samw 
60*7052Samw #include <smbsrv/ctype.h>
61*7052Samw #include <smbsrv/smb_vops.h>
62*7052Samw #include <smbsrv/smb_fsd.h>
63*7052Samw 
64*7052Samw #define	SMB_SHARE_HTAB_SZ	1024
65*7052Samw 
66*7052Samw #define	SMB_SHARE_PUBLISH	0
67*7052Samw #define	SMB_SHARE_UNPUBLISH	1
68*7052Samw 
69*7052Samw static HT_HANDLE *smb_shr_handle = NULL;
70*7052Samw static rwlock_t smb_shr_lock;
71*7052Samw static pthread_t smb_shr_cache_populatethr;
72*7052Samw 
73*7052Samw static uint32_t smb_shr_cache_create(void);
74*7052Samw static void *smb_shr_cache_populate(void *);
75*7052Samw static int smb_shr_del_shmgr(smb_share_t *);
76*7052Samw static int smb_shr_set_shmgr(smb_share_t *);
77*7052Samw static uint32_t smb_shr_set_refcnt(char *, int);
78*7052Samw static void smb_shr_set_oemname(smb_share_t *);
79*7052Samw 
80*7052Samw typedef struct smb_shr_adinfo {
81*7052Samw 	TAILQ_ENTRY(smb_shr_adinfo) next;
82*7052Samw 	char name[MAXNAMELEN];
83*7052Samw 	char container[MAXPATHLEN];
84*7052Samw 	char flag;
85*7052Samw } smb_shr_adinfo_t;
86*7052Samw 
87*7052Samw typedef struct smb_shr_adqueue {
88*7052Samw 	int nentries;
89*7052Samw 	TAILQ_HEAD(adqueue, smb_shr_adinfo) adlist;
90*7052Samw } smb_shr_adqueue_t;
91*7052Samw 
92*7052Samw static smb_shr_adqueue_t ad_queue;
93*7052Samw static int publish_on = 0;
94*7052Samw 
95*7052Samw static pthread_t smb_shr_publish_thr;
96*7052Samw static mutex_t smb_shr_publish_mtx = PTHREAD_MUTEX_INITIALIZER;
97*7052Samw static cond_t smb_shr_publish_cv = DEFAULTCV;
98*7052Samw 
99*7052Samw static void *smb_shr_publisher(void *);
100*7052Samw static void smb_shr_stop_publish(void);
101*7052Samw static void smb_shr_publish(smb_share_t *, char, int);
102*7052Samw 
103*7052Samw /*
104*7052Samw  * Start loading lmshare information from sharemanager
105*7052Samw  * and create the cache.
106*7052Samw  */
107*7052Samw int
108*7052Samw smb_shr_start(void)
109*7052Samw {
110*7052Samw 	int rc;
111*7052Samw 
112*7052Samw 	rc = pthread_create(&smb_shr_publish_thr, NULL,
113*7052Samw 	    smb_shr_publisher, 0);
114*7052Samw 	if (rc != 0) {
115*7052Samw 		syslog(LOG_ERR, "Failed to start publisher thread, "
116*7052Samw 		    "share publishing is disabled");
117*7052Samw 	}
118*7052Samw 
119*7052Samw 	rc = pthread_create(&smb_shr_cache_populatethr, NULL,
120*7052Samw 	    smb_shr_cache_populate, 0);
121*7052Samw 	if (rc != 0) {
122*7052Samw 		syslog(LOG_ERR, "Failed to start share loading, "
123*7052Samw 		    "existing shares will not be available");
124*7052Samw 	}
125*7052Samw 
126*7052Samw 	return (rc);
127*7052Samw }
128*7052Samw 
129*7052Samw void
130*7052Samw smb_shr_stop(void)
131*7052Samw {
132*7052Samw 	smb_shr_stop_publish();
133*7052Samw }
134*7052Samw 
135*7052Samw /*
136*7052Samw  * lmshare_load_shares
137*7052Samw  *
138*7052Samw  * Helper function for smb_shr_cache_populate. It attempts to load the shares
139*7052Samw  * contained in the group.
140*7052Samw  */
141*7052Samw 
142*7052Samw static void
143*7052Samw lmshare_load_shares(sa_group_t group)
144*7052Samw {
145*7052Samw 	sa_share_t share;
146*7052Samw 	sa_resource_t resource;
147*7052Samw 	smb_share_t si;
148*7052Samw 	char *path, *rname;
149*7052Samw 
150*7052Samw 	/* Don't bother if "smb" isn't set on the group */
151*7052Samw 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
152*7052Samw 		return;
153*7052Samw 
154*7052Samw 	for (share = sa_get_share(group, NULL);
155*7052Samw 	    share != NULL; share = sa_get_next_share(share)) {
156*7052Samw 		path = sa_get_share_attr(share, "path");
157*7052Samw 		if (path == NULL) {
158*7052Samw 			continue;
159*7052Samw 		}
160*7052Samw 		for (resource = sa_get_share_resource(share, NULL);
161*7052Samw 		    resource != NULL;
162*7052Samw 		    resource = sa_get_next_resource(resource)) {
163*7052Samw 			rname = sa_get_resource_attr(resource, "name");
164*7052Samw 			if (rname == NULL) {
165*7052Samw 				syslog(LOG_ERR, "Invalid share "
166*7052Samw 				    "resource for path: %s", path);
167*7052Samw 				continue;
168*7052Samw 			}
169*7052Samw 			smb_build_lmshare_info(rname, path, resource, &si);
170*7052Samw 			sa_free_attr_string(rname);
171*7052Samw 			if (smb_shr_add(&si, 0) != NERR_Success) {
172*7052Samw 				syslog(LOG_ERR, "Failed to load "
173*7052Samw 				    "share %s", si.shr_name);
174*7052Samw 			}
175*7052Samw 		}
176*7052Samw 		/* We are done with all shares for same path */
177*7052Samw 		sa_free_attr_string(path);
178*7052Samw 	}
179*7052Samw }
180*7052Samw 
181*7052Samw /*
182*7052Samw  * smb_shr_cache_populate
183*7052Samw  *
184*7052Samw  * Load shares from sharemanager.  The args argument is currently not
185*7052Samw  * used. The function walks through all the groups in libshare and
186*7052Samw  * calls lmshare_load_shares for each group found. It also looks for
187*7052Samw  * sub-groups and calls lmshare_load_shares for each sub-group found.
188*7052Samw  */
189*7052Samw 
190*7052Samw /*ARGSUSED*/
191*7052Samw static void *
192*7052Samw smb_shr_cache_populate(void *args)
193*7052Samw {
194*7052Samw 	sa_handle_t handle;
195*7052Samw 	sa_group_t group, subgroup;
196*7052Samw 	char *gstate;
197*7052Samw 
198*7052Samw 	if (smb_shr_cache_create() != NERR_Success) {
199*7052Samw 		syslog(LOG_ERR, "Failed to create share hash table");
200*7052Samw 		return (NULL);
201*7052Samw 	}
202*7052Samw 
203*7052Samw 	handle = sa_init(SA_INIT_SHARE_API);
204*7052Samw 	if (handle == NULL) {
205*7052Samw 		syslog(LOG_ERR, "Failed to load share "
206*7052Samw 		    "information: no libshare handle");
207*7052Samw 		return (NULL);
208*7052Samw 	}
209*7052Samw 
210*7052Samw 	for (group = sa_get_group(handle, NULL);
211*7052Samw 	    group != NULL; group = sa_get_next_group(group)) {
212*7052Samw 		gstate = sa_get_group_attr(group, "state");
213*7052Samw 		if (gstate == NULL)
214*7052Samw 			continue;
215*7052Samw 		if (strcasecmp(gstate, "disabled") == 0) {
216*7052Samw 			/* Skip disabled or unknown state group */
217*7052Samw 			sa_free_attr_string(gstate);
218*7052Samw 			continue;
219*7052Samw 		}
220*7052Samw 		sa_free_attr_string(gstate);
221*7052Samw 
222*7052Samw 		/*
223*7052Samw 		 * Attempt to load the shares.  lmshare_load_shares
224*7052Samw 		 * will check to see if the protocol is enabled or
225*7052Samw 		 * not. We then want to check for any sub-groups on
226*7052Samw 		 * this group. This is needed in the ZFS case where
227*7052Samw 		 * the top level ZFS group won't have "smb" protocol
228*7052Samw 		 * enabled but the sub-groups will.
229*7052Samw 		 */
230*7052Samw 		lmshare_load_shares(group);
231*7052Samw 		for (subgroup = sa_get_sub_group(group);
232*7052Samw 		    subgroup != NULL;
233*7052Samw 		    subgroup = sa_get_next_group(subgroup)) {
234*7052Samw 			lmshare_load_shares(subgroup);
235*7052Samw 		}
236*7052Samw 
237*7052Samw 	}
238*7052Samw 
239*7052Samw 	sa_fini(handle);
240*7052Samw 
241*7052Samw 	return (NULL);
242*7052Samw }
243*7052Samw 
244*7052Samw /*
245*7052Samw  * lmshare_callback
246*7052Samw  *
247*7052Samw  * Call back to free share structures stored
248*7052Samw  * in shares' hash table.
249*7052Samw  */
250*7052Samw static void
251*7052Samw lmshare_callback(HT_ITEM *item)
252*7052Samw {
253*7052Samw 	if (item && item->hi_data)
254*7052Samw 		free(item->hi_data);
255*7052Samw }
256*7052Samw 
257*7052Samw /*
258*7052Samw  * smb_shr_cache_create
259*7052Samw  *
260*7052Samw  * Create the share hash table.
261*7052Samw  */
262*7052Samw static uint32_t
263*7052Samw smb_shr_cache_create(void)
264*7052Samw {
265*7052Samw 	if (smb_shr_handle == NULL) {
266*7052Samw 		(void) rwlock_init(&smb_shr_lock, USYNC_THREAD, 0);
267*7052Samw 		(void) rw_wrlock(&smb_shr_lock);
268*7052Samw 
269*7052Samw 		smb_shr_handle = ht_create_table(SMB_SHARE_HTAB_SZ,
270*7052Samw 		    MAXNAMELEN, 0);
271*7052Samw 		if (smb_shr_handle == NULL) {
272*7052Samw 			syslog(LOG_ERR, "smb_shr_cache_create:"
273*7052Samw 			    " unable to create share table");
274*7052Samw 			(void) rw_unlock(&smb_shr_lock);
275*7052Samw 			return (NERR_InternalError);
276*7052Samw 		}
277*7052Samw 		(void) ht_register_callback(smb_shr_handle, lmshare_callback);
278*7052Samw 		(void) rw_unlock(&smb_shr_lock);
279*7052Samw 	}
280*7052Samw 
281*7052Samw 	return (NERR_Success);
282*7052Samw }
283*7052Samw 
284*7052Samw /*
285*7052Samw  * smb_shr_add_adminshare
286*7052Samw  *
287*7052Samw  * add the admin share for the volume when the share database
288*7052Samw  * for that volume is going to be loaded.
289*7052Samw  */
290*7052Samw uint32_t
291*7052Samw smb_shr_add_adminshare(char *volname, unsigned char drive)
292*7052Samw {
293*7052Samw 	smb_share_t si;
294*7052Samw 	uint32_t rc;
295*7052Samw 
296*7052Samw 	if (drive == 0)
297*7052Samw 		return (NERR_InvalidDevice);
298*7052Samw 
299*7052Samw 	bzero(&si, sizeof (smb_share_t));
300*7052Samw 	(void) strcpy(si.shr_path, volname);
301*7052Samw 	si.shr_flags = SMB_SHRF_TRANS | SMB_SHRF_ADMIN;
302*7052Samw 	(void) snprintf(si.shr_name, sizeof (si.shr_name), "%c$", drive);
303*7052Samw 	rc = smb_shr_add(&si, 0);
304*7052Samw 
305*7052Samw 	return (rc);
306*7052Samw }
307*7052Samw 
308*7052Samw /*
309*7052Samw  * smb_shr_count
310*7052Samw  *
311*7052Samw  * Return the total number of shares, which should be the same value
312*7052Samw  * that would be returned from a share enum request.
313*7052Samw  */
314*7052Samw int
315*7052Samw smb_shr_count(void)
316*7052Samw {
317*7052Samw 	int n_shares;
318*7052Samw 
319*7052Samw 	n_shares = ht_get_total_items(smb_shr_handle);
320*7052Samw 
321*7052Samw 	/* If we don't store IPC$ in hash table we should do this */
322*7052Samw 	n_shares++;
323*7052Samw 
324*7052Samw 	return (n_shares);
325*7052Samw }
326*7052Samw 
327*7052Samw /*
328*7052Samw  * smb_shr_iterinit
329*7052Samw  *
330*7052Samw  * Initialize an iterator for traversing hash table.
331*7052Samw  * 'mode' is used for filtering shares when iterating.
332*7052Samw  */
333*7052Samw void
334*7052Samw smb_shr_iterinit(smb_shriter_t *shi, uint32_t mode)
335*7052Samw {
336*7052Samw 	bzero(shi, sizeof (smb_shriter_t));
337*7052Samw 	shi->si_mode = mode;
338*7052Samw }
339*7052Samw 
340*7052Samw /*
341*7052Samw  * smb_shr_iterate
342*7052Samw  *
343*7052Samw  * Iterate on the shares in the hash table. The iterator must be initialized
344*7052Samw  * before the first iteration. On subsequent calls, the iterator must be
345*7052Samw  * passed unchanged.
346*7052Samw  *
347*7052Samw  * Returns NULL on failure or when all shares are visited, otherwise
348*7052Samw  * returns information of visited share.
349*7052Samw  *
350*7052Samw  * Note that there are some special shares, i.e. IPC$, that must also
351*7052Samw  * be processed.
352*7052Samw  */
353*7052Samw smb_share_t *
354*7052Samw smb_shr_iterate(smb_shriter_t *shi)
355*7052Samw {
356*7052Samw 	HT_ITEM *item;
357*7052Samw 	smb_share_t *si;
358*7052Samw 
359*7052Samw 	if (smb_shr_handle == NULL || shi == NULL)
360*7052Samw 		return (NULL);
361*7052Samw 
362*7052Samw 	if (shi->si_counter == 0) {
363*7052Samw 		/*
364*7052Samw 		 * IPC$ is always first.
365*7052Samw 		 */
366*7052Samw 		(void) strcpy(shi->si_share.shr_name, "IPC$");
367*7052Samw 		smb_shr_set_oemname(&shi->si_share);
368*7052Samw 		shi->si_share.shr_flags = SMB_SHRF_TRANS;
369*7052Samw 		shi->si_share.shr_type = (int)(STYPE_IPC | STYPE_SPECIAL);
370*7052Samw 		shi->si_counter = 1;
371*7052Samw 		return (&(shi->si_share));
372*7052Samw 	}
373*7052Samw 
374*7052Samw 	if (shi->si_counter == 1) {
375*7052Samw 		if ((item = ht_findfirst(
376*7052Samw 		    smb_shr_handle, &shi->si_hashiter)) == NULL) {
377*7052Samw 			return (NULL);
378*7052Samw 		}
379*7052Samw 
380*7052Samw 		si = (smb_share_t *)(item->hi_data);
381*7052Samw 		++shi->si_counter;
382*7052Samw 
383*7052Samw 		if (si->shr_flags & shi->si_mode) {
384*7052Samw 			bcopy(si, &(shi->si_share), sizeof (smb_share_t));
385*7052Samw 			return (&(shi->si_share));
386*7052Samw 		}
387*7052Samw 	}
388*7052Samw 
389*7052Samw 	while ((item = ht_findnext(&shi->si_hashiter)) != NULL) {
390*7052Samw 		si = (smb_share_t *)(item->hi_data);
391*7052Samw 		++shi->si_counter;
392*7052Samw 		if (si->shr_flags & shi->si_mode) {
393*7052Samw 			bcopy(si, &(shi->si_share), sizeof (smb_share_t));
394*7052Samw 			return (&(shi->si_share));
395*7052Samw 		}
396*7052Samw 	}
397*7052Samw 
398*7052Samw 	return (NULL);
399*7052Samw }
400*7052Samw 
401*7052Samw /*
402*7052Samw  * smb_shr_add
403*7052Samw  *
404*7052Samw  * Add a share. This is a wrapper round smb_shr_set that checks
405*7052Samw  * whether or not the share already exists. If the share exists, an
406*7052Samw  * error is returned.
407*7052Samw  *
408*7052Samw  * Don't check smb_shr_is_dir here: it causes rootfs to recurse.
409*7052Samw  */
410*7052Samw uint32_t
411*7052Samw smb_shr_add(smb_share_t *si, int doshm)
412*7052Samw {
413*7052Samw 	uint32_t status = NERR_Success;
414*7052Samw 
415*7052Samw 	if (si == 0 || smb_shr_is_valid(si->shr_name) == 0)
416*7052Samw 		return (NERR_InvalidDevice);
417*7052Samw 
418*7052Samw 	(void) utf8_strlwr(si->shr_name);
419*7052Samw 
420*7052Samw 	if (smb_shr_exists(si->shr_name)) {
421*7052Samw 		/*
422*7052Samw 		 * Only autohome shares can be added multiple times
423*7052Samw 		 */
424*7052Samw 		if ((si->shr_flags & SMB_SHRF_AUTOHOME) == 0)
425*7052Samw 			return (NERR_DuplicateShare);
426*7052Samw 	}
427*7052Samw 
428*7052Samw 	if (si->shr_refcnt == 0) {
429*7052Samw 		status = smb_shr_set(si, doshm);
430*7052Samw 		smb_shr_publish(si, SMB_SHARE_PUBLISH, 1);
431*7052Samw 	}
432*7052Samw 
433*7052Samw 	if ((si->shr_flags & SMB_SHRF_AUTOHOME) && (status == NERR_Success)) {
434*7052Samw 		si->shr_refcnt++;
435*7052Samw 		status = smb_shr_set_refcnt(si->shr_name, si->shr_refcnt);
436*7052Samw 	}
437*7052Samw 
438*7052Samw 	if (status)
439*7052Samw 		return (status);
440*7052Samw 
441*7052Samw 	return (smb_dwncall_share(SMB_SHROP_ADD, si->shr_path, si->shr_name));
442*7052Samw }
443*7052Samw 
444*7052Samw /*
445*7052Samw  * smb_shr_del
446*7052Samw  *
447*7052Samw  * Remove a share. Ensure that all SMB trees associated with this share
448*7052Samw  * are disconnected. If the share does not exist, an error is returned.
449*7052Samw  */
450*7052Samw uint32_t
451*7052Samw smb_shr_del(char *share_name, int doshm)
452*7052Samw {
453*7052Samw 	smb_share_t *si;
454*7052Samw 	HT_ITEM *item;
455*7052Samw 	uint32_t status;
456*7052Samw 	char path[MAXPATHLEN];
457*7052Samw 
458*7052Samw 	if (share_name)
459*7052Samw 		(void) utf8_strlwr(share_name);
460*7052Samw 
461*7052Samw 	if (smb_shr_is_valid(share_name) == 0 ||
462*7052Samw 	    smb_shr_exists(share_name) == 0) {
463*7052Samw 		return (NERR_NetNameNotFound);
464*7052Samw 	}
465*7052Samw 
466*7052Samw 	(void) rw_wrlock(&smb_shr_lock);
467*7052Samw 	item = ht_find_item(smb_shr_handle, share_name);
468*7052Samw 
469*7052Samw 	if (item == NULL) {
470*7052Samw 		(void) rw_unlock(&smb_shr_lock);
471*7052Samw 		return (NERR_ItemNotFound);
472*7052Samw 	}
473*7052Samw 
474*7052Samw 	si = (smb_share_t *)item->hi_data;
475*7052Samw 	if (si == NULL) {
476*7052Samw 		(void) rw_unlock(&smb_shr_lock);
477*7052Samw 		return (NERR_InternalError);
478*7052Samw 	}
479*7052Samw 
480*7052Samw 	if ((si->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) {
481*7052Samw 		si->shr_refcnt--;
482*7052Samw 		if (si->shr_refcnt > 0) {
483*7052Samw 			status = smb_shr_set_refcnt(si->shr_name,
484*7052Samw 			    si->shr_refcnt);
485*7052Samw 			(void) rw_unlock(&smb_shr_lock);
486*7052Samw 			return (status);
487*7052Samw 		}
488*7052Samw 	}
489*7052Samw 
490*7052Samw 	if (doshm && (smb_shr_del_shmgr(si) != 0)) {
491*7052Samw 		(void) rw_unlock(&smb_shr_lock);
492*7052Samw 		return (NERR_InternalError);
493*7052Samw 	}
494*7052Samw 
495*7052Samw 	smb_shr_publish(si, SMB_SHARE_UNPUBLISH, 1);
496*7052Samw 
497*7052Samw 	/*
498*7052Samw 	 * Copy the path before the entry is removed from the hash table
499*7052Samw 	 */
500*7052Samw 
501*7052Samw 	(void) strlcpy(path, si->shr_path, MAXPATHLEN);
502*7052Samw 
503*7052Samw 	/* Delete from hash table */
504*7052Samw 
505*7052Samw 	(void) ht_remove_item(smb_shr_handle, share_name);
506*7052Samw 	(void) rw_unlock(&smb_shr_lock);
507*7052Samw 
508*7052Samw 	return (smb_dwncall_share(SMB_SHROP_DELETE, path, share_name));
509*7052Samw }
510*7052Samw 
511*7052Samw /*
512*7052Samw  * smb_shr_set_refcnt
513*7052Samw  *
514*7052Samw  * sets the autohome shr_refcnt for a share
515*7052Samw  */
516*7052Samw static uint32_t
517*7052Samw smb_shr_set_refcnt(char *share_name, int refcnt)
518*7052Samw {
519*7052Samw 	smb_share_t *si;
520*7052Samw 	HT_ITEM *item;
521*7052Samw 
522*7052Samw 	if (share_name) {
523*7052Samw 		(void) utf8_strlwr(share_name);
524*7052Samw 	}
525*7052Samw 	(void) rw_wrlock(&smb_shr_lock);
526*7052Samw 	item = ht_find_item(smb_shr_handle, share_name);
527*7052Samw 	if (item == NULL) {
528*7052Samw 		(void) rw_unlock(&smb_shr_lock);
529*7052Samw 		return (NERR_ItemNotFound);
530*7052Samw 	}
531*7052Samw 
532*7052Samw 	si = (smb_share_t *)item->hi_data;
533*7052Samw 	if (si == NULL) {
534*7052Samw 		(void) rw_unlock(&smb_shr_lock);
535*7052Samw 		return (NERR_InternalError);
536*7052Samw 	}
537*7052Samw 	si->shr_refcnt = refcnt;
538*7052Samw 	(void) rw_unlock(&smb_shr_lock);
539*7052Samw 	return (NERR_Success);
540*7052Samw }
541*7052Samw 
542*7052Samw /*
543*7052Samw  * smb_shr_ren
544*7052Samw  *
545*7052Samw  * Rename a share. Check that the current name exists and the new name
546*7052Samw  * doesn't exist. The rename is performed by deleting the current share
547*7052Samw  * definition and creating a new share with the new name.
548*7052Samw  */
549*7052Samw uint32_t
550*7052Samw smb_shr_ren(char *from_name, char *to_name, int doshm)
551*7052Samw {
552*7052Samw 	smb_share_t si;
553*7052Samw 	uint32_t nerr;
554*7052Samw 
555*7052Samw 	if (smb_shr_is_valid(from_name) == 0 ||
556*7052Samw 	    smb_shr_is_valid(to_name) == 0)
557*7052Samw 		return (NERR_InvalidDevice);
558*7052Samw 
559*7052Samw 	(void) utf8_strlwr(from_name);
560*7052Samw 	(void) utf8_strlwr(to_name);
561*7052Samw 
562*7052Samw 	if (smb_shr_exists(from_name) == 0)
563*7052Samw 		return (NERR_NetNameNotFound);
564*7052Samw 
565*7052Samw 	if (smb_shr_exists(to_name))
566*7052Samw 		return (NERR_DuplicateShare);
567*7052Samw 
568*7052Samw 	if ((nerr = smb_shr_get(from_name, &si)) != NERR_Success)
569*7052Samw 		return (nerr);
570*7052Samw 
571*7052Samw 	if ((nerr = smb_shr_del(from_name, doshm)) != NERR_Success)
572*7052Samw 		return (nerr);
573*7052Samw 
574*7052Samw 	(void) strlcpy(si.shr_name, to_name, MAXNAMELEN);
575*7052Samw 	return (smb_shr_add(&si, 1));
576*7052Samw }
577*7052Samw 
578*7052Samw /*
579*7052Samw  * smb_shr_exists
580*7052Samw  *
581*7052Samw  * Returns 1 if the share exists. Otherwise returns 0.
582*7052Samw  */
583*7052Samw int
584*7052Samw smb_shr_exists(char *share_name)
585*7052Samw {
586*7052Samw 	if (share_name == 0 || *share_name == 0)
587*7052Samw 		return (0);
588*7052Samw 
589*7052Samw 	if (ht_find_item(smb_shr_handle, share_name) == NULL)
590*7052Samw 		return (0);
591*7052Samw 	else
592*7052Samw 		return (1);
593*7052Samw }
594*7052Samw 
595*7052Samw /*
596*7052Samw  * smb_shr_is_special
597*7052Samw  *
598*7052Samw  * Simple check to determine if share name represents a special share,
599*7052Samw  * i.e. the last character of the name is a '$'. Returns STYPE_SPECIAL
600*7052Samw  * if the name is special. Otherwise returns 0.
601*7052Samw  */
602*7052Samw int
603*7052Samw smb_shr_is_special(char *share_name)
604*7052Samw {
605*7052Samw 	int len;
606*7052Samw 
607*7052Samw 	if (share_name == 0)
608*7052Samw 		return (0);
609*7052Samw 
610*7052Samw 	if ((len = strlen(share_name)) == 0)
611*7052Samw 		return (0);
612*7052Samw 
613*7052Samw 	if (share_name[len - 1] == '$')
614*7052Samw 		return (STYPE_SPECIAL);
615*7052Samw 	else
616*7052Samw 		return (0);
617*7052Samw }
618*7052Samw 
619*7052Samw 
620*7052Samw /*
621*7052Samw  * smb_shr_is_restricted
622*7052Samw  *
623*7052Samw  * Check whether or not there is a restriction on a share. Restricted
624*7052Samw  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
625*7052Samw  * administration share names are restricted: C$, D$ etc. Returns 1
626*7052Samw  * if the share is restricted. Otherwise 0 is returned to indicate
627*7052Samw  * that there are no restrictions.
628*7052Samw  */
629*7052Samw int
630*7052Samw smb_shr_is_restricted(char *share_name)
631*7052Samw {
632*7052Samw 	static char *restricted[] = {
633*7052Samw 		"IPC$"
634*7052Samw 	};
635*7052Samw 
636*7052Samw 	int i;
637*7052Samw 
638*7052Samw 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
639*7052Samw 		if (strcasecmp(restricted[i], share_name) == 0)
640*7052Samw 			return (1);
641*7052Samw 	}
642*7052Samw 
643*7052Samw 	if (smb_shr_is_admin(share_name))
644*7052Samw 		return (1);
645*7052Samw 
646*7052Samw 	return (0);
647*7052Samw }
648*7052Samw 
649*7052Samw 
650*7052Samw /*
651*7052Samw  * smb_shr_is_admin
652*7052Samw  *
653*7052Samw  * Check whether or not access to the share should be restricted to
654*7052Samw  * administrators. This is a bit of a hack because what we're doing
655*7052Samw  * is checking for the default admin shares: C$, D$ etc.. There are
656*7052Samw  * other shares that have restrictions: see smb_shr_is_restricted().
657*7052Samw  *
658*7052Samw  * Returns 1 if the shares is an admin share. Otherwise 0 is returned
659*7052Samw  * to indicate that there are no restrictions.
660*7052Samw  */
661*7052Samw int
662*7052Samw smb_shr_is_admin(char *share_name)
663*7052Samw {
664*7052Samw 	if (share_name == 0)
665*7052Samw 		return (0);
666*7052Samw 
667*7052Samw 	if (strlen(share_name) == 2 &&
668*7052Samw 	    mts_isalpha(share_name[0]) && share_name[1] == '$') {
669*7052Samw 		return (1);
670*7052Samw 	}
671*7052Samw 
672*7052Samw 	return (0);
673*7052Samw }
674*7052Samw 
675*7052Samw 
676*7052Samw /*
677*7052Samw  * smb_shr_is_valid
678*7052Samw  *
679*7052Samw  * Check if any invalid char is present in share name. According to
680*7052Samw  * MSDN article #236388: "Err Msg: The Share Name Contains Invalid
681*7052Samw  * Characters", the list of invalid character is:
682*7052Samw  *
683*7052Samw  * " / \ [ ] : | < > + ; , ? * =
684*7052Samw  *
685*7052Samw  * Also rejects if control characters are embedded.
686*7052Samw  *
687*7052Samw  * If the sharename is valid, return (1). Otherwise return (0).
688*7052Samw  */
689*7052Samw int
690*7052Samw smb_shr_is_valid(char *share_name)
691*7052Samw {
692*7052Samw 	char *invalid = "\"/\\[]:|<>+;,?*=";
693*7052Samw 	char *cp;
694*7052Samw 
695*7052Samw 	if (share_name == 0)
696*7052Samw 		return (0);
697*7052Samw 
698*7052Samw 	if (strpbrk(share_name, invalid))
699*7052Samw 		return (0);
700*7052Samw 
701*7052Samw 	for (cp = share_name; *cp != '\0'; cp++)
702*7052Samw 		if (iscntrl(*cp))
703*7052Samw 			return (0);
704*7052Samw 
705*7052Samw 	return (1);
706*7052Samw }
707*7052Samw 
708*7052Samw /*
709*7052Samw  * smb_shr_is_dir
710*7052Samw  *
711*7052Samw  * Check to determine if a share object represents a directory.
712*7052Samw  *
713*7052Samw  * Returns 1 if the path leads to a directory. Otherwise returns 0.
714*7052Samw  */
715*7052Samw int
716*7052Samw smb_shr_is_dir(char *path)
717*7052Samw {
718*7052Samw 	struct stat stat_info;
719*7052Samw 
720*7052Samw 	if (stat(path, &stat_info) == 0)
721*7052Samw 		if (S_ISDIR(stat_info.st_mode))
722*7052Samw 			return (1);
723*7052Samw 
724*7052Samw 	return (0);
725*7052Samw 
726*7052Samw }
727*7052Samw 
728*7052Samw /*
729*7052Samw  * smb_shr_get
730*7052Samw  *
731*7052Samw  * Load the information for the specified share into the supplied share
732*7052Samw  * info structure. If the shared directory does not begin with a /, one
733*7052Samw  * will be inserted as a prefix.
734*7052Samw  */
735*7052Samw uint32_t
736*7052Samw smb_shr_get(char *share_name, smb_share_t *si)
737*7052Samw {
738*7052Samw 	int i, endidx;
739*7052Samw 	int dirlen;
740*7052Samw 	HT_ITEM *item;
741*7052Samw 
742*7052Samw 	(void) rw_rdlock(&smb_shr_lock);
743*7052Samw 
744*7052Samw 	(void) utf8_strlwr(share_name);
745*7052Samw 	if ((item = ht_find_item(smb_shr_handle, share_name)) == NULL) {
746*7052Samw 		bzero(si, sizeof (smb_share_t));
747*7052Samw 		(void) rw_unlock(&smb_shr_lock);
748*7052Samw 		return (NERR_NetNameNotFound);
749*7052Samw 	}
750*7052Samw 
751*7052Samw 	(void) memcpy(si, item->hi_data, sizeof (smb_share_t));
752*7052Samw 	(void) rw_unlock(&smb_shr_lock);
753*7052Samw 
754*7052Samw 	if (si->shr_path[0] == '\0')
755*7052Samw 		return (NERR_NetNameNotFound);
756*7052Samw 
757*7052Samw 	if (si->shr_path[0] != '/') {
758*7052Samw 		dirlen = strlen(si->shr_path) + 1;
759*7052Samw 		endidx = (dirlen < MAXPATHLEN-1) ?
760*7052Samw 		    dirlen : MAXPATHLEN - 2;
761*7052Samw 		for (i = endidx; i >= 0; i--)
762*7052Samw 			si->shr_path[i+1] = si->shr_path[i];
763*7052Samw 		si->shr_path[MAXPATHLEN-1] = '\0';
764*7052Samw 		si->shr_path[0] = '/';
765*7052Samw 	}
766*7052Samw 
767*7052Samw 	return (NERR_Success);
768*7052Samw }
769*7052Samw 
770*7052Samw /*
771*7052Samw  * Remove share from sharemanager repository.
772*7052Samw  */
773*7052Samw static int
774*7052Samw smb_shr_del_shmgr(smb_share_t *si)
775*7052Samw {
776*7052Samw 	sa_handle_t handle;
777*7052Samw 	sa_share_t share;
778*7052Samw 	sa_resource_t resource;
779*7052Samw 
780*7052Samw 	handle = sa_init(SA_INIT_SHARE_API);
781*7052Samw 	if (handle == NULL) {
782*7052Samw 		syslog(LOG_ERR, "Failed to get handle to "
783*7052Samw 		    "share lib");
784*7052Samw 		return (1);
785*7052Samw 	}
786*7052Samw 	share = sa_find_share(handle, si->shr_path);
787*7052Samw 	if (share == NULL) {
788*7052Samw 		syslog(LOG_ERR, "Failed to get share to delete");
789*7052Samw 		sa_fini(handle);
790*7052Samw 		return (1);
791*7052Samw 	}
792*7052Samw 	resource = sa_get_share_resource(share, si->shr_name);
793*7052Samw 	if (resource == NULL) {
794*7052Samw 		syslog(LOG_ERR, "Failed to get share resource to delete");
795*7052Samw 		sa_fini(handle);
796*7052Samw 		return (1);
797*7052Samw 	}
798*7052Samw 	if (sa_remove_resource(resource) != SA_OK) {
799*7052Samw 		syslog(LOG_ERR, "Failed to remove resource");
800*7052Samw 		sa_fini(handle);
801*7052Samw 		return (1);
802*7052Samw 	}
803*7052Samw 	sa_fini(handle);
804*7052Samw 	return (0);
805*7052Samw }
806*7052Samw 
807*7052Samw static int
808*7052Samw smb_shr_set_shmgr(smb_share_t *si)
809*7052Samw {
810*7052Samw 	sa_handle_t handle;
811*7052Samw 	sa_share_t share;
812*7052Samw 	sa_group_t group;
813*7052Samw 	sa_resource_t resource;
814*7052Samw 	int share_created = 0;
815*7052Samw 	int err;
816*7052Samw 
817*7052Samw 	/* Add share to sharemanager */
818*7052Samw 	handle = sa_init(SA_INIT_SHARE_API);
819*7052Samw 	if (handle == NULL) {
820*7052Samw 		syslog(LOG_ERR, "Failed to get handle to share lib");
821*7052Samw 		return (1);
822*7052Samw 	}
823*7052Samw 	share = sa_find_share(handle, si->shr_path);
824*7052Samw 	if (share == NULL) {
825*7052Samw 		group = smb_get_smb_share_group(handle);
826*7052Samw 		if (group == NULL) {
827*7052Samw 			sa_fini(handle);
828*7052Samw 			return (1);
829*7052Samw 		}
830*7052Samw 		share = sa_add_share(group, si->shr_path, 0, &err);
831*7052Samw 		if (share == NULL) {
832*7052Samw 			sa_fini(handle);
833*7052Samw 			return (1);
834*7052Samw 		}
835*7052Samw 		share_created = 1;
836*7052Samw 	}
837*7052Samw 	resource = sa_get_share_resource(share, si->shr_name);
838*7052Samw 	if (resource == NULL) {
839*7052Samw 		resource = sa_add_resource(share, si->shr_name,
840*7052Samw 		    SA_SHARE_PERMANENT, &err);
841*7052Samw 		if (resource == NULL) {
842*7052Samw 			goto failure;
843*7052Samw 		}
844*7052Samw 	}
845*7052Samw 	if (sa_set_resource_attr(resource,
846*7052Samw 	    "description", si->shr_cmnt) != SA_OK) {
847*7052Samw 		syslog(LOG_ERR, "Falied to set resource "
848*7052Samw 		    "description in sharemgr");
849*7052Samw 		goto failure;
850*7052Samw 	}
851*7052Samw 	if (sa_set_resource_attr(resource,
852*7052Samw 	    SMB_SHROPT_AD_CONTAINER, si->shr_container) != SA_OK) {
853*7052Samw 		syslog(LOG_ERR, "Falied to set ad-container in sharemgr");
854*7052Samw 		goto failure;
855*7052Samw 	}
856*7052Samw 
857*7052Samw 	sa_fini(handle);
858*7052Samw 	return (0);
859*7052Samw failure:
860*7052Samw 	if (share_created && (share != NULL)) {
861*7052Samw 		if (sa_remove_share(share) != SA_OK) {
862*7052Samw 			syslog(LOG_ERR, "Failed to cleanup share");
863*7052Samw 		}
864*7052Samw 	}
865*7052Samw 	if (resource != NULL) {
866*7052Samw 		if (sa_remove_resource(resource) != SA_OK) {
867*7052Samw 			syslog(LOG_ERR, "Failed to cleanup share resource");
868*7052Samw 		}
869*7052Samw 	}
870*7052Samw 	sa_fini(handle);
871*7052Samw 	return (1);
872*7052Samw }
873*7052Samw 
874*7052Samw /*
875*7052Samw  * smb_shr_cache_delshare
876*7052Samw  *
877*7052Samw  * Delete the given share only from hash table
878*7052Samw  */
879*7052Samw static uint32_t
880*7052Samw smb_shr_cache_delshare(char *share_name)
881*7052Samw {
882*7052Samw 	if (share_name == 0)
883*7052Samw 		return (NERR_NetNameNotFound);
884*7052Samw 
885*7052Samw 	(void) utf8_strlwr(share_name);
886*7052Samw 
887*7052Samw 	if (smb_shr_is_valid(share_name) == 0 ||
888*7052Samw 	    smb_shr_exists(share_name) == 0) {
889*7052Samw 		return (NERR_NetNameNotFound);
890*7052Samw 	}
891*7052Samw 
892*7052Samw 	(void) rw_wrlock(&smb_shr_lock);
893*7052Samw 	(void) ht_remove_item(smb_shr_handle, share_name);
894*7052Samw 	(void) rw_unlock(&smb_shr_lock);
895*7052Samw 
896*7052Samw 	return (NERR_Success);
897*7052Samw }
898*7052Samw 
899*7052Samw /*
900*7052Samw  * smb_shr_set
901*7052Samw  *
902*7052Samw  * Adds the specified share into the system hash table
903*7052Samw  * and also store its info in the corresponding disk
904*7052Samw  * structure if it is not a temporary (SMB_SHRF_TRANS) share.
905*7052Samw  * when the first share is going to be added, create shares
906*7052Samw  * hash table if it is not already created.
907*7052Samw  * If the share already exists, it will be replaced. If the
908*7052Samw  * new share directory name does not begin with a /, one will be
909*7052Samw  * inserted as a prefix.
910*7052Samw  */
911*7052Samw uint32_t
912*7052Samw smb_shr_set(smb_share_t *si, int doshm)
913*7052Samw {
914*7052Samw 	int i, endidx;
915*7052Samw 	int dirlen;
916*7052Samw 	smb_share_t *add_si;
917*7052Samw 	int res = NERR_Success;
918*7052Samw 	smb_share_t old_si;
919*7052Samw 
920*7052Samw 	if (si->shr_path[0] != '/') {
921*7052Samw 		dirlen = strlen(si->shr_path) + 1;
922*7052Samw 		endidx = (dirlen < MAXPATHLEN - 1) ?
923*7052Samw 		    dirlen : MAXPATHLEN - 2;
924*7052Samw 		for (i = endidx; i >= 0; i--)
925*7052Samw 			si->shr_path[i+1] = si->shr_path[i];
926*7052Samw 		si->shr_path[MAXPATHLEN-1] = '\0';
927*7052Samw 		si->shr_path[0] = '/';
928*7052Samw 	}
929*7052Samw 
930*7052Samw 	/* XXX Do we need to translate the directory here? to real path */
931*7052Samw 	if (smb_shr_is_dir(si->shr_path) == 0)
932*7052Samw 		return (NERR_UnknownDevDir);
933*7052Samw 
934*7052Samw 	/*
935*7052Samw 	 * We should allocate memory for new entry because we
936*7052Samw 	 * don't know anything about the passed pointer i.e.
937*7052Samw 	 * it maybe destroyed by caller of this function while
938*7052Samw 	 * we only store a pointer to the data in hash table.
939*7052Samw 	 * Hash table doesn't do any allocation for the data that
940*7052Samw 	 * is being added.
941*7052Samw 	 */
942*7052Samw 	add_si = malloc(sizeof (smb_share_t));
943*7052Samw 	if (add_si == NULL) {
944*7052Samw 		syslog(LOG_ERR, "LmshareSetinfo: resource shortage");
945*7052Samw 		return (NERR_NoRoom);
946*7052Samw 	}
947*7052Samw 
948*7052Samw 	(void) memcpy(add_si, si, sizeof (smb_share_t));
949*7052Samw 
950*7052Samw 	/*
951*7052Samw 	 * If we can't find it, use the new one to get things in sync,
952*7052Samw 	 * but if there is an existing one, that is the one to
953*7052Samw 	 * unpublish.
954*7052Samw 	 */
955*7052Samw 	if (smb_shr_get(si->shr_name, &old_si) != NERR_Success)
956*7052Samw 		(void) memcpy(&old_si, si, sizeof (smb_share_t));
957*7052Samw 
958*7052Samw 	if (doshm) {
959*7052Samw 		res = smb_shr_del(si->shr_name, doshm);
960*7052Samw 		if (res != NERR_Success) {
961*7052Samw 			free(add_si);
962*7052Samw 			syslog(LOG_ERR, "LmshareSetinfo: delete failed", res);
963*7052Samw 			return (res);
964*7052Samw 		}
965*7052Samw 	} else {
966*7052Samw 		/* Unpublish old share from AD */
967*7052Samw 		if ((add_si->shr_flags & SMB_SHRF_PERM) == SMB_SHRF_PERM)
968*7052Samw 			smb_shr_publish(&old_si, SMB_SHARE_UNPUBLISH, 1);
969*7052Samw 		(void) smb_shr_cache_delshare(si->shr_name);
970*7052Samw 	}
971*7052Samw 
972*7052Samw 	smb_shr_set_oemname(add_si);
973*7052Samw 
974*7052Samw 	/* if it's not transient it should be permanent */
975*7052Samw 	if ((add_si->shr_flags & SMB_SHRF_TRANS) == 0)
976*7052Samw 		add_si->shr_flags |= SMB_SHRF_PERM;
977*7052Samw 
978*7052Samw 
979*7052Samw 	add_si->shr_type = STYPE_DISKTREE;
980*7052Samw 	add_si->shr_type |= smb_shr_is_special(add_si->shr_name);
981*7052Samw 
982*7052Samw 	(void) rw_wrlock(&smb_shr_lock);
983*7052Samw 	if (ht_add_item(smb_shr_handle, add_si->shr_name, add_si) == NULL) {
984*7052Samw 		syslog(LOG_ERR, "smb_shr_set[%s]: error in adding share",
985*7052Samw 		    add_si->shr_name);
986*7052Samw 		(void) rw_unlock(&smb_shr_lock);
987*7052Samw 		free(add_si);
988*7052Samw 		return (NERR_InternalError);
989*7052Samw 	}
990*7052Samw 	(void) rw_unlock(&smb_shr_lock);
991*7052Samw 
992*7052Samw 	if ((add_si->shr_flags & SMB_SHRF_PERM) == SMB_SHRF_PERM) {
993*7052Samw 		if (doshm && (smb_shr_set_shmgr(add_si) != 0)) {
994*7052Samw 			syslog(LOG_ERR, "Update share %s in sharemgr failed",
995*7052Samw 			    add_si->shr_name);
996*7052Samw 			return (NERR_InternalError);
997*7052Samw 		}
998*7052Samw 		smb_shr_publish(add_si, SMB_SHARE_PUBLISH, 1);
999*7052Samw 	}
1000*7052Samw 
1001*7052Samw 	return (res);
1002*7052Samw }
1003*7052Samw 
1004*7052Samw void
1005*7052Samw smb_shr_list(int offset, smb_shrlist_t *list)
1006*7052Samw {
1007*7052Samw 	smb_shriter_t iterator;
1008*7052Samw 	smb_share_t *si;
1009*7052Samw 	int list_idx = 0;
1010*7052Samw 	int i = 0;
1011*7052Samw 
1012*7052Samw 	bzero(list, sizeof (smb_shrlist_t));
1013*7052Samw 	smb_shr_iterinit(&iterator, SMB_SHRF_ALL);
1014*7052Samw 
1015*7052Samw 	(void) smb_shr_iterate(&iterator);	/* To skip IPC$ */
1016*7052Samw 
1017*7052Samw 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
1018*7052Samw 		if (smb_shr_is_special(si->shr_name)) {
1019*7052Samw 			/*
1020*7052Samw 			 * Don't return restricted shares.
1021*7052Samw 			 */
1022*7052Samw 			if (smb_shr_is_restricted(si->shr_name))
1023*7052Samw 				continue;
1024*7052Samw 		}
1025*7052Samw 
1026*7052Samw 		if (i++ < offset)
1027*7052Samw 			continue;
1028*7052Samw 
1029*7052Samw 		(void) memcpy(&list->smbshr[list_idx], si,
1030*7052Samw 		    sizeof (smb_share_t));
1031*7052Samw 		if (++list_idx == LMSHARES_PER_REQUEST)
1032*7052Samw 			break;
1033*7052Samw 	}
1034*7052Samw 
1035*7052Samw 	list->no = list_idx;
1036*7052Samw }
1037*7052Samw 
1038*7052Samw /*
1039*7052Samw  * Put the share on publish queue.
1040*7052Samw  */
1041*7052Samw static void
1042*7052Samw smb_shr_publish(smb_share_t *si, char flag, int poke)
1043*7052Samw {
1044*7052Samw 	smb_shr_adinfo_t *item = NULL;
1045*7052Samw 
1046*7052Samw 	if (publish_on == 0)
1047*7052Samw 		return;
1048*7052Samw 
1049*7052Samw 	if ((si == NULL) || (si->shr_container[0] == '\0'))
1050*7052Samw 		return;
1051*7052Samw 
1052*7052Samw 	(void) mutex_lock(&smb_shr_publish_mtx);
1053*7052Samw 	item = (smb_shr_adinfo_t *)malloc(sizeof (smb_shr_adinfo_t));
1054*7052Samw 	if (item == NULL) {
1055*7052Samw 		syslog(LOG_ERR, "Failed to allocate share publish item");
1056*7052Samw 		(void) mutex_unlock(&smb_shr_publish_mtx);
1057*7052Samw 		return;
1058*7052Samw 	}
1059*7052Samw 	item->flag = flag;
1060*7052Samw 	(void) strlcpy(item->name, si->shr_name, sizeof (item->name));
1061*7052Samw 	(void) strlcpy(item->container, si->shr_container,
1062*7052Samw 	    sizeof (item->container));
1063*7052Samw 	/*LINTED - E_CONSTANT_CONDITION*/
1064*7052Samw 	TAILQ_INSERT_TAIL(&ad_queue.adlist, item, next);
1065*7052Samw 	ad_queue.nentries++;
1066*7052Samw 	if (poke)
1067*7052Samw 		(void) cond_signal(&smb_shr_publish_cv);
1068*7052Samw 	(void) mutex_unlock(&smb_shr_publish_mtx);
1069*7052Samw }
1070*7052Samw 
1071*7052Samw void
1072*7052Samw smb_shr_stop_publish()
1073*7052Samw {
1074*7052Samw 	(void) mutex_lock(&smb_shr_publish_mtx);
1075*7052Samw 	publish_on = 0;
1076*7052Samw 	(void) cond_signal(&smb_shr_publish_cv);
1077*7052Samw 	(void) mutex_unlock(&smb_shr_publish_mtx);
1078*7052Samw }
1079*7052Samw 
1080*7052Samw /*
1081*7052Samw  * This functions waits to be signaled and once running
1082*7052Samw  * will publish/unpublish any items on list.
1083*7052Samw  * smb_shr_stop_publish when called will exit this thread.
1084*7052Samw  */
1085*7052Samw /*ARGSUSED*/
1086*7052Samw static void *
1087*7052Samw smb_shr_publisher(void *arg)
1088*7052Samw {
1089*7052Samw 	smb_ads_handle_t *ah;
1090*7052Samw 	smb_shr_adinfo_t *item;
1091*7052Samw 	char hostname[MAXHOSTNAMELEN];
1092*7052Samw 	char name[MAXNAMELEN];
1093*7052Samw 	char container[MAXPATHLEN];
1094*7052Samw 	char flag;
1095*7052Samw 
1096*7052Samw 	/*LINTED - E_CONSTANT_CONDITION*/
1097*7052Samw 	TAILQ_INIT(&ad_queue.adlist);
1098*7052Samw 	ad_queue.nentries = 0;
1099*7052Samw 	publish_on = 1;
1100*7052Samw 	hostname[0] = '\0';
1101*7052Samw 
1102*7052Samw 	for (;;) {
1103*7052Samw 		(void) cond_wait(&smb_shr_publish_cv,
1104*7052Samw 		    &smb_shr_publish_mtx);
1105*7052Samw 
1106*7052Samw 		if (hostname[0] == '\0') {
1107*7052Samw 			if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0)
1108*7052Samw 				continue;
1109*7052Samw 		}
1110*7052Samw 
1111*7052Samw 		if (publish_on == 0) {
1112*7052Samw 			syslog(LOG_DEBUG, "lmshare: publisher exit");
1113*7052Samw 			if (ad_queue.nentries == 0) {
1114*7052Samw 				(void) mutex_unlock(&smb_shr_publish_mtx);
1115*7052Samw 				break;
1116*7052Samw 			}
1117*7052Samw 			for (item = TAILQ_FIRST(&ad_queue.adlist); item;
1118*7052Samw 			    item = TAILQ_FIRST(&ad_queue.adlist)) {
1119*7052Samw 				/*LINTED - E_CONSTANT_CONDITION*/
1120*7052Samw 				TAILQ_REMOVE(&ad_queue.adlist, item, next);
1121*7052Samw 				(void) free(item);
1122*7052Samw 			}
1123*7052Samw 			ad_queue.nentries = 0;
1124*7052Samw 			(void) mutex_unlock(&smb_shr_publish_mtx);
1125*7052Samw 			break;
1126*7052Samw 		}
1127*7052Samw 		if (ad_queue.nentries == 0)
1128*7052Samw 			continue;
1129*7052Samw 		ah = smb_ads_open();
1130*7052Samw 		if (ah == NULL) {
1131*7052Samw 			/* We mostly have no AD config so just clear the list */
1132*7052Samw 			for (item = TAILQ_FIRST(&ad_queue.adlist); item;
1133*7052Samw 			    item = TAILQ_FIRST(&ad_queue.adlist)) {
1134*7052Samw 				/*LINTED - E_CONSTANT_CONDITION*/
1135*7052Samw 				TAILQ_REMOVE(&ad_queue.adlist, item, next);
1136*7052Samw 				(void) free(item);
1137*7052Samw 			}
1138*7052Samw 			ad_queue.nentries = 0;
1139*7052Samw 			continue;
1140*7052Samw 		}
1141*7052Samw 		TAILQ_FOREACH(item, &ad_queue.adlist, next) {
1142*7052Samw 			(void) strlcpy(name, item->name, sizeof (name));
1143*7052Samw 			(void) strlcpy(container, item->container,
1144*7052Samw 			    sizeof (container));
1145*7052Samw 			flag = item->flag;
1146*7052Samw 
1147*7052Samw 			if (flag == SMB_SHARE_UNPUBLISH)
1148*7052Samw 				(void) smb_ads_remove_share(ah, name, NULL,
1149*7052Samw 				    container, hostname);
1150*7052Samw 			else
1151*7052Samw 				(void) smb_ads_publish_share(ah, name, NULL,
1152*7052Samw 				    container, hostname);
1153*7052Samw 		}
1154*7052Samw 		for (item = TAILQ_FIRST(&ad_queue.adlist); item;
1155*7052Samw 		    item = TAILQ_FIRST(&ad_queue.adlist)) {
1156*7052Samw 			/*LINTED - E_CONSTANT_CONDITION*/
1157*7052Samw 			TAILQ_REMOVE(&ad_queue.adlist, item, next);
1158*7052Samw 			(void) free(item);
1159*7052Samw 		}
1160*7052Samw 		ad_queue.nentries = 0;
1161*7052Samw 		if (ah != NULL) {
1162*7052Samw 			smb_ads_close(ah);
1163*7052Samw 			ah = NULL;
1164*7052Samw 		}
1165*7052Samw 	}
1166*7052Samw 
1167*7052Samw 	syslog(LOG_DEBUG, "lmshare: Stopping publisher");
1168*7052Samw 	return (NULL);
1169*7052Samw }
1170*7052Samw 
1171*7052Samw /*
1172*7052Samw  * smb_shr_get_realpath
1173*7052Samw  *
1174*7052Samw  * Derive the real path of a share from the path provided by a
1175*7052Samw  * Windows client application during the share addition.
1176*7052Samw  *
1177*7052Samw  * For instance, the real path of C:\ is /cvol and the
1178*7052Samw  * real path of F:\home is /vol1/home.
1179*7052Samw  *
1180*7052Samw  * clipath  - path provided by the Windows client is in the
1181*7052Samw  *            format of <drive letter>:\<dir>
1182*7052Samw  * realpath - path that will be stored as the directory field of
1183*7052Samw  *            the smb_share_t structure of the share.
1184*7052Samw  * maxlen   - maximum length fo the realpath buffer
1185*7052Samw  *
1186*7052Samw  * Return LAN Manager network error code.
1187*7052Samw  */
1188*7052Samw /*ARGSUSED*/
1189*7052Samw uint32_t
1190*7052Samw smb_shr_get_realpath(const char *clipath, char *realpath, int maxlen)
1191*7052Samw {
1192*7052Samw 	/* XXX do this translation */
1193*7052Samw 	return (NERR_Success);
1194*7052Samw }
1195*7052Samw 
1196*7052Samw /*
1197*7052Samw  * smb_shr_set_oemname
1198*7052Samw  *
1199*7052Samw  * Generates the OEM name of the given share. If it's
1200*7052Samw  * shorter than 13 chars it'll be saved in si->shr_oemname.
1201*7052Samw  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME
1202*7052Samw  * will be set in si->shr_flags.
1203*7052Samw  */
1204*7052Samw static void
1205*7052Samw smb_shr_set_oemname(smb_share_t *si)
1206*7052Samw {
1207*7052Samw 	unsigned int cpid = oem_get_smb_cpid();
1208*7052Samw 	mts_wchar_t *unibuf;
1209*7052Samw 	char *oem_name;
1210*7052Samw 	int length;
1211*7052Samw 
1212*7052Samw 	length = strlen(si->shr_name) + 1;
1213*7052Samw 
1214*7052Samw 	oem_name = malloc(length);
1215*7052Samw 	unibuf = malloc(length * sizeof (mts_wchar_t));
1216*7052Samw 	if ((oem_name == NULL) || (unibuf == NULL)) {
1217*7052Samw 		free(oem_name);
1218*7052Samw 		free(unibuf);
1219*7052Samw 		return;
1220*7052Samw 	}
1221*7052Samw 
1222*7052Samw 	(void) mts_mbstowcs(unibuf, si->shr_name, length);
1223*7052Samw 
1224*7052Samw 	if (unicodestooems(oem_name, unibuf, length, cpid) == 0)
1225*7052Samw 		(void) strcpy(oem_name, si->shr_name);
1226*7052Samw 
1227*7052Samw 	free(unibuf);
1228*7052Samw 
1229*7052Samw 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
1230*7052Samw 		si->shr_flags |= SMB_SHRF_LONGNAME;
1231*7052Samw 		*si->shr_oemname = '\0';
1232*7052Samw 	} else {
1233*7052Samw 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
1234*7052Samw 		(void) strlcpy(si->shr_oemname, oem_name,
1235*7052Samw 		    SMB_SHARE_OEMNAME_MAX);
1236*7052Samw 	}
1237*7052Samw 
1238*7052Samw 	free(oem_name);
1239*7052Samw }
1240