xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_main.c (revision bbf6f00c25b6a2bed23c35eac6d62998ecdb338c)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
2289dc44ceSjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #include <sys/types.h>
27da6c28aaSamw #include <sys/stat.h>
28da6c28aaSamw #include <sys/ioccom.h>
2929bd2886SAlan Wright #include <sys/corectl.h>
30da6c28aaSamw #include <stdio.h>
31da6c28aaSamw #include <string.h>
32da6c28aaSamw #include <strings.h>
33da6c28aaSamw #include <stdlib.h>
34da6c28aaSamw #include <unistd.h>
35da6c28aaSamw #include <stdarg.h>
36da6c28aaSamw #include <fcntl.h>
37da6c28aaSamw #include <wait.h>
38da6c28aaSamw #include <signal.h>
398d7e4166Sjose borrego #include <atomic.h>
40da6c28aaSamw #include <libscf.h>
41da6c28aaSamw #include <limits.h>
42da6c28aaSamw #include <priv_utils.h>
43da6c28aaSamw #include <door.h>
44da6c28aaSamw #include <errno.h>
45da6c28aaSamw #include <pthread.h>
46da6c28aaSamw #include <time.h>
47da6c28aaSamw #include <libscf.h>
48da6c28aaSamw #include <zone.h>
49da6c28aaSamw #include <libgen.h>
50da6c28aaSamw #include <pwd.h>
51da6c28aaSamw #include <grp.h>
52da6c28aaSamw 
53da6c28aaSamw #include <smbsrv/smb_door_svc.h>
54da6c28aaSamw #include <smbsrv/smb_ioctl.h>
55*bbf6f00cSJordan Brown #include <smbsrv/string.h>
56da6c28aaSamw #include <smbsrv/libsmb.h>
57da6c28aaSamw #include <smbsrv/libsmbns.h>
58da6c28aaSamw #include <smbsrv/libmlsvc.h>
59da6c28aaSamw #include "smbd.h"
60da6c28aaSamw 
61da6c28aaSamw #define	DRV_DEVICE_PATH	"/devices/pseudo/smbsrv@0:smbsrv"
62da6c28aaSamw #define	SMB_DBDIR "/var/smb"
63da6c28aaSamw 
6429bd2886SAlan Wright static void *smbd_nbt_listener(void *);
6529bd2886SAlan Wright static void *smbd_tcp_listener(void *);
6629bd2886SAlan Wright static void *smbd_nbt_receiver(void *);
6729bd2886SAlan Wright static void *smbd_tcp_receiver(void *);
68faa1795aSjb150015 
69da6c28aaSamw static int smbd_daemonize_init(void);
70da6c28aaSamw static void smbd_daemonize_fini(int, int);
7129bd2886SAlan Wright static int smb_init_daemon_priv(int, uid_t, gid_t);
72da6c28aaSamw 
736537f381Sas200622 static int smbd_kernel_bind(void);
74da6c28aaSamw static void smbd_kernel_unbind(void);
75da6c28aaSamw static int smbd_already_running(void);
76da6c28aaSamw 
77da6c28aaSamw static int smbd_service_init(void);
78da6c28aaSamw static void smbd_service_fini(void);
79da6c28aaSamw 
80da6c28aaSamw static int smbd_setup_options(int argc, char *argv[]);
81da6c28aaSamw static void smbd_usage(FILE *fp);
82da6c28aaSamw static void smbd_report(const char *fmt, ...);
83da6c28aaSamw 
84da6c28aaSamw static void smbd_sig_handler(int sig);
85da6c28aaSamw 
86c8ec8eeaSjose borrego static int32_t smbd_gmtoff(void);
87da6c28aaSamw static int smbd_localtime_init(void);
88da6c28aaSamw static void *smbd_localtime_monitor(void *arg);
89da6c28aaSamw 
90da6c28aaSamw static pthread_t localtime_thr;
91da6c28aaSamw 
92da6c28aaSamw static int smbd_refresh_init(void);
93da6c28aaSamw static void smbd_refresh_fini(void);
94da6c28aaSamw static void *smbd_refresh_monitor(void *);
957f667e74Sjose borrego static void smbd_refresh_dc(void);
967f667e74Sjose borrego 
9729bd2886SAlan Wright static void *smbd_nbt_receiver(void *);
9829bd2886SAlan Wright static void *smbd_nbt_listener(void *);
9929bd2886SAlan Wright 
10029bd2886SAlan Wright static void *smbd_tcp_receiver(void *);
10129bd2886SAlan Wright static void *smbd_tcp_listener(void *);
10229bd2886SAlan Wright 
103a4b239dfSjose borrego static int smbd_start_listeners(void);
104a4b239dfSjose borrego static void smbd_stop_listeners(void);
10529bd2886SAlan Wright static int smbd_kernel_start(void);
10629bd2886SAlan Wright 
10729bd2886SAlan Wright static void smbd_fatal_error(const char *);
108a4b239dfSjose borrego 
109da6c28aaSamw static pthread_t refresh_thr;
110da6c28aaSamw static pthread_cond_t refresh_cond;
111da6c28aaSamw static pthread_mutex_t refresh_mutex;
112da6c28aaSamw 
113faa1795aSjb150015 smbd_t smbd;
114da6c28aaSamw 
115da6c28aaSamw /*
116da6c28aaSamw  * smbd user land daemon
117da6c28aaSamw  *
118da6c28aaSamw  * Use SMF error codes only on return or exit.
119da6c28aaSamw  */
120da6c28aaSamw int
121da6c28aaSamw main(int argc, char *argv[])
122da6c28aaSamw {
123da6c28aaSamw 	struct sigaction	act;
124da6c28aaSamw 	sigset_t		set;
125da6c28aaSamw 	uid_t			uid;
126da6c28aaSamw 	int			pfd = -1;
1278d7e4166Sjose borrego 	uint_t			sigval;
128da6c28aaSamw 
129da6c28aaSamw 	smbd.s_pname = basename(argv[0]);
130da6c28aaSamw 	openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
131da6c28aaSamw 
132da6c28aaSamw 	if (smbd_setup_options(argc, argv) != 0)
133da6c28aaSamw 		return (SMF_EXIT_ERR_FATAL);
134da6c28aaSamw 
135da6c28aaSamw 	if ((uid = getuid()) != smbd.s_uid) {
136da6c28aaSamw 		smbd_report("user %d: %s", uid, strerror(EPERM));
137da6c28aaSamw 		return (SMF_EXIT_ERR_FATAL);
138da6c28aaSamw 	}
139da6c28aaSamw 
140da6c28aaSamw 	if (getzoneid() != GLOBAL_ZONEID) {
141da6c28aaSamw 		smbd_report("non-global zones are not supported");
142da6c28aaSamw 		return (SMF_EXIT_ERR_FATAL);
143da6c28aaSamw 	}
144da6c28aaSamw 
145da6c28aaSamw 	if (is_system_labeled()) {
146da6c28aaSamw 		smbd_report("Trusted Extensions not supported");
147da6c28aaSamw 		return (SMF_EXIT_ERR_FATAL);
148da6c28aaSamw 	}
149da6c28aaSamw 
150da6c28aaSamw 	if (smbd_already_running())
151da6c28aaSamw 		return (SMF_EXIT_OK);
152da6c28aaSamw 
153da6c28aaSamw 	(void) sigfillset(&set);
154da6c28aaSamw 	(void) sigdelset(&set, SIGABRT);
155da6c28aaSamw 
156da6c28aaSamw 	(void) sigfillset(&act.sa_mask);
157da6c28aaSamw 	act.sa_handler = smbd_sig_handler;
158da6c28aaSamw 	act.sa_flags = 0;
159da6c28aaSamw 
160da6c28aaSamw 	(void) sigaction(SIGTERM, &act, NULL);
161da6c28aaSamw 	(void) sigaction(SIGHUP, &act, NULL);
162da6c28aaSamw 	(void) sigaction(SIGINT, &act, NULL);
163da6c28aaSamw 	(void) sigaction(SIGPIPE, &act, NULL);
164da6c28aaSamw 
165da6c28aaSamw 	(void) sigdelset(&set, SIGTERM);
166da6c28aaSamw 	(void) sigdelset(&set, SIGHUP);
167da6c28aaSamw 	(void) sigdelset(&set, SIGINT);
168da6c28aaSamw 	(void) sigdelset(&set, SIGPIPE);
169da6c28aaSamw 
170da6c28aaSamw 	if (smbd.s_fg) {
171da6c28aaSamw 		(void) sigdelset(&set, SIGTSTP);
172da6c28aaSamw 		(void) sigdelset(&set, SIGTTIN);
173da6c28aaSamw 		(void) sigdelset(&set, SIGTTOU);
174da6c28aaSamw 
175da6c28aaSamw 		if (smbd_service_init() != 0) {
176da6c28aaSamw 			smbd_report("service initialization failed");
177da6c28aaSamw 			exit(SMF_EXIT_ERR_FATAL);
178da6c28aaSamw 		}
179da6c28aaSamw 	} else {
180da6c28aaSamw 		/*
181da6c28aaSamw 		 * "pfd" is a pipe descriptor -- any fatal errors
182da6c28aaSamw 		 * during subsequent initialization of the child
183da6c28aaSamw 		 * process should be written to this pipe and the
184da6c28aaSamw 		 * parent will report this error as the exit status.
185da6c28aaSamw 		 */
186da6c28aaSamw 		pfd = smbd_daemonize_init();
187da6c28aaSamw 
188da6c28aaSamw 		if (smbd_service_init() != 0) {
189da6c28aaSamw 			smbd_report("daemon initialization failed");
190da6c28aaSamw 			exit(SMF_EXIT_ERR_FATAL);
191da6c28aaSamw 		}
192da6c28aaSamw 
193da6c28aaSamw 		smbd_daemonize_fini(pfd, SMF_EXIT_OK);
194da6c28aaSamw 	}
195da6c28aaSamw 
196da6c28aaSamw 	(void) atexit(smbd_service_fini);
197da6c28aaSamw 
1988d7e4166Sjose borrego 	while (!smbd.s_shutting_down) {
1998d7e4166Sjose borrego 		if (smbd.s_sigval == 0 && smbd.s_refreshes == 0)
200da6c28aaSamw 			(void) sigsuspend(&set);
201da6c28aaSamw 
2028d7e4166Sjose borrego 		sigval = atomic_swap_uint(&smbd.s_sigval, 0);
203da6c28aaSamw 
2043db3f65cSamw 		switch (sigval) {
2053db3f65cSamw 		case 0:
206da6c28aaSamw 		case SIGPIPE:
207da6c28aaSamw 			break;
208da6c28aaSamw 
209da6c28aaSamw 		case SIGHUP:
2108d7e4166Sjose borrego 			syslog(LOG_DEBUG, "refresh requested");
211da6c28aaSamw 			(void) pthread_cond_signal(&refresh_cond);
212da6c28aaSamw 			break;
213da6c28aaSamw 
214da6c28aaSamw 		default:
215da6c28aaSamw 			/*
216da6c28aaSamw 			 * Typically SIGINT or SIGTERM.
217da6c28aaSamw 			 */
2188d7e4166Sjose borrego 			smbd.s_shutting_down = B_TRUE;
219da6c28aaSamw 			break;
220da6c28aaSamw 		}
221da6c28aaSamw 	}
222da6c28aaSamw 
223da6c28aaSamw 	smbd_service_fini();
224da6c28aaSamw 	closelog();
22529bd2886SAlan Wright 	return ((smbd.s_fatal_error) ? SMF_EXIT_ERR_FATAL : SMF_EXIT_OK);
226da6c28aaSamw }
227da6c28aaSamw 
228da6c28aaSamw /*
229da6c28aaSamw  * This function will fork off a child process,
230da6c28aaSamw  * from which only the child will return.
231da6c28aaSamw  *
232da6c28aaSamw  * Use SMF error codes only on exit.
233da6c28aaSamw  */
234da6c28aaSamw static int
235da6c28aaSamw smbd_daemonize_init(void)
236da6c28aaSamw {
237da6c28aaSamw 	int status, pfds[2];
238da6c28aaSamw 	sigset_t set, oset;
239da6c28aaSamw 	pid_t pid;
240da6c28aaSamw 	int rc;
241da6c28aaSamw 
242da6c28aaSamw 	/*
243da6c28aaSamw 	 * Reset privileges to the minimum set required. We continue
244da6c28aaSamw 	 * to run as root to create and access files in /var.
245da6c28aaSamw 	 */
24629bd2886SAlan Wright 	rc = smb_init_daemon_priv(PU_RESETGROUPS, smbd.s_uid, smbd.s_gid);
247da6c28aaSamw 
248da6c28aaSamw 	if (rc != 0) {
249da6c28aaSamw 		smbd_report("insufficient privileges");
250da6c28aaSamw 		exit(SMF_EXIT_ERR_FATAL);
251da6c28aaSamw 	}
252da6c28aaSamw 
253da6c28aaSamw 	/*
254da6c28aaSamw 	 * Block all signals prior to the fork and leave them blocked in the
255da6c28aaSamw 	 * parent so we don't get in a situation where the parent gets SIGINT
256da6c28aaSamw 	 * and returns non-zero exit status and the child is actually running.
257da6c28aaSamw 	 * In the child, restore the signal mask once we've done our setsid().
258da6c28aaSamw 	 */
259da6c28aaSamw 	(void) sigfillset(&set);
260da6c28aaSamw 	(void) sigdelset(&set, SIGABRT);
261da6c28aaSamw 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
262da6c28aaSamw 
263da6c28aaSamw 	if (pipe(pfds) == -1) {
264da6c28aaSamw 		smbd_report("unable to create pipe");
265da6c28aaSamw 		exit(SMF_EXIT_ERR_FATAL);
266da6c28aaSamw 	}
267da6c28aaSamw 
268da6c28aaSamw 	closelog();
269da6c28aaSamw 
270da6c28aaSamw 	if ((pid = fork()) == -1) {
271da6c28aaSamw 		openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
272da6c28aaSamw 		smbd_report("unable to fork");
273da6c28aaSamw 		closelog();
274da6c28aaSamw 		exit(SMF_EXIT_ERR_FATAL);
275da6c28aaSamw 	}
276da6c28aaSamw 
277da6c28aaSamw 	/*
278da6c28aaSamw 	 * If we're the parent process, wait for either the child to send us
279da6c28aaSamw 	 * the appropriate exit status over the pipe or for the read to fail
280da6c28aaSamw 	 * (presumably with 0 for EOF if our child terminated abnormally).
281da6c28aaSamw 	 * If the read fails, exit with either the child's exit status if it
282da6c28aaSamw 	 * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
283da6c28aaSamw 	 */
284da6c28aaSamw 	if (pid != 0) {
285da6c28aaSamw 		(void) close(pfds[1]);
286da6c28aaSamw 
287da6c28aaSamw 		if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
288da6c28aaSamw 			_exit(status);
289da6c28aaSamw 
290da6c28aaSamw 		if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
291da6c28aaSamw 			_exit(WEXITSTATUS(status));
292da6c28aaSamw 
293da6c28aaSamw 		_exit(SMF_EXIT_ERR_FATAL);
294da6c28aaSamw 	}
295da6c28aaSamw 
296da6c28aaSamw 	openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
297da6c28aaSamw 	(void) setsid();
298da6c28aaSamw 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
299da6c28aaSamw 	(void) chdir("/");
300da6c28aaSamw 	(void) umask(022);
301da6c28aaSamw 	(void) close(pfds[0]);
302da6c28aaSamw 
303da6c28aaSamw 	return (pfds[1]);
304da6c28aaSamw }
305da6c28aaSamw 
30629bd2886SAlan Wright /*
30729bd2886SAlan Wright  * This function is based on __init_daemon_priv() and replaces
30829bd2886SAlan Wright  * __init_daemon_priv() since we want smbd to have all privileges so that it
30929bd2886SAlan Wright  * can execute map/unmap commands with all privileges during share
31029bd2886SAlan Wright  * connection/disconnection.  Unused privileges are disabled until command
31129bd2886SAlan Wright  * execution.  The permitted and the limit set contains all privileges.  The
31229bd2886SAlan Wright  * inheritable set contains no privileges.
31329bd2886SAlan Wright  */
31429bd2886SAlan Wright 
31529bd2886SAlan Wright static const char root_cp[] = "/core.%f.%t";
31629bd2886SAlan Wright static const char daemon_cp[] = "/var/tmp/core.%f.%t";
31729bd2886SAlan Wright 
31829bd2886SAlan Wright static int
31929bd2886SAlan Wright smb_init_daemon_priv(int flags, uid_t uid, gid_t gid)
32029bd2886SAlan Wright {
32129bd2886SAlan Wright 	priv_set_t *perm = NULL;
32229bd2886SAlan Wright 	int ret = -1;
32329bd2886SAlan Wright 	char buf[1024];
32429bd2886SAlan Wright 
32529bd2886SAlan Wright 	/*
32629bd2886SAlan Wright 	 * This is not a significant failure: it allows us to start programs
32729bd2886SAlan Wright 	 * with sufficient privileges and with the proper uid.   We don't
32829bd2886SAlan Wright 	 * care enough about the extra groups in that case.
32929bd2886SAlan Wright 	 */
33029bd2886SAlan Wright 	if (flags & PU_RESETGROUPS)
33129bd2886SAlan Wright 		(void) setgroups(0, NULL);
33229bd2886SAlan Wright 
33329bd2886SAlan Wright 	if (gid != (gid_t)-1 && setgid(gid) != 0)
33429bd2886SAlan Wright 		goto end;
33529bd2886SAlan Wright 
33629bd2886SAlan Wright 	perm = priv_allocset();
33729bd2886SAlan Wright 	if (perm == NULL)
33829bd2886SAlan Wright 		goto end;
33929bd2886SAlan Wright 
34029bd2886SAlan Wright 	/* E = P */
34129bd2886SAlan Wright 	(void) getppriv(PRIV_PERMITTED, perm);
34229bd2886SAlan Wright 	(void) setppriv(PRIV_SET, PRIV_EFFECTIVE, perm);
34329bd2886SAlan Wright 
34429bd2886SAlan Wright 	/* Now reset suid and euid */
34529bd2886SAlan Wright 	if (uid != (uid_t)-1 && setreuid(uid, uid) != 0)
34629bd2886SAlan Wright 		goto end;
34729bd2886SAlan Wright 
34829bd2886SAlan Wright 	/* I = 0 */
34929bd2886SAlan Wright 	priv_emptyset(perm);
35029bd2886SAlan Wright 	ret = setppriv(PRIV_SET, PRIV_INHERITABLE, perm);
35129bd2886SAlan Wright end:
35229bd2886SAlan Wright 	priv_freeset(perm);
35329bd2886SAlan Wright 
35429bd2886SAlan Wright 	if (core_get_process_path(buf, sizeof (buf), getpid()) == 0 &&
35529bd2886SAlan Wright 	    strcmp(buf, "core") == 0) {
35629bd2886SAlan Wright 
35729bd2886SAlan Wright 		if ((uid == (uid_t)-1 ? geteuid() : uid) == 0) {
35829bd2886SAlan Wright 			(void) core_set_process_path(root_cp, sizeof (root_cp),
35929bd2886SAlan Wright 			    getpid());
36029bd2886SAlan Wright 		} else {
36129bd2886SAlan Wright 			(void) core_set_process_path(daemon_cp,
36229bd2886SAlan Wright 			    sizeof (daemon_cp), getpid());
36329bd2886SAlan Wright 		}
36429bd2886SAlan Wright 	}
36529bd2886SAlan Wright 	(void) setpflags(__PROC_PROTECT, 0);
36629bd2886SAlan Wright 
36729bd2886SAlan Wright 	return (ret);
36829bd2886SAlan Wright }
36929bd2886SAlan Wright 
37029bd2886SAlan Wright /*
37129bd2886SAlan Wright  * Most privileges, except the ones that are required for smbd, are turn off
37229bd2886SAlan Wright  * in the effective set.  They will be turn on when needed for command
37329bd2886SAlan Wright  * execution during share connection/disconnection.
37429bd2886SAlan Wright  */
375da6c28aaSamw static void
376da6c28aaSamw smbd_daemonize_fini(int fd, int exit_status)
377da6c28aaSamw {
37829bd2886SAlan Wright 	priv_set_t *pset;
37929bd2886SAlan Wright 
380da6c28aaSamw 	/*
381da6c28aaSamw 	 * Now that we're running, if a pipe fd was specified, write an exit
382da6c28aaSamw 	 * status to it to indicate that our parent process can safely detach.
383da6c28aaSamw 	 * Then proceed to loading the remaining non-built-in modules.
384da6c28aaSamw 	 */
385da6c28aaSamw 	if (fd >= 0)
386da6c28aaSamw 		(void) write(fd, &exit_status, sizeof (exit_status));
387da6c28aaSamw 
388da6c28aaSamw 	(void) close(fd);
389da6c28aaSamw 
39029bd2886SAlan Wright 	pset = priv_allocset();
39129bd2886SAlan Wright 	if (pset == NULL)
39229bd2886SAlan Wright 		return;
39329bd2886SAlan Wright 
39429bd2886SAlan Wright 	priv_emptyset(pset);
39529bd2886SAlan Wright 
39629bd2886SAlan Wright 	/* list of privileges for smbd */
39729bd2886SAlan Wright 	(void) priv_addset(pset, PRIV_NET_MAC_AWARE);
39829bd2886SAlan Wright 	(void) priv_addset(pset, PRIV_NET_PRIVADDR);
39929bd2886SAlan Wright 	(void) priv_addset(pset, PRIV_PROC_AUDIT);
40029bd2886SAlan Wright 	(void) priv_addset(pset, PRIV_SYS_DEVICES);
40129bd2886SAlan Wright 	(void) priv_addset(pset, PRIV_SYS_SMB);
40229bd2886SAlan Wright 
40329bd2886SAlan Wright 	priv_inverse(pset);
40429bd2886SAlan Wright 
40529bd2886SAlan Wright 	/* turn off unneeded privileges */
40629bd2886SAlan Wright 	(void) setppriv(PRIV_OFF, PRIV_EFFECTIVE, pset);
40729bd2886SAlan Wright 
40829bd2886SAlan Wright 	priv_freeset(pset);
40929bd2886SAlan Wright 
41029bd2886SAlan Wright 	/* reenable core dumps */
41129bd2886SAlan Wright 	__fini_daemon_priv(NULL);
412da6c28aaSamw }
413da6c28aaSamw 
414faa1795aSjb150015 /*
415faa1795aSjb150015  * smbd_service_init
416faa1795aSjb150015  */
417da6c28aaSamw static int
418da6c28aaSamw smbd_service_init(void)
419da6c28aaSamw {
420da6c28aaSamw 	int	rc;
421da6c28aaSamw 
42229bd2886SAlan Wright 	smbd.s_pid = getpid();
423faa1795aSjb150015 	if ((mkdir(SMB_DBDIR, 0700) < 0) && (errno != EEXIST)) {
424faa1795aSjb150015 		smbd_report("mkdir %s: %s", SMB_DBDIR, strerror(errno));
425da6c28aaSamw 		return (1);
426da6c28aaSamw 	}
427da6c28aaSamw 
428faa1795aSjb150015 	if ((rc = smb_ccache_init(SMB_VARRUN_DIR, SMB_CCACHE_FILE)) != 0) {
429faa1795aSjb150015 		if (rc == -1)
430faa1795aSjb150015 			smbd_report("mkdir %s: %s", SMB_VARRUN_DIR,
431faa1795aSjb150015 			    strerror(errno));
432faa1795aSjb150015 		else
433da6c28aaSamw 			smbd_report("unable to set KRB5CCNAME");
434da6c28aaSamw 		return (1);
435da6c28aaSamw 	}
436da6c28aaSamw 
437*bbf6f00cSJordan Brown 	smb_codepage_init();
438da6c28aaSamw 
4396537f381Sas200622 	if (!smb_wka_init()) {
440da6c28aaSamw 		smbd_report("out of memory");
441da6c28aaSamw 		return (1);
442da6c28aaSamw 	}
443da6c28aaSamw 
4446537f381Sas200622 	if (smb_nicmon_start(SMBD_DEFAULT_INSTANCE_FMRI) != 0)
4456537f381Sas200622 		smbd_report("NIC monitoring failed to start");
4466537f381Sas200622 
4478d7e4166Sjose borrego 	(void) dyndns_start();
448a0aa776eSAlan Wright 	smb_ipc_init();
449da6c28aaSamw 
450dc20a302Sas200622 	if (smb_netbios_start() != 0)
451dc20a302Sas200622 		smbd_report("NetBIOS services failed to start");
452dc20a302Sas200622 	else
453dc20a302Sas200622 		smbd_report("NetBIOS services started");
454dc20a302Sas200622 
455da6c28aaSamw 	/* Get the ID map client handle */
456da6c28aaSamw 	if ((rc = smb_idmap_start()) != 0) {
457da6c28aaSamw 		smbd_report("no idmap handle");
458da6c28aaSamw 		return (rc);
459da6c28aaSamw 	}
460da6c28aaSamw 
4616537f381Sas200622 	smbd.s_secmode = smb_config_get_secmode();
462a0aa776eSAlan Wright 	if ((rc = smb_domain_init(smbd.s_secmode)) != 0) {
463dc20a302Sas200622 		if (rc == SMB_DOMAIN_NOMACHINE_SID) {
464dc20a302Sas200622 			smbd_report(
465dc20a302Sas200622 			    "no machine SID: check idmap configuration");
466da6c28aaSamw 			return (rc);
467da6c28aaSamw 		}
468dc20a302Sas200622 	}
469da6c28aaSamw 
4703db3f65cSamw 	smb_ads_init();
471da6c28aaSamw 	if ((rc = mlsvc_init()) != 0) {
472da6c28aaSamw 		smbd_report("msrpc initialization failed");
473da6c28aaSamw 		return (rc);
474da6c28aaSamw 	}
475da6c28aaSamw 
476c8ec8eeaSjose borrego 	if (smbd.s_secmode == SMB_SECMODE_DOMAIN)
4778d7e4166Sjose borrego 		if (smbd_locate_dc_start() != 0)
478c8ec8eeaSjose borrego 			smbd_report("dc discovery failed %s", strerror(errno));
479faa1795aSjb150015 
4806537f381Sas200622 	smbd.s_door_srv = smb_door_srv_start();
4816537f381Sas200622 	if (smbd.s_door_srv < 0)
482da6c28aaSamw 		return (rc);
483da6c28aaSamw 
484da6c28aaSamw 	if ((rc = smbd_refresh_init()) != 0)
485da6c28aaSamw 		return (rc);
486da6c28aaSamw 
4878d7e4166Sjose borrego 	dyndns_update_zones();
488da6c28aaSamw 
489da6c28aaSamw 	(void) smbd_localtime_init();
490da6c28aaSamw 
4913db3f65cSamw 	smbd.s_door_opipe = smbd_opipe_dsrv_start();
4923db3f65cSamw 	if (smbd.s_door_opipe < 0) {
4933db3f65cSamw 		smbd_report("opipe initialization failed %s",
49455bf511dSas200622 		    strerror(errno));
49555bf511dSas200622 		return (rc);
49655bf511dSas200622 	}
49755bf511dSas200622 
498dc20a302Sas200622 	(void) smb_lgrp_start();
4997b59d02dSjb150015 
5003db3f65cSamw 	smb_pwd_init(B_TRUE);
5017b59d02dSjb150015 
502b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((rc = smb_shr_start()) != 0) {
503b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smbd_report("share initialization failed: %s", strerror(errno));
5046537f381Sas200622 		return (rc);
5056537f381Sas200622 	}
506da6c28aaSamw 
507b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smbd.s_door_lmshr = smb_share_dsrv_start();
508b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smbd.s_door_lmshr < 0) {
509b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smbd_report("share initialization failed");
510b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
511b89a8333Snatalie li - Sun Microsystems - Irvine United States 
5128d7e4166Sjose borrego 	if ((rc = smbd_kernel_bind()) != 0) {
513b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smbd_report("kernel bind error: %s", strerror(errno));
514c8ec8eeaSjose borrego 		return (rc);
515c8ec8eeaSjose borrego 	}
516c8ec8eeaSjose borrego 
5178d7e4166Sjose borrego 	if ((rc = smb_shr_load()) != 0) {
5188d7e4166Sjose borrego 		smbd_report("failed to start loading shares: %s",
5198d7e4166Sjose borrego 		    strerror(errno));
5208d7e4166Sjose borrego 		return (rc);
5218d7e4166Sjose borrego 	}
5228d7e4166Sjose borrego 
523c8ec8eeaSjose borrego 	return (0);
52455bf511dSas200622 }
52555bf511dSas200622 
526da6c28aaSamw /*
527da6c28aaSamw  * Close the kernel service and shutdown smbd services.
528da6c28aaSamw  * This function is registered with atexit(): ensure that anything
529da6c28aaSamw  * called from here is safe to be called multiple times.
530da6c28aaSamw  */
531da6c28aaSamw static void
532da6c28aaSamw smbd_service_fini(void)
533da6c28aaSamw {
5343db3f65cSamw 	smbd_opipe_dsrv_stop();
5356537f381Sas200622 	smb_wka_fini();
536da6c28aaSamw 	smbd_refresh_fini();
537da6c28aaSamw 	smbd_kernel_unbind();
538da6c28aaSamw 	smb_door_srv_stop();
5393ad684d6Sjb150015 	smb_share_dsrv_stop();
5403db3f65cSamw 	smb_shr_stop();
5418d7e4166Sjose borrego 	dyndns_stop();
542da6c28aaSamw 	smb_nicmon_stop();
543da6c28aaSamw 	smb_idmap_stop();
544dc20a302Sas200622 	smb_lgrp_stop();
545faa1795aSjb150015 	smb_ccache_remove(SMB_CCACHE_PATH);
5467b59d02dSjb150015 	smb_pwd_fini();
547a0aa776eSAlan Wright 	smb_domain_fini();
54829bd2886SAlan Wright 	mlsvc_fini();
54929bd2886SAlan Wright 	smb_ads_fini();
550a0aa776eSAlan Wright 	smb_netbios_stop();
551da6c28aaSamw }
552da6c28aaSamw 
553faa1795aSjb150015 
554da6c28aaSamw /*
555da6c28aaSamw  * smbd_refresh_init()
556da6c28aaSamw  *
557da6c28aaSamw  * SMB service refresh thread initialization.  This thread waits for a
558da6c28aaSamw  * refresh event and updates the daemon's view of the configuration
559da6c28aaSamw  * before going back to sleep.
560da6c28aaSamw  */
561da6c28aaSamw static int
562da6c28aaSamw smbd_refresh_init()
563da6c28aaSamw {
564da6c28aaSamw 	pthread_attr_t		tattr;
565da6c28aaSamw 	pthread_condattr_t	cattr;
566da6c28aaSamw 	int			rc;
567da6c28aaSamw 
568da6c28aaSamw 	(void) pthread_condattr_init(&cattr);
569da6c28aaSamw 	(void) pthread_cond_init(&refresh_cond, &cattr);
570da6c28aaSamw 	(void) pthread_condattr_destroy(&cattr);
571da6c28aaSamw 
572da6c28aaSamw 	(void) pthread_mutex_init(&refresh_mutex, NULL);
573da6c28aaSamw 
574da6c28aaSamw 	(void) pthread_attr_init(&tattr);
575da6c28aaSamw 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
576da6c28aaSamw 	rc = pthread_create(&refresh_thr, &tattr, smbd_refresh_monitor, 0);
577da6c28aaSamw 	(void) pthread_attr_destroy(&tattr);
578da6c28aaSamw 
5796537f381Sas200622 	return (rc);
580da6c28aaSamw }
581da6c28aaSamw 
582da6c28aaSamw /*
583da6c28aaSamw  * smbd_refresh_fini()
584da6c28aaSamw  *
585da6c28aaSamw  * Stop the refresh thread.
586da6c28aaSamw  */
587da6c28aaSamw static void
588da6c28aaSamw smbd_refresh_fini()
589da6c28aaSamw {
590da6c28aaSamw 	(void) pthread_cancel(refresh_thr);
591da6c28aaSamw 
592da6c28aaSamw 	(void) pthread_cond_destroy(&refresh_cond);
593da6c28aaSamw 	(void) pthread_mutex_destroy(&refresh_mutex);
594da6c28aaSamw }
595da6c28aaSamw 
596da6c28aaSamw /*
597da6c28aaSamw  * smbd_refresh_monitor()
598da6c28aaSamw  *
599da6c28aaSamw  * Wait for a refresh event. When this thread wakes up, update the
600da6c28aaSamw  * smbd configuration from the SMF config information then go back to
601da6c28aaSamw  * wait for the next refresh.
602da6c28aaSamw  */
603da6c28aaSamw /*ARGSUSED*/
604da6c28aaSamw static void *
605da6c28aaSamw smbd_refresh_monitor(void *arg)
606da6c28aaSamw {
60729bd2886SAlan Wright 	smb_kmod_cfg_t	cfg;
60829bd2886SAlan Wright 	int		error;
6093ad684d6Sjb150015 
6108d7e4166Sjose borrego 	while (!smbd.s_shutting_down) {
611da6c28aaSamw 		(void) pthread_mutex_lock(&refresh_mutex);
6128d7e4166Sjose borrego 		while ((atomic_swap_uint(&smbd.s_refreshes, 0) == 0) &&
6138d7e4166Sjose borrego 		    (!smbd.s_shutting_down))
6148d7e4166Sjose borrego 			(void) pthread_cond_wait(&refresh_cond, &refresh_mutex);
6158d7e4166Sjose borrego 		(void) pthread_mutex_unlock(&refresh_mutex);
6168d7e4166Sjose borrego 
6178d7e4166Sjose borrego 		if (smbd.s_shutting_down) {
6188d7e4166Sjose borrego 			syslog(LOG_DEBUG, "shutting down");
61929bd2886SAlan Wright 			exit((smbd.s_fatal_error) ? SMF_EXIT_ERR_FATAL :
62029bd2886SAlan Wright 			    SMF_EXIT_OK);
6218d7e4166Sjose borrego 		}
6228d7e4166Sjose borrego 
623da6c28aaSamw 		/*
624da6c28aaSamw 		 * We've been woken up by a refresh event so go do
625da6c28aaSamw 		 * what is necessary.
626da6c28aaSamw 		 */
6273db3f65cSamw 		smb_ads_refresh();
628faa1795aSjb150015 		smb_ccache_remove(SMB_CCACHE_PATH);
6296537f381Sas200622 
6308d7e4166Sjose borrego 		/*
6318d7e4166Sjose borrego 		 * Start the dyndns thread, if required.
6328d7e4166Sjose borrego 		 * Clear the DNS zones for the existing interfaces
6338d7e4166Sjose borrego 		 * before updating the NIC interface list.
6348d7e4166Sjose borrego 		 */
6358d7e4166Sjose borrego 		(void) dyndns_start();
6368d7e4166Sjose borrego 		dyndns_clear_zones();
6376537f381Sas200622 
6386537f381Sas200622 		/* re-initialize NIC table */
6396537f381Sas200622 		if (smb_nic_init() != 0)
6406537f381Sas200622 			smbd_report("failed to get NIC information");
6416537f381Sas200622 		smb_netbios_name_reconfig();
6426537f381Sas200622 		smb_browser_reconfig();
6437f667e74Sjose borrego 		smbd_refresh_dc();
6448d7e4166Sjose borrego 		dyndns_update_zones();
6456537f381Sas200622 
6468d7e4166Sjose borrego 		if (smbd_set_netlogon_cred()) {
6476537f381Sas200622 			/*
6488d7e4166Sjose borrego 			 * Restart required because the domain changed
6498d7e4166Sjose borrego 			 * or the credential chain setup failed.
6506537f381Sas200622 			 */
6518d7e4166Sjose borrego 			if (smb_smf_restart_service() != 0) {
6528d7e4166Sjose borrego 				syslog(LOG_ERR,
6538d7e4166Sjose borrego 				    "unable to restart smb service. "
6548d7e4166Sjose borrego 				    "Run 'svcs -xv smb/server' for more "
6558d7e4166Sjose borrego 				    "information.");
6568d7e4166Sjose borrego 				smbd.s_shutting_down = B_TRUE;
6578d7e4166Sjose borrego 				exit(SMF_EXIT_OK);
6588d7e4166Sjose borrego 			}
6598d7e4166Sjose borrego 
6608d7e4166Sjose borrego 			break;
6618d7e4166Sjose borrego 		}
6628d7e4166Sjose borrego 
66329bd2886SAlan Wright 		if (!smbd.s_kbound) {
66429bd2886SAlan Wright 			error = smbd_kernel_bind();
66529bd2886SAlan Wright 			if (error != 0)
6666537f381Sas200622 				smbd_report("kernel bind error: %s",
66729bd2886SAlan Wright 				    strerror(error));
66829bd2886SAlan Wright 			else
6698d7e4166Sjose borrego 				(void) smb_shr_load();
67029bd2886SAlan Wright 
6716537f381Sas200622 			continue;
6726537f381Sas200622 		}
6736537f381Sas200622 
6748d7e4166Sjose borrego 		(void) smb_shr_load();
6758d7e4166Sjose borrego 
67629bd2886SAlan Wright 		smb_load_kconfig(&cfg);
67729bd2886SAlan Wright 		error = smb_kmod_setcfg(&cfg);
67829bd2886SAlan Wright 		if (error < 0)
67929bd2886SAlan Wright 			smbd_report("configuration update failed: %s",
68029bd2886SAlan Wright 			    strerror(error));
681da6c28aaSamw 	}
6828d7e4166Sjose borrego 
683da6c28aaSamw 	return (NULL);
684da6c28aaSamw }
685da6c28aaSamw 
6867f667e74Sjose borrego /*
6877f667e74Sjose borrego  * Update DC information on a refresh.
6887f667e74Sjose borrego  */
6897f667e74Sjose borrego static void
6907f667e74Sjose borrego smbd_refresh_dc(void)
6917f667e74Sjose borrego {
6927f667e74Sjose borrego 	char fqdomain[MAXHOSTNAMELEN];
6937f667e74Sjose borrego 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
6947f667e74Sjose borrego 		return;
6957f667e74Sjose borrego 
6967f667e74Sjose borrego 	if (smb_getfqdomainname(fqdomain, MAXHOSTNAMELEN))
6977f667e74Sjose borrego 		return;
6987f667e74Sjose borrego 
6997f667e74Sjose borrego 	if (smb_locate_dc(fqdomain, "", NULL))
7007f667e74Sjose borrego 		smbd_report("DC discovery failed");
7017f667e74Sjose borrego }
7027f667e74Sjose borrego 
7038d7e4166Sjose borrego void
7048d7e4166Sjose borrego smbd_set_secmode(int secmode)
7058d7e4166Sjose borrego {
7068d7e4166Sjose borrego 	switch (secmode) {
7078d7e4166Sjose borrego 	case SMB_SECMODE_WORKGRP:
7088d7e4166Sjose borrego 	case SMB_SECMODE_DOMAIN:
7098d7e4166Sjose borrego 		(void) smb_config_set_secmode(secmode);
7108d7e4166Sjose borrego 		smbd.s_secmode = secmode;
7118d7e4166Sjose borrego 		break;
7128d7e4166Sjose borrego 
7138d7e4166Sjose borrego 	default:
7148d7e4166Sjose borrego 		syslog(LOG_ERR, "invalid security mode: %d", secmode);
7158d7e4166Sjose borrego 		syslog(LOG_ERR, "entering maintenance mode");
7168d7e4166Sjose borrego 		(void) smb_smf_maintenance_mode();
7178d7e4166Sjose borrego 	}
7188d7e4166Sjose borrego }
719da6c28aaSamw 
720da6c28aaSamw /*
721da6c28aaSamw  * If the door has already been opened by another process (non-zero pid
722da6c28aaSamw  * in target), we assume that another smbd is already running.  If there
723da6c28aaSamw  * is a race here, it will be caught later when smbsrv is opened because
724da6c28aaSamw  * only one process is allowed to open the device at a time.
725da6c28aaSamw  */
726da6c28aaSamw static int
727da6c28aaSamw smbd_already_running(void)
728da6c28aaSamw {
729da6c28aaSamw 	door_info_t info;
730da6c28aaSamw 	int door;
731da6c28aaSamw 
732faa1795aSjb150015 	if ((door = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0)
733da6c28aaSamw 		return (0);
734da6c28aaSamw 
735da6c28aaSamw 	if (door_info(door, &info) < 0)
736da6c28aaSamw 		return (0);
737da6c28aaSamw 
738da6c28aaSamw 	if (info.di_target > 0) {
739da6c28aaSamw 		smbd_report("already running: pid %ld\n", info.di_target);
740da6c28aaSamw 		(void) close(door);
741da6c28aaSamw 		return (1);
742da6c28aaSamw 	}
743da6c28aaSamw 
744da6c28aaSamw 	(void) close(door);
745da6c28aaSamw 	return (0);
746da6c28aaSamw }
747da6c28aaSamw 
748faa1795aSjb150015 /*
749faa1795aSjb150015  * smbd_kernel_bind
7506537f381Sas200622  *
7516537f381Sas200622  * This function open the smbsrv device and start the kernel service.
752faa1795aSjb150015  */
753da6c28aaSamw static int
7546537f381Sas200622 smbd_kernel_bind(void)
755da6c28aaSamw {
756faa1795aSjb150015 	int rc;
757faa1795aSjb150015 
7588d7e4166Sjose borrego 	smbd_kernel_unbind();
759da6c28aaSamw 
76029bd2886SAlan Wright 	rc = smb_kmod_bind();
76129bd2886SAlan Wright 	if (rc == 0) {
76229bd2886SAlan Wright 		rc = smbd_kernel_start();
76329bd2886SAlan Wright 		if (rc != 0)
76429bd2886SAlan Wright 			smb_kmod_unbind();
76529bd2886SAlan Wright 		else
76629bd2886SAlan Wright 			smbd.s_kbound = B_TRUE;
76729bd2886SAlan Wright 	}
76829bd2886SAlan Wright 	return (rc);
769da6c28aaSamw }
77094fff790SAlan Wright 
77129bd2886SAlan Wright static int
77229bd2886SAlan Wright smbd_kernel_start(void)
77329bd2886SAlan Wright {
77429bd2886SAlan Wright 	smb_kmod_cfg_t	cfg;
77529bd2886SAlan Wright 	int		rc;
7768d7e4166Sjose borrego 
77729bd2886SAlan Wright 	smb_load_kconfig(&cfg);
77829bd2886SAlan Wright 	rc = smb_kmod_setcfg(&cfg);
77929bd2886SAlan Wright 	if (rc != 0)
78029bd2886SAlan Wright 		return (rc);
78129bd2886SAlan Wright 
78229bd2886SAlan Wright 	rc = smb_kmod_setgmtoff(smbd_gmtoff());
78329bd2886SAlan Wright 	if (rc != 0)
78429bd2886SAlan Wright 		return (rc);
78529bd2886SAlan Wright 
78629bd2886SAlan Wright 	rc = smb_kmod_start(smbd.s_door_opipe, smbd.s_door_lmshr,
78729bd2886SAlan Wright 	    smbd.s_door_srv);
78829bd2886SAlan Wright 	if (rc != 0)
78929bd2886SAlan Wright 		return (rc);
790da6c28aaSamw 
791a4b239dfSjose borrego 	rc = smbd_start_listeners();
79229bd2886SAlan Wright 	if (rc != 0)
793faa1795aSjb150015 		return (rc);
79429bd2886SAlan Wright 
79529bd2886SAlan Wright 	return (0);
796faa1795aSjb150015 }
797faa1795aSjb150015 
798faa1795aSjb150015 /*
799faa1795aSjb150015  * smbd_kernel_unbind
800faa1795aSjb150015  */
801faa1795aSjb150015 static void
802faa1795aSjb150015 smbd_kernel_unbind(void)
803faa1795aSjb150015 {
804a4b239dfSjose borrego 	smbd_stop_listeners();
80529bd2886SAlan Wright 	smb_kmod_unbind();
8066537f381Sas200622 	smbd.s_kbound = B_FALSE;
807faa1795aSjb150015 }
80894fff790SAlan Wright 
809da6c28aaSamw /*
810da6c28aaSamw  * Initialization of the localtime thread.
811da6c28aaSamw  * Returns 0 on success, an error number if thread creation fails.
812da6c28aaSamw  */
813da6c28aaSamw 
814da6c28aaSamw int
815da6c28aaSamw smbd_localtime_init(void)
816da6c28aaSamw {
817da6c28aaSamw 	pthread_attr_t tattr;
818da6c28aaSamw 	int rc;
819da6c28aaSamw 
820da6c28aaSamw 	(void) pthread_attr_init(&tattr);
821da6c28aaSamw 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
822da6c28aaSamw 	rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0);
823da6c28aaSamw 	(void) pthread_attr_destroy(&tattr);
824da6c28aaSamw 	return (rc);
825da6c28aaSamw }
826da6c28aaSamw 
827da6c28aaSamw /*
828da6c28aaSamw  * Local time thread to kernel land.
829da6c28aaSamw  * Send local gmtoff to kernel module one time at startup
830da6c28aaSamw  * and each time it changes (up to twice a year).
831da6c28aaSamw  * Local gmtoff is checked once every 15 minutes and
832da6c28aaSamw  * since some timezones are aligned on half and qtr hour boundaries,
833da6c28aaSamw  * once an hour would likely suffice.
834da6c28aaSamw  */
835da6c28aaSamw 
836da6c28aaSamw /*ARGSUSED*/
837da6c28aaSamw static void *
838da6c28aaSamw smbd_localtime_monitor(void *arg)
839da6c28aaSamw {
840da6c28aaSamw 	struct tm local_tm;
841c8ec8eeaSjose borrego 	time_t secs;
842c8ec8eeaSjose borrego 	int32_t gmtoff, last_gmtoff = -1;
843da6c28aaSamw 	int timeout;
84429bd2886SAlan Wright 	int error;
84594fff790SAlan Wright 
846da6c28aaSamw 	for (;;) {
847c8ec8eeaSjose borrego 		gmtoff = smbd_gmtoff();
848da6c28aaSamw 
84929bd2886SAlan Wright 		if ((last_gmtoff != gmtoff) && smbd.s_kbound) {
85029bd2886SAlan Wright 			error = smb_kmod_setgmtoff(gmtoff);
85129bd2886SAlan Wright 			if (error != 0)
85229bd2886SAlan Wright 				smbd_report("localtime set failed: %s",
85329bd2886SAlan Wright 				    strerror(error));
854da6c28aaSamw 		}
855da6c28aaSamw 
856da6c28aaSamw 		/*
857da6c28aaSamw 		 * Align the next iteration on a fifteen minute boundary.
858da6c28aaSamw 		 */
859da6c28aaSamw 		secs = time(0);
860da6c28aaSamw 		(void) localtime_r(&secs, &local_tm);
861da6c28aaSamw 		timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN);
862da6c28aaSamw 		(void) sleep(timeout);
863da6c28aaSamw 
864da6c28aaSamw 		last_gmtoff = gmtoff;
865da6c28aaSamw 	}
866da6c28aaSamw 
867da6c28aaSamw 	/*NOTREACHED*/
868da6c28aaSamw 	return (NULL);
869da6c28aaSamw }
870da6c28aaSamw 
871c8ec8eeaSjose borrego /*
872c8ec8eeaSjose borrego  * smbd_gmtoff
873c8ec8eeaSjose borrego  *
874c8ec8eeaSjose borrego  * Determine offset from GMT. If daylight saving time use altzone,
875c8ec8eeaSjose borrego  * otherwise use timezone.
876c8ec8eeaSjose borrego  */
877c8ec8eeaSjose borrego static int32_t
878c8ec8eeaSjose borrego smbd_gmtoff(void)
879c8ec8eeaSjose borrego {
880c8ec8eeaSjose borrego 	time_t clock_val;
881c8ec8eeaSjose borrego 	struct tm *atm;
882c8ec8eeaSjose borrego 	int32_t gmtoff;
883c8ec8eeaSjose borrego 
884c8ec8eeaSjose borrego 	(void) time(&clock_val);
885c8ec8eeaSjose borrego 	atm = localtime(&clock_val);
886c8ec8eeaSjose borrego 
887c8ec8eeaSjose borrego 	gmtoff = (atm->tm_isdst) ? altzone : timezone;
888c8ec8eeaSjose borrego 
889c8ec8eeaSjose borrego 	return (gmtoff);
890c8ec8eeaSjose borrego }
891c8ec8eeaSjose borrego 
892da6c28aaSamw static void
893da6c28aaSamw smbd_sig_handler(int sigval)
894da6c28aaSamw {
895da6c28aaSamw 	if (smbd.s_sigval == 0)
8968d7e4166Sjose borrego 		(void) atomic_swap_uint(&smbd.s_sigval, sigval);
8978d7e4166Sjose borrego 
8988d7e4166Sjose borrego 	if (sigval == SIGHUP) {
8998d7e4166Sjose borrego 		atomic_inc_uint(&smbd.s_refreshes);
9008d7e4166Sjose borrego 		(void) pthread_cond_signal(&refresh_cond);
9018d7e4166Sjose borrego 	}
9028d7e4166Sjose borrego 
9038d7e4166Sjose borrego 	if (sigval == SIGINT || sigval == SIGTERM) {
9048d7e4166Sjose borrego 		smbd.s_shutting_down = B_TRUE;
9058d7e4166Sjose borrego 		(void) pthread_cond_signal(&refresh_cond);
9068d7e4166Sjose borrego 	}
907da6c28aaSamw }
908da6c28aaSamw 
909da6c28aaSamw /*
910da6c28aaSamw  * Set up configuration options and parse the command line.
911da6c28aaSamw  * This function will determine if we will run as a daemon
912da6c28aaSamw  * or in the foreground.
913da6c28aaSamw  *
914da6c28aaSamw  * Failure to find a uid or gid results in using the default (0).
915da6c28aaSamw  */
916da6c28aaSamw static int
917da6c28aaSamw smbd_setup_options(int argc, char *argv[])
918da6c28aaSamw {
919da6c28aaSamw 	struct passwd *pwd;
920da6c28aaSamw 	struct group *grp;
921da6c28aaSamw 	int c;
922da6c28aaSamw 
923da6c28aaSamw 	if ((pwd = getpwnam("root")) != NULL)
924da6c28aaSamw 		smbd.s_uid = pwd->pw_uid;
925da6c28aaSamw 
926da6c28aaSamw 	if ((grp = getgrnam("sys")) != NULL)
927da6c28aaSamw 		smbd.s_gid = grp->gr_gid;
928da6c28aaSamw 
929dc20a302Sas200622 	smbd.s_fg = smb_config_get_fg_flag();
930da6c28aaSamw 
931da6c28aaSamw 	while ((c = getopt(argc, argv, ":f")) != -1) {
932da6c28aaSamw 		switch (c) {
933da6c28aaSamw 		case 'f':
934da6c28aaSamw 			smbd.s_fg = 1;
935da6c28aaSamw 			break;
936da6c28aaSamw 
937da6c28aaSamw 		case ':':
938da6c28aaSamw 		case '?':
939da6c28aaSamw 		default:
940da6c28aaSamw 			smbd_usage(stderr);
941da6c28aaSamw 			return (-1);
942da6c28aaSamw 		}
943da6c28aaSamw 	}
944da6c28aaSamw 
945da6c28aaSamw 	return (0);
946da6c28aaSamw }
947da6c28aaSamw 
948da6c28aaSamw static void
949da6c28aaSamw smbd_usage(FILE *fp)
950da6c28aaSamw {
951da6c28aaSamw 	static char *help[] = {
952da6c28aaSamw 		"-f  run program in foreground"
953da6c28aaSamw 	};
954da6c28aaSamw 
955da6c28aaSamw 	int i;
956da6c28aaSamw 
957da6c28aaSamw 	(void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname);
958da6c28aaSamw 
959da6c28aaSamw 	for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i)
960da6c28aaSamw 		(void) fprintf(fp, "    %s\n", help[i]);
961da6c28aaSamw }
962da6c28aaSamw 
963da6c28aaSamw static void
964da6c28aaSamw smbd_report(const char *fmt, ...)
965da6c28aaSamw {
966da6c28aaSamw 	char buf[128];
967da6c28aaSamw 	va_list ap;
968da6c28aaSamw 
969da6c28aaSamw 	if (fmt == NULL)
970da6c28aaSamw 		return;
971da6c28aaSamw 
972da6c28aaSamw 	va_start(ap, fmt);
973da6c28aaSamw 	(void) vsnprintf(buf, 128, fmt, ap);
974da6c28aaSamw 	va_end(ap);
975da6c28aaSamw 
976da6c28aaSamw 	(void) fprintf(stderr, "smbd: %s\n", buf);
977da6c28aaSamw }
978da6c28aaSamw 
979a4b239dfSjose borrego static int
980a4b239dfSjose borrego smbd_start_listeners(void)
981a4b239dfSjose borrego {
982a4b239dfSjose borrego 	int		rc1;
983a4b239dfSjose borrego 	int		rc2;
984a4b239dfSjose borrego 	pthread_attr_t	tattr;
985a4b239dfSjose borrego 
986a4b239dfSjose borrego 	(void) pthread_attr_init(&tattr);
987a4b239dfSjose borrego 
988a4b239dfSjose borrego 	if (!smbd.s_nbt_listener_running) {
989a4b239dfSjose borrego 		rc1 = pthread_create(&smbd.s_nbt_listener_id, &tattr,
990a4b239dfSjose borrego 		    smbd_nbt_listener, NULL);
991a4b239dfSjose borrego 		if (rc1 != 0)
992a4b239dfSjose borrego 			smbd_report("unable to start NBT service");
993a4b239dfSjose borrego 		else
994a4b239dfSjose borrego 			smbd.s_nbt_listener_running = B_TRUE;
995a4b239dfSjose borrego 	}
996a4b239dfSjose borrego 
997a4b239dfSjose borrego 	if (!smbd.s_tcp_listener_running) {
998a4b239dfSjose borrego 		rc2 = pthread_create(&smbd.s_tcp_listener_id, &tattr,
999a4b239dfSjose borrego 		    smbd_tcp_listener, NULL);
1000a4b239dfSjose borrego 		if (rc2 != 0)
1001a4b239dfSjose borrego 			smbd_report("unable to start TCP service");
1002a4b239dfSjose borrego 		else
1003a4b239dfSjose borrego 			smbd.s_tcp_listener_running = B_TRUE;
1004a4b239dfSjose borrego 	}
1005a4b239dfSjose borrego 
1006a4b239dfSjose borrego 	(void) pthread_attr_destroy(&tattr);
1007a4b239dfSjose borrego 
1008a4b239dfSjose borrego 	if (rc1 != 0)
1009a4b239dfSjose borrego 		return (rc1);
1010a4b239dfSjose borrego 	return (rc2);
1011a4b239dfSjose borrego }
1012a4b239dfSjose borrego 
1013a4b239dfSjose borrego static void
1014a4b239dfSjose borrego smbd_stop_listeners(void)
1015a4b239dfSjose borrego {
1016a4b239dfSjose borrego 	void	*status;
1017a4b239dfSjose borrego 
1018a4b239dfSjose borrego 	if (smbd.s_nbt_listener_running) {
1019a4b239dfSjose borrego 		(void) pthread_kill(smbd.s_nbt_listener_id, SIGTERM);
1020a4b239dfSjose borrego 		(void) pthread_join(smbd.s_nbt_listener_id, &status);
1021a4b239dfSjose borrego 		smbd.s_nbt_listener_running = B_FALSE;
1022a4b239dfSjose borrego 	}
1023a4b239dfSjose borrego 
1024a4b239dfSjose borrego 	if (smbd.s_tcp_listener_running) {
1025a4b239dfSjose borrego 		(void) pthread_kill(smbd.s_tcp_listener_id, SIGTERM);
1026a4b239dfSjose borrego 		(void) pthread_join(smbd.s_tcp_listener_id, &status);
1027a4b239dfSjose borrego 		smbd.s_tcp_listener_running = B_FALSE;
1028a4b239dfSjose borrego 	}
1029a4b239dfSjose borrego }
1030a4b239dfSjose borrego 
1031da6c28aaSamw /*
103229bd2886SAlan Wright  * Perform fatal error exit.
103329bd2886SAlan Wright  */
103429bd2886SAlan Wright static void
103529bd2886SAlan Wright smbd_fatal_error(const char *msg)
103629bd2886SAlan Wright {
103729bd2886SAlan Wright 	if (msg == NULL)
103829bd2886SAlan Wright 		msg = "Fatal error";
103929bd2886SAlan Wright 
104029bd2886SAlan Wright 	smbd_report("%s", msg);
104129bd2886SAlan Wright 	smbd.s_fatal_error = B_TRUE;
104229bd2886SAlan Wright 	(void) kill(smbd.s_pid, SIGTERM);
104329bd2886SAlan Wright }
104429bd2886SAlan Wright 
104529bd2886SAlan Wright /*ARGSUSED*/
104629bd2886SAlan Wright static void *
104729bd2886SAlan Wright smbd_nbt_receiver(void *arg)
104829bd2886SAlan Wright {
104929bd2886SAlan Wright 	(void) smb_kmod_nbtreceive();
105029bd2886SAlan Wright 	return (NULL);
105129bd2886SAlan Wright }
105229bd2886SAlan Wright 
105329bd2886SAlan Wright /*ARGSUSED*/
105429bd2886SAlan Wright static void *
105529bd2886SAlan Wright smbd_nbt_listener(void *arg)
105629bd2886SAlan Wright {
105729bd2886SAlan Wright 	pthread_attr_t	tattr;
105829bd2886SAlan Wright 	sigset_t	set;
105929bd2886SAlan Wright 	sigset_t	oset;
106029bd2886SAlan Wright 	pthread_t	tid;
106129bd2886SAlan Wright 	int		error = 0;
106229bd2886SAlan Wright 
106329bd2886SAlan Wright 	(void) sigfillset(&set);
106429bd2886SAlan Wright 	(void) sigdelset(&set, SIGTERM);
106529bd2886SAlan Wright 	(void) sigdelset(&set, SIGINT);
106629bd2886SAlan Wright 	(void) pthread_sigmask(SIG_SETMASK, &set, &oset);
106729bd2886SAlan Wright 	(void) pthread_attr_init(&tattr);
106829bd2886SAlan Wright 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
106929bd2886SAlan Wright 
107029bd2886SAlan Wright 	while (smb_kmod_nbtlisten(error) == 0)
107129bd2886SAlan Wright 		error = pthread_create(&tid, &tattr, smbd_nbt_receiver, NULL);
107229bd2886SAlan Wright 
107329bd2886SAlan Wright 	(void) pthread_attr_destroy(&tattr);
107429bd2886SAlan Wright 
107529bd2886SAlan Wright 	if (!smbd.s_shutting_down)
107629bd2886SAlan Wright 		smbd_fatal_error("NBT listener thread terminated unexpectedly");
107729bd2886SAlan Wright 
107829bd2886SAlan Wright 	return (NULL);
107929bd2886SAlan Wright }
108029bd2886SAlan Wright 
108129bd2886SAlan Wright /*ARGSUSED*/
108229bd2886SAlan Wright static void *
108329bd2886SAlan Wright smbd_tcp_receiver(void *arg)
108429bd2886SAlan Wright {
108529bd2886SAlan Wright 	(void) smb_kmod_tcpreceive();
108629bd2886SAlan Wright 	return (NULL);
108729bd2886SAlan Wright }
108829bd2886SAlan Wright 
108929bd2886SAlan Wright /*ARGSUSED*/
109029bd2886SAlan Wright static void *
109129bd2886SAlan Wright smbd_tcp_listener(void *arg)
109229bd2886SAlan Wright {
109329bd2886SAlan Wright 	pthread_attr_t	tattr;
109429bd2886SAlan Wright 	sigset_t	set;
109529bd2886SAlan Wright 	sigset_t	oset;
109629bd2886SAlan Wright 	pthread_t	tid;
109729bd2886SAlan Wright 	int		error = 0;
109829bd2886SAlan Wright 
109929bd2886SAlan Wright 	(void) sigfillset(&set);
110029bd2886SAlan Wright 	(void) sigdelset(&set, SIGTERM);
110129bd2886SAlan Wright 	(void) sigdelset(&set, SIGINT);
110229bd2886SAlan Wright 	(void) pthread_sigmask(SIG_SETMASK, &set, &oset);
110329bd2886SAlan Wright 	(void) pthread_attr_init(&tattr);
110429bd2886SAlan Wright 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
110529bd2886SAlan Wright 
110629bd2886SAlan Wright 	while (smb_kmod_tcplisten(error) == 0)
110729bd2886SAlan Wright 		error = pthread_create(&tid, &tattr, smbd_tcp_receiver, NULL);
110829bd2886SAlan Wright 
110929bd2886SAlan Wright 	(void) pthread_attr_destroy(&tattr);
111029bd2886SAlan Wright 
111129bd2886SAlan Wright 	if (!smbd.s_shutting_down)
111229bd2886SAlan Wright 		smbd_fatal_error("TCP listener thread terminated unexpectedly");
111329bd2886SAlan Wright 
111429bd2886SAlan Wright 	return (NULL);
111529bd2886SAlan Wright }
111629bd2886SAlan Wright 
111729bd2886SAlan Wright /*
1118da6c28aaSamw  * Enable libumem debugging by default on DEBUG builds.
1119da6c28aaSamw  */
1120da6c28aaSamw #ifdef DEBUG
1121da6c28aaSamw const char *
1122da6c28aaSamw _umem_debug_init(void)
1123da6c28aaSamw {
1124da6c28aaSamw 	return ("default,verbose"); /* $UMEM_DEBUG setting */
1125da6c28aaSamw }
1126da6c28aaSamw 
1127da6c28aaSamw const char *
1128da6c28aaSamw _umem_logging_init(void)
1129da6c28aaSamw {
1130da6c28aaSamw 	return ("fail,contents"); /* $UMEM_LOGGING setting */
1131da6c28aaSamw }
1132da6c28aaSamw #endif
1133