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