xref: /onnv-gate/usr/src/cmd/smbsrv/smbd/smbd_main.c (revision 5331:3047ad28a67b)
1*5331Samw /*
2*5331Samw  * CDDL HEADER START
3*5331Samw  *
4*5331Samw  * The contents of this file are subject to the terms of the
5*5331Samw  * Common Development and Distribution License (the "License").
6*5331Samw  * You may not use this file except in compliance with the License.
7*5331Samw  *
8*5331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5331Samw  * or http://www.opensolaris.org/os/licensing.
10*5331Samw  * See the License for the specific language governing permissions
11*5331Samw  * and limitations under the License.
12*5331Samw  *
13*5331Samw  * When distributing Covered Code, include this CDDL HEADER in each
14*5331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5331Samw  * If applicable, add the following below this CDDL HEADER, with the
16*5331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
17*5331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5331Samw  *
19*5331Samw  * CDDL HEADER END
20*5331Samw  */
21*5331Samw /*
22*5331Samw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*5331Samw  * Use is subject to license terms.
24*5331Samw  */
25*5331Samw 
26*5331Samw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*5331Samw 
28*5331Samw #include <sys/types.h>
29*5331Samw #include <sys/stat.h>
30*5331Samw #include <sys/ioccom.h>
31*5331Samw #include <stdio.h>
32*5331Samw #include <string.h>
33*5331Samw #include <strings.h>
34*5331Samw #include <stdlib.h>
35*5331Samw #include <unistd.h>
36*5331Samw #include <stdarg.h>
37*5331Samw #include <fcntl.h>
38*5331Samw #include <wait.h>
39*5331Samw #include <signal.h>
40*5331Samw #include <libscf.h>
41*5331Samw #include <limits.h>
42*5331Samw #include <priv_utils.h>
43*5331Samw #include <door.h>
44*5331Samw #include <errno.h>
45*5331Samw #include <syslog.h>
46*5331Samw #include <pthread.h>
47*5331Samw #include <time.h>
48*5331Samw #include <libscf.h>
49*5331Samw #include <zone.h>
50*5331Samw #include <tzfile.h>
51*5331Samw #include <libgen.h>
52*5331Samw #include <pwd.h>
53*5331Samw #include <grp.h>
54*5331Samw 
55*5331Samw #include <smbsrv/smb_door_svc.h>
56*5331Samw #include <smbsrv/smb_ioctl.h>
57*5331Samw #include <smbsrv/libsmb.h>
58*5331Samw #include <smbsrv/libsmbns.h>
59*5331Samw #include <smbsrv/libsmbrdr.h>
60*5331Samw #include <smbsrv/libmlsvc.h>
61*5331Samw 
62*5331Samw #include "smbd.h"
63*5331Samw 
64*5331Samw #define	DRV_DEVICE_PATH	"/devices/pseudo/smbsrv@0:smbsrv"
65*5331Samw #define	SMB_CACHEDIR "/var/run/smb"
66*5331Samw #define	SMB_DBDIR "/var/smb"
67*5331Samw 
68*5331Samw extern void smb_netbios_name_reconfig();
69*5331Samw extern void smb_browser_config();
70*5331Samw 
71*5331Samw static int smbd_daemonize_init(void);
72*5331Samw static void smbd_daemonize_fini(int, int);
73*5331Samw 
74*5331Samw static int smbd_kernel_bind(void);
75*5331Samw static void smbd_kernel_unbind(void);
76*5331Samw static int smbd_already_running(void);
77*5331Samw 
78*5331Samw static int smbd_service_init(void);
79*5331Samw static void smbd_service_fini(void);
80*5331Samw 
81*5331Samw static int smbd_setup_options(int argc, char *argv[]);
82*5331Samw static void smbd_usage(FILE *fp);
83*5331Samw static void smbd_report(const char *fmt, ...);
84*5331Samw 
85*5331Samw static void smbd_sig_handler(int sig);
86*5331Samw 
87*5331Samw static int smbd_localtime_init(void);
88*5331Samw static void *smbd_localtime_monitor(void *arg);
89*5331Samw 
90*5331Samw extern time_t altzone;
91*5331Samw 
92*5331Samw static pthread_t localtime_thr;
93*5331Samw 
94*5331Samw static int smbd_refresh_init(void);
95*5331Samw static void smbd_refresh_fini(void);
96*5331Samw static void *smbd_refresh_monitor(void *);
97*5331Samw static pthread_t refresh_thr;
98*5331Samw static pthread_cond_t refresh_cond;
99*5331Samw static pthread_mutex_t refresh_mutex;
100*5331Samw 
101*5331Samw static smbd_t smbd;
102*5331Samw 
103*5331Samw /*
104*5331Samw  * smbd user land daemon
105*5331Samw  *
106*5331Samw  * Use SMF error codes only on return or exit.
107*5331Samw  */
108*5331Samw int
109*5331Samw main(int argc, char *argv[])
110*5331Samw {
111*5331Samw 	struct sigaction act;
112*5331Samw 	sigset_t set;
113*5331Samw 	uid_t uid;
114*5331Samw 	int pfd = -1;
115*5331Samw 
116*5331Samw 	smbd.s_pname = basename(argv[0]);
117*5331Samw 	openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
118*5331Samw 
119*5331Samw 	if (smbd_setup_options(argc, argv) != 0)
120*5331Samw 		return (SMF_EXIT_ERR_FATAL);
121*5331Samw 
122*5331Samw 	if ((uid = getuid()) != smbd.s_uid) {
123*5331Samw 		smbd_report("user %d: %s", uid, strerror(EPERM));
124*5331Samw 		return (SMF_EXIT_ERR_FATAL);
125*5331Samw 	}
126*5331Samw 
127*5331Samw 	if (getzoneid() != GLOBAL_ZONEID) {
128*5331Samw 		smbd_report("non-global zones are not supported");
129*5331Samw 		return (SMF_EXIT_ERR_FATAL);
130*5331Samw 	}
131*5331Samw 
132*5331Samw 	if (is_system_labeled()) {
133*5331Samw 		smbd_report("Trusted Extensions not supported");
134*5331Samw 		return (SMF_EXIT_ERR_FATAL);
135*5331Samw 	}
136*5331Samw 
137*5331Samw 	if (smbd_already_running())
138*5331Samw 		return (SMF_EXIT_OK);
139*5331Samw 
140*5331Samw 	(void) sigfillset(&set);
141*5331Samw 	(void) sigdelset(&set, SIGABRT);
142*5331Samw 
143*5331Samw 	(void) sigfillset(&act.sa_mask);
144*5331Samw 	act.sa_handler = smbd_sig_handler;
145*5331Samw 	act.sa_flags = 0;
146*5331Samw 
147*5331Samw 	(void) sigaction(SIGTERM, &act, NULL);
148*5331Samw 	(void) sigaction(SIGHUP, &act, NULL);
149*5331Samw 	(void) sigaction(SIGINT, &act, NULL);
150*5331Samw 	(void) sigaction(SIGPIPE, &act, NULL);
151*5331Samw 
152*5331Samw 	(void) sigdelset(&set, SIGTERM);
153*5331Samw 	(void) sigdelset(&set, SIGHUP);
154*5331Samw 	(void) sigdelset(&set, SIGINT);
155*5331Samw 	(void) sigdelset(&set, SIGPIPE);
156*5331Samw 
157*5331Samw 	if (smbd.s_fg) {
158*5331Samw 		(void) sigdelset(&set, SIGTSTP);
159*5331Samw 		(void) sigdelset(&set, SIGTTIN);
160*5331Samw 		(void) sigdelset(&set, SIGTTOU);
161*5331Samw 
162*5331Samw 		if (smbd_service_init() != 0) {
163*5331Samw 			smbd_report("service initialization failed");
164*5331Samw 			exit(SMF_EXIT_ERR_FATAL);
165*5331Samw 		}
166*5331Samw 	} else {
167*5331Samw 		/*
168*5331Samw 		 * "pfd" is a pipe descriptor -- any fatal errors
169*5331Samw 		 * during subsequent initialization of the child
170*5331Samw 		 * process should be written to this pipe and the
171*5331Samw 		 * parent will report this error as the exit status.
172*5331Samw 		 */
173*5331Samw 		pfd = smbd_daemonize_init();
174*5331Samw 
175*5331Samw 		if (smbd_service_init() != 0) {
176*5331Samw 			smbd_report("daemon initialization failed");
177*5331Samw 			exit(SMF_EXIT_ERR_FATAL);
178*5331Samw 		}
179*5331Samw 
180*5331Samw 		smbd_daemonize_fini(pfd, SMF_EXIT_OK);
181*5331Samw 	}
182*5331Samw 
183*5331Samw 	(void) atexit(smbd_service_fini);
184*5331Samw 
185*5331Samw 	while (!smbd.s_shutdown_flag) {
186*5331Samw 		(void) sigsuspend(&set);
187*5331Samw 
188*5331Samw 		switch (smbd.s_sigval) {
189*5331Samw 		case 0:
190*5331Samw 			break;
191*5331Samw 
192*5331Samw 		case SIGPIPE:
193*5331Samw 			break;
194*5331Samw 
195*5331Samw 		case SIGHUP:
196*5331Samw 			/* Refresh config was triggered */
197*5331Samw 			if (smbd.s_fg)
198*5331Samw 				smbd_report("reconfiguration requested");
199*5331Samw 			(void) pthread_cond_signal(&refresh_cond);
200*5331Samw 			break;
201*5331Samw 
202*5331Samw 		default:
203*5331Samw 			/*
204*5331Samw 			 * Typically SIGINT or SIGTERM.
205*5331Samw 			 */
206*5331Samw 			smbd.s_shutdown_flag = 1;
207*5331Samw 			break;
208*5331Samw 		}
209*5331Samw 
210*5331Samw 		smbd.s_sigval = 0;
211*5331Samw 	}
212*5331Samw 
213*5331Samw 	smbd_service_fini();
214*5331Samw 	closelog();
215*5331Samw 	return (SMF_EXIT_OK);
216*5331Samw }
217*5331Samw 
218*5331Samw /*
219*5331Samw  * This function will fork off a child process,
220*5331Samw  * from which only the child will return.
221*5331Samw  *
222*5331Samw  * Use SMF error codes only on exit.
223*5331Samw  */
224*5331Samw static int
225*5331Samw smbd_daemonize_init(void)
226*5331Samw {
227*5331Samw 	int status, pfds[2];
228*5331Samw 	sigset_t set, oset;
229*5331Samw 	pid_t pid;
230*5331Samw 	int rc;
231*5331Samw 
232*5331Samw 	/*
233*5331Samw 	 * Reset privileges to the minimum set required. We continue
234*5331Samw 	 * to run as root to create and access files in /var.
235*5331Samw 	 */
236*5331Samw 	rc = __init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS,
237*5331Samw 	    smbd.s_uid, smbd.s_gid,
238*5331Samw 	    PRIV_NET_MAC_AWARE, PRIV_NET_PRIVADDR, PRIV_PROC_AUDIT,
239*5331Samw 	    PRIV_SYS_DEVICES, PRIV_SYS_SMB, NULL);
240*5331Samw 
241*5331Samw 	if (rc != 0) {
242*5331Samw 		smbd_report("insufficient privileges");
243*5331Samw 		exit(SMF_EXIT_ERR_FATAL);
244*5331Samw 	}
245*5331Samw 
246*5331Samw 	/*
247*5331Samw 	 * Block all signals prior to the fork and leave them blocked in the
248*5331Samw 	 * parent so we don't get in a situation where the parent gets SIGINT
249*5331Samw 	 * and returns non-zero exit status and the child is actually running.
250*5331Samw 	 * In the child, restore the signal mask once we've done our setsid().
251*5331Samw 	 */
252*5331Samw 	(void) sigfillset(&set);
253*5331Samw 	(void) sigdelset(&set, SIGABRT);
254*5331Samw 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
255*5331Samw 
256*5331Samw 	if (pipe(pfds) == -1) {
257*5331Samw 		smbd_report("unable to create pipe");
258*5331Samw 		exit(SMF_EXIT_ERR_FATAL);
259*5331Samw 	}
260*5331Samw 
261*5331Samw 	closelog();
262*5331Samw 
263*5331Samw 	if ((pid = fork()) == -1) {
264*5331Samw 		openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
265*5331Samw 		smbd_report("unable to fork");
266*5331Samw 		closelog();
267*5331Samw 		exit(SMF_EXIT_ERR_FATAL);
268*5331Samw 	}
269*5331Samw 
270*5331Samw 	/*
271*5331Samw 	 * If we're the parent process, wait for either the child to send us
272*5331Samw 	 * the appropriate exit status over the pipe or for the read to fail
273*5331Samw 	 * (presumably with 0 for EOF if our child terminated abnormally).
274*5331Samw 	 * If the read fails, exit with either the child's exit status if it
275*5331Samw 	 * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
276*5331Samw 	 */
277*5331Samw 	if (pid != 0) {
278*5331Samw 		(void) close(pfds[1]);
279*5331Samw 
280*5331Samw 		if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
281*5331Samw 			_exit(status);
282*5331Samw 
283*5331Samw 		if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
284*5331Samw 			_exit(WEXITSTATUS(status));
285*5331Samw 
286*5331Samw 		_exit(SMF_EXIT_ERR_FATAL);
287*5331Samw 	}
288*5331Samw 
289*5331Samw 	openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
290*5331Samw 	smbd.s_pid = getpid();
291*5331Samw 	(void) setsid();
292*5331Samw 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
293*5331Samw 	(void) chdir("/");
294*5331Samw 	(void) umask(022);
295*5331Samw 	(void) close(pfds[0]);
296*5331Samw 
297*5331Samw 	return (pfds[1]);
298*5331Samw }
299*5331Samw 
300*5331Samw static void
301*5331Samw smbd_daemonize_fini(int fd, int exit_status)
302*5331Samw {
303*5331Samw 	/*
304*5331Samw 	 * Now that we're running, if a pipe fd was specified, write an exit
305*5331Samw 	 * status to it to indicate that our parent process can safely detach.
306*5331Samw 	 * Then proceed to loading the remaining non-built-in modules.
307*5331Samw 	 */
308*5331Samw 	if (fd >= 0)
309*5331Samw 		(void) write(fd, &exit_status, sizeof (exit_status));
310*5331Samw 
311*5331Samw 	(void) close(fd);
312*5331Samw 
313*5331Samw 	if ((fd = open("/dev/null", O_RDWR)) >= 0) {
314*5331Samw 		(void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
315*5331Samw 		(void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
316*5331Samw 		(void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
317*5331Samw 		(void) close(fd);
318*5331Samw 	}
319*5331Samw 
320*5331Samw 	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
321*5331Samw 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL);
322*5331Samw }
323*5331Samw 
324*5331Samw static int
325*5331Samw smbd_service_init(void)
326*5331Samw {
327*5331Samw 	static char *dir[] = {
328*5331Samw 		SMB_DBDIR,		/* smbpasswd */
329*5331Samw 		SMB_CACHEDIR		/* KRB credential cache */
330*5331Samw 	};
331*5331Samw 
332*5331Samw 	int rc;
333*5331Samw 	int ddns_enabled;
334*5331Samw 	uint32_t mode;
335*5331Samw 	char resource_domain[SMB_PI_MAX_DOMAIN];
336*5331Samw 	int i;
337*5331Samw 
338*5331Samw 	smbd.s_drv_fd = -1;
339*5331Samw 
340*5331Samw 	for (i = 0; i < (sizeof (dir)/sizeof (dir[0])); ++i) {
341*5331Samw 		errno = 0;
342*5331Samw 
343*5331Samw 		if ((mkdir(dir[i], 0700) < 0) && (errno != EEXIST)) {
344*5331Samw 			smbd_report("mkdir %s: %s", dir[i], strerror(errno));
345*5331Samw 			return (1);
346*5331Samw 		}
347*5331Samw 	}
348*5331Samw 
349*5331Samw 	/*
350*5331Samw 	 * Set KRB5CCNAME (for the SMB credential cache) in the environment.
351*5331Samw 	 */
352*5331Samw 	if (putenv("KRB5CCNAME=" SMB_CACHEDIR "/ccache") != 0) {
353*5331Samw 		smbd_report("unable to set KRB5CCNAME");
354*5331Samw 		return (1);
355*5331Samw 	}
356*5331Samw 
357*5331Samw 	(void) oem_language_set("english");
358*5331Samw 
359*5331Samw 	if (!nt_builtin_init()) {
360*5331Samw 		smbd_report("out of memory");
361*5331Samw 		return (1);
362*5331Samw 	}
363*5331Samw 
364*5331Samw 	/*
365*5331Samw 	 * Need to load the configuration data prior to getting the
366*5331Samw 	 * interface information.
367*5331Samw 	 */
368*5331Samw 	if (smb_config_load() != 0) {
369*5331Samw 		smbd_report("failed to load configuration data");
370*5331Samw 		return (1);
371*5331Samw 	}
372*5331Samw 
373*5331Samw 	smb_resolver_init();
374*5331Samw 	(void) smb_nicmon_start();
375*5331Samw 
376*5331Samw 	smbrdr_init();
377*5331Samw 
378*5331Samw 	smb_netbios_start();
379*5331Samw 	if (smb_netlogon_init() != 0) {
380*5331Samw 		smbd_report("netlogon initialization failed");
381*5331Samw 		return (1);
382*5331Samw 	}
383*5331Samw 
384*5331Samw 	smb_config_rdlock();
385*5331Samw 	resource_domain[0] = '\0';
386*5331Samw 	(void) strlcpy(resource_domain,
387*5331Samw 	    smb_config_getstr(SMB_CI_DOMAIN_NAME), SMB_PI_MAX_DOMAIN);
388*5331Samw 	(void) utf8_strupr(resource_domain);
389*5331Samw 	smb_config_unlock();
390*5331Samw 
391*5331Samw 	mode = smb_get_security_mode();
392*5331Samw 
393*5331Samw 	if (mode == SMB_SECMODE_DOMAIN)
394*5331Samw 		(void) locate_resource_pdc(resource_domain);
395*5331Samw 
396*5331Samw 	/* Get the ID map client handle */
397*5331Samw 	if ((rc = smb_idmap_start()) != 0) {
398*5331Samw 		smbd_report("no idmap handle");
399*5331Samw 		return (rc);
400*5331Samw 	}
401*5331Samw 
402*5331Samw 	if ((rc = nt_domain_init(resource_domain, mode)) != 0) {
403*5331Samw 		if (rc == SMB_DOMAIN_NOMACHINE_SID)
404*5331Samw 			smbd_report("No Security Identifier (SID) has been "
405*5331Samw 			    "generated for this system.\n"
406*5331Samw 			    "Check idmap service configuration.");
407*5331Samw 
408*5331Samw 		if (rc == SMB_DOMAIN_NODOMAIN_SID) {
409*5331Samw 			/* Get the domain sid from domain controller */
410*5331Samw 			if ((rc = lsa_query_primary_domain_info()) != 0)
411*5331Samw 				smbd_report("Failed to get the Security "
412*5331Samw 				    "Identifier (SID) of domain %s",
413*5331Samw 				    resource_domain);
414*5331Samw 			}
415*5331Samw 		return (rc);
416*5331Samw 	}
417*5331Samw 
418*5331Samw 	if ((rc = mlsvc_init()) != 0) {
419*5331Samw 		smbd_report("msrpc initialization failed");
420*5331Samw 		return (rc);
421*5331Samw 	}
422*5331Samw 
423*5331Samw 	if (rc = smb_mlsvc_srv_start()) {
424*5331Samw 		smbd_report("msrpc door initialization failed: %d", rc);
425*5331Samw 		return (rc);
426*5331Samw 	}
427*5331Samw 
428*5331Samw 	if (smb_lmshrd_srv_start() != 0) {
429*5331Samw 		smbd_report("share initialization failed");
430*5331Samw 	}
431*5331Samw 
432*5331Samw 	/* XXX following will get removed */
433*5331Samw 	(void) smb_doorsrv_start();
434*5331Samw 	if ((rc = smb_door_srv_start()) != 0)
435*5331Samw 		return (rc);
436*5331Samw 
437*5331Samw 	if ((rc = smbd_refresh_init()) != 0)
438*5331Samw 		return (rc);
439*5331Samw 
440*5331Samw 	/* Call dyndns update - Just in case its configured to refresh DNS */
441*5331Samw 	smb_config_rdlock();
442*5331Samw 	ddns_enabled = smb_config_getyorn(SMB_CI_DYNDNS_ENABLE);
443*5331Samw 	smb_config_unlock();
444*5331Samw 	if (ddns_enabled) {
445*5331Samw 		(void) dyndns_update();
446*5331Samw 	}
447*5331Samw 
448*5331Samw 	if ((rc = smbd_kernel_bind()) != 0)
449*5331Samw 		smbd_report("kernel bind error: %s", strerror(errno));
450*5331Samw 
451*5331Samw 	(void) smbd_localtime_init();
452*5331Samw 
453*5331Samw 	return (lmshare_start());
454*5331Samw }
455*5331Samw 
456*5331Samw /*
457*5331Samw  * Close the kernel service and shutdown smbd services.
458*5331Samw  * This function is registered with atexit(): ensure that anything
459*5331Samw  * called from here is safe to be called multiple times.
460*5331Samw  */
461*5331Samw static void
462*5331Samw smbd_service_fini(void)
463*5331Samw {
464*5331Samw 	nt_builtin_fini();
465*5331Samw 	smbd_refresh_fini();
466*5331Samw 	smbd_kernel_unbind();
467*5331Samw 	smb_door_srv_stop();
468*5331Samw 	smb_doorsrv_stop();
469*5331Samw 	smb_lmshrd_srv_stop();
470*5331Samw 	lmshare_stop();
471*5331Samw 	smb_mlsvc_srv_stop();
472*5331Samw 	smb_nicmon_stop();
473*5331Samw 	smb_resolver_close();
474*5331Samw 	smb_idmap_stop();
475*5331Samw }
476*5331Samw 
477*5331Samw /*
478*5331Samw  * smbd_refresh_init()
479*5331Samw  *
480*5331Samw  * SMB service refresh thread initialization.  This thread waits for a
481*5331Samw  * refresh event and updates the daemon's view of the configuration
482*5331Samw  * before going back to sleep.
483*5331Samw  */
484*5331Samw static int
485*5331Samw smbd_refresh_init()
486*5331Samw {
487*5331Samw 	pthread_attr_t tattr;
488*5331Samw 	pthread_condattr_t cattr;
489*5331Samw 	int rc;
490*5331Samw 
491*5331Samw 	(void) pthread_condattr_init(&cattr);
492*5331Samw 	(void) pthread_cond_init(&refresh_cond, &cattr);
493*5331Samw 	(void) pthread_condattr_destroy(&cattr);
494*5331Samw 
495*5331Samw 	(void) pthread_mutex_init(&refresh_mutex, NULL);
496*5331Samw 
497*5331Samw 	(void) pthread_attr_init(&tattr);
498*5331Samw 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
499*5331Samw 	rc = pthread_create(&refresh_thr, &tattr, smbd_refresh_monitor, 0);
500*5331Samw 	(void) pthread_attr_destroy(&tattr);
501*5331Samw 	return (rc);
502*5331Samw 
503*5331Samw }
504*5331Samw 
505*5331Samw /*
506*5331Samw  * smbd_refresh_fini()
507*5331Samw  *
508*5331Samw  * Stop the refresh thread.
509*5331Samw  */
510*5331Samw static void
511*5331Samw smbd_refresh_fini()
512*5331Samw {
513*5331Samw 	(void) pthread_cancel(refresh_thr);
514*5331Samw 
515*5331Samw 	(void) pthread_cond_destroy(&refresh_cond);
516*5331Samw 	(void) pthread_mutex_destroy(&refresh_mutex);
517*5331Samw }
518*5331Samw 
519*5331Samw /*
520*5331Samw  * smbd_refresh_monitor()
521*5331Samw  *
522*5331Samw  * Wait for a refresh event. When this thread wakes up, update the
523*5331Samw  * smbd configuration from the SMF config information then go back to
524*5331Samw  * wait for the next refresh.
525*5331Samw  */
526*5331Samw /*ARGSUSED*/
527*5331Samw static void *
528*5331Samw smbd_refresh_monitor(void *arg)
529*5331Samw {
530*5331Samw 	int dummy = 0;
531*5331Samw 
532*5331Samw 	(void) pthread_mutex_lock(&refresh_mutex);
533*5331Samw 	while (pthread_cond_wait(&refresh_cond, &refresh_mutex) == 0) {
534*5331Samw 		/*
535*5331Samw 		 * We've been woken up by a refresh event so go do
536*5331Samw 		 * what is necessary.
537*5331Samw 		 */
538*5331Samw 		(void) smb_config_load();
539*5331Samw 		smb_nic_build_info();
540*5331Samw 		(void) smb_netbios_name_reconfig();
541*5331Samw 		(void) smb_browser_config();
542*5331Samw 		if (ioctl(smbd.s_drv_fd, SMB_IOC_CONFIG_REFRESH, &dummy) < 0) {
543*5331Samw 			smbd_report("configuration update ioctl: %s",
544*5331Samw 			    strerror(errno));
545*5331Samw 		}
546*5331Samw 	}
547*5331Samw 	return (NULL);
548*5331Samw }
549*5331Samw 
550*5331Samw 
551*5331Samw /*
552*5331Samw  * If the door has already been opened by another process (non-zero pid
553*5331Samw  * in target), we assume that another smbd is already running.  If there
554*5331Samw  * is a race here, it will be caught later when smbsrv is opened because
555*5331Samw  * only one process is allowed to open the device at a time.
556*5331Samw  */
557*5331Samw static int
558*5331Samw smbd_already_running(void)
559*5331Samw {
560*5331Samw 	door_info_t info;
561*5331Samw 	int door;
562*5331Samw 
563*5331Samw 	if ((door = open(SMBD_DOOR_NAME, O_RDONLY)) < 0)
564*5331Samw 		return (0);
565*5331Samw 
566*5331Samw 	if (door_info(door, &info) < 0)
567*5331Samw 		return (0);
568*5331Samw 
569*5331Samw 	if (info.di_target > 0) {
570*5331Samw 		smbd_report("already running: pid %ld\n", info.di_target);
571*5331Samw 		(void) close(door);
572*5331Samw 		return (1);
573*5331Samw 	}
574*5331Samw 
575*5331Samw 	(void) close(door);
576*5331Samw 	return (0);
577*5331Samw }
578*5331Samw 
579*5331Samw static int
580*5331Samw smbd_kernel_bind(void)
581*5331Samw {
582*5331Samw 	if (smbd.s_drv_fd != -1)
583*5331Samw 		(void) close(smbd.s_drv_fd);
584*5331Samw 
585*5331Samw 	if ((smbd.s_drv_fd = open(DRV_DEVICE_PATH, 0)) < 0) {
586*5331Samw 		smbd.s_drv_fd = -1;
587*5331Samw 		return (1);
588*5331Samw 	}
589*5331Samw 	return (0);
590*5331Samw }
591*5331Samw 
592*5331Samw 
593*5331Samw /*
594*5331Samw  * Initialization of the localtime thread.
595*5331Samw  * Returns 0 on success, an error number if thread creation fails.
596*5331Samw  */
597*5331Samw 
598*5331Samw int
599*5331Samw smbd_localtime_init(void)
600*5331Samw {
601*5331Samw 	pthread_attr_t tattr;
602*5331Samw 	int rc;
603*5331Samw 
604*5331Samw 	(void) pthread_attr_init(&tattr);
605*5331Samw 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
606*5331Samw 	rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0);
607*5331Samw 	(void) pthread_attr_destroy(&tattr);
608*5331Samw 	return (rc);
609*5331Samw }
610*5331Samw 
611*5331Samw /*
612*5331Samw  * Local time thread to kernel land.
613*5331Samw  * Send local gmtoff to kernel module one time at startup
614*5331Samw  * and each time it changes (up to twice a year).
615*5331Samw  * Local gmtoff is checked once every 15 minutes and
616*5331Samw  * since some timezones are aligned on half and qtr hour boundaries,
617*5331Samw  * once an hour would likely suffice.
618*5331Samw  */
619*5331Samw 
620*5331Samw /*ARGSUSED*/
621*5331Samw static void *
622*5331Samw smbd_localtime_monitor(void *arg)
623*5331Samw {
624*5331Samw 	struct tm local_tm;
625*5331Samw 	time_t secs, gmtoff;
626*5331Samw 	time_t last_gmtoff = -1;
627*5331Samw 	int timeout;
628*5331Samw 
629*5331Samw 	for (;;) {
630*5331Samw 		gmtoff = -altzone;
631*5331Samw 
632*5331Samw 		if ((last_gmtoff != gmtoff) && (smbd.s_drv_fd != -1)) {
633*5331Samw 			if (ioctl(smbd.s_drv_fd, SMB_IOC_GMTOFF, &gmtoff) < 0) {
634*5331Samw 				smbd_report("localtime ioctl: %s",
635*5331Samw 				    strerror(errno));
636*5331Samw 			}
637*5331Samw 		}
638*5331Samw 
639*5331Samw 		/*
640*5331Samw 		 * Align the next iteration on a fifteen minute boundary.
641*5331Samw 		 */
642*5331Samw 		secs = time(0);
643*5331Samw 		(void) localtime_r(&secs, &local_tm);
644*5331Samw 		timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN);
645*5331Samw 		(void) sleep(timeout);
646*5331Samw 
647*5331Samw 		last_gmtoff = gmtoff;
648*5331Samw 	}
649*5331Samw 
650*5331Samw 	/*NOTREACHED*/
651*5331Samw 	return (NULL);
652*5331Samw }
653*5331Samw 
654*5331Samw 
655*5331Samw static void
656*5331Samw smbd_kernel_unbind(void)
657*5331Samw {
658*5331Samw 	if (smbd.s_drv_fd != -1) {
659*5331Samw 		(void) close(smbd.s_drv_fd);
660*5331Samw 		smbd.s_drv_fd = -1;
661*5331Samw 	}
662*5331Samw }
663*5331Samw 
664*5331Samw static void
665*5331Samw smbd_sig_handler(int sigval)
666*5331Samw {
667*5331Samw 	if (smbd.s_sigval == 0)
668*5331Samw 		smbd.s_sigval = sigval;
669*5331Samw }
670*5331Samw 
671*5331Samw /*
672*5331Samw  * Set up configuration options and parse the command line.
673*5331Samw  * This function will determine if we will run as a daemon
674*5331Samw  * or in the foreground.
675*5331Samw  *
676*5331Samw  * Failure to find a uid or gid results in using the default (0).
677*5331Samw  */
678*5331Samw static int
679*5331Samw smbd_setup_options(int argc, char *argv[])
680*5331Samw {
681*5331Samw 	struct passwd *pwd;
682*5331Samw 	struct group *grp;
683*5331Samw 	int c;
684*5331Samw 
685*5331Samw 	if ((pwd = getpwnam("root")) != NULL)
686*5331Samw 		smbd.s_uid = pwd->pw_uid;
687*5331Samw 
688*5331Samw 	if ((grp = getgrnam("sys")) != NULL)
689*5331Samw 		smbd.s_gid = grp->gr_gid;
690*5331Samw 
691*5331Samw 	smbd.s_fg = smb_get_fg_flag();
692*5331Samw 
693*5331Samw 	while ((c = getopt(argc, argv, ":f")) != -1) {
694*5331Samw 		switch (c) {
695*5331Samw 		case 'f':
696*5331Samw 			smbd.s_fg = 1;
697*5331Samw 			break;
698*5331Samw 
699*5331Samw 		case ':':
700*5331Samw 		case '?':
701*5331Samw 		default:
702*5331Samw 			smbd_usage(stderr);
703*5331Samw 			return (-1);
704*5331Samw 		}
705*5331Samw 	}
706*5331Samw 
707*5331Samw 	return (0);
708*5331Samw }
709*5331Samw 
710*5331Samw static void
711*5331Samw smbd_usage(FILE *fp)
712*5331Samw {
713*5331Samw 	static char *help[] = {
714*5331Samw 		"-f  run program in foreground"
715*5331Samw 	};
716*5331Samw 
717*5331Samw 	int i;
718*5331Samw 
719*5331Samw 	(void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname);
720*5331Samw 
721*5331Samw 	for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i)
722*5331Samw 		(void) fprintf(fp, "    %s\n", help[i]);
723*5331Samw }
724*5331Samw 
725*5331Samw static void
726*5331Samw smbd_report(const char *fmt, ...)
727*5331Samw {
728*5331Samw 	char buf[128];
729*5331Samw 	va_list ap;
730*5331Samw 
731*5331Samw 	if (fmt == NULL)
732*5331Samw 		return;
733*5331Samw 
734*5331Samw 	va_start(ap, fmt);
735*5331Samw 	(void) vsnprintf(buf, 128, fmt, ap);
736*5331Samw 	va_end(ap);
737*5331Samw 
738*5331Samw 	(void) fprintf(stderr, "smbd: %s\n", buf);
739*5331Samw }
740*5331Samw 
741*5331Samw /*
742*5331Samw  * Enable libumem debugging by default on DEBUG builds.
743*5331Samw  */
744*5331Samw #ifdef DEBUG
745*5331Samw /* LINTED - external libumem symbol */
746*5331Samw const char *
747*5331Samw _umem_debug_init(void)
748*5331Samw {
749*5331Samw 	return ("default,verbose"); /* $UMEM_DEBUG setting */
750*5331Samw }
751*5331Samw 
752*5331Samw /* LINTED - external libumem symbol */
753*5331Samw const char *
754*5331Samw _umem_logging_init(void)
755*5331Samw {
756*5331Samw 	return ("fail,contents"); /* $UMEM_LOGGING setting */
757*5331Samw }
758*5331Samw #endif
759