xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_main.c (revision 051aabe6136ff13e81542a427e9693ffe1503525)
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 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/ioccom.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <stdarg.h>
37 #include <fcntl.h>
38 #include <wait.h>
39 #include <signal.h>
40 #include <libscf.h>
41 #include <limits.h>
42 #include <priv_utils.h>
43 #include <door.h>
44 #include <errno.h>
45 #include <syslog.h>
46 #include <pthread.h>
47 #include <time.h>
48 #include <libscf.h>
49 #include <zone.h>
50 #include <tzfile.h>
51 #include <libgen.h>
52 #include <pwd.h>
53 #include <grp.h>
54 
55 #include <smbsrv/smb_door_svc.h>
56 #include <smbsrv/smb_ioctl.h>
57 #include <smbsrv/libsmb.h>
58 #include <smbsrv/libsmbns.h>
59 #include <smbsrv/libsmbrdr.h>
60 #include <smbsrv/libmlsvc.h>
61 
62 #include "smbd.h"
63 
64 #define	DRV_DEVICE_PATH	"/devices/pseudo/smbsrv@0:smbsrv"
65 #define	SMB_DBDIR "/var/smb"
66 
67 extern void *smbd_nbt_listener(void *);
68 extern void *smbd_tcp_listener(void *);
69 
70 static int smbd_daemonize_init(void);
71 static void smbd_daemonize_fini(int, int);
72 
73 static int smbd_kernel_bind(void);
74 static void smbd_kernel_unbind(void);
75 static int smbd_already_running(void);
76 
77 static int smbd_service_init(void);
78 static void smbd_service_fini(void);
79 
80 static int smbd_setup_options(int argc, char *argv[]);
81 static void smbd_usage(FILE *fp);
82 static void smbd_report(const char *fmt, ...);
83 
84 static void smbd_sig_handler(int sig);
85 
86 static int smbd_localtime_init(void);
87 static void *smbd_localtime_monitor(void *arg);
88 
89 static pthread_t localtime_thr;
90 
91 static int smbd_refresh_init(void);
92 static void smbd_refresh_fini(void);
93 static void *smbd_refresh_monitor(void *);
94 static pthread_t nbt_listener;
95 static pthread_t tcp_listener;
96 static pthread_t refresh_thr;
97 static pthread_cond_t refresh_cond;
98 static pthread_mutex_t refresh_mutex;
99 
100 smbd_t smbd;
101 
102 /*
103  * smbd user land daemon
104  *
105  * Use SMF error codes only on return or exit.
106  */
107 int
108 main(int argc, char *argv[])
109 {
110 	struct sigaction	act;
111 	sigset_t		set;
112 	uid_t			uid;
113 	int			pfd = -1;
114 	int			sigval;
115 
116 	smbd.s_pname = basename(argv[0]);
117 	openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
118 
119 	if (smbd_setup_options(argc, argv) != 0)
120 		return (SMF_EXIT_ERR_FATAL);
121 
122 	if ((uid = getuid()) != smbd.s_uid) {
123 		smbd_report("user %d: %s", uid, strerror(EPERM));
124 		return (SMF_EXIT_ERR_FATAL);
125 	}
126 
127 	if (getzoneid() != GLOBAL_ZONEID) {
128 		smbd_report("non-global zones are not supported");
129 		return (SMF_EXIT_ERR_FATAL);
130 	}
131 
132 	if (is_system_labeled()) {
133 		smbd_report("Trusted Extensions not supported");
134 		return (SMF_EXIT_ERR_FATAL);
135 	}
136 
137 	if (smbd_already_running())
138 		return (SMF_EXIT_OK);
139 
140 	(void) sigfillset(&set);
141 	(void) sigdelset(&set, SIGABRT);
142 
143 	(void) sigfillset(&act.sa_mask);
144 	act.sa_handler = smbd_sig_handler;
145 	act.sa_flags = 0;
146 
147 	(void) sigaction(SIGTERM, &act, NULL);
148 	(void) sigaction(SIGHUP, &act, NULL);
149 	(void) sigaction(SIGINT, &act, NULL);
150 	(void) sigaction(SIGPIPE, &act, NULL);
151 
152 	(void) sigdelset(&set, SIGTERM);
153 	(void) sigdelset(&set, SIGHUP);
154 	(void) sigdelset(&set, SIGINT);
155 	(void) sigdelset(&set, SIGPIPE);
156 
157 	if (smbd.s_fg) {
158 		(void) sigdelset(&set, SIGTSTP);
159 		(void) sigdelset(&set, SIGTTIN);
160 		(void) sigdelset(&set, SIGTTOU);
161 
162 		if (smbd_service_init() != 0) {
163 			smbd_report("service initialization failed");
164 			exit(SMF_EXIT_ERR_FATAL);
165 		}
166 	} else {
167 		/*
168 		 * "pfd" is a pipe descriptor -- any fatal errors
169 		 * during subsequent initialization of the child
170 		 * process should be written to this pipe and the
171 		 * parent will report this error as the exit status.
172 		 */
173 		pfd = smbd_daemonize_init();
174 
175 		if (smbd_service_init() != 0) {
176 			smbd_report("daemon initialization failed");
177 			exit(SMF_EXIT_ERR_FATAL);
178 		}
179 
180 		smbd_daemonize_fini(pfd, SMF_EXIT_OK);
181 	}
182 
183 	(void) atexit(smbd_service_fini);
184 
185 	while (!smbd.s_shutdown_flag) {
186 		if (smbd.s_sigval == 0)
187 			(void) sigsuspend(&set);
188 
189 		sigval = smbd.s_sigval;
190 		smbd.s_sigval = 0;
191 
192 		switch (sigval) {
193 		case 0:
194 		case SIGPIPE:
195 			break;
196 
197 		case SIGHUP:
198 			/* Refresh config was triggered */
199 			if (smbd.s_fg)
200 				smbd_report("reconfiguration requested");
201 			(void) pthread_cond_signal(&refresh_cond);
202 			break;
203 
204 		default:
205 			/*
206 			 * Typically SIGINT or SIGTERM.
207 			 */
208 			smbd.s_shutdown_flag = 1;
209 			break;
210 		}
211 	}
212 
213 	smbd_service_fini();
214 	closelog();
215 	return (SMF_EXIT_OK);
216 }
217 
218 /*
219  * This function will fork off a child process,
220  * from which only the child will return.
221  *
222  * Use SMF error codes only on exit.
223  */
224 static int
225 smbd_daemonize_init(void)
226 {
227 	int status, pfds[2];
228 	sigset_t set, oset;
229 	pid_t pid;
230 	int rc;
231 
232 	/*
233 	 * Reset privileges to the minimum set required. We continue
234 	 * to run as root to create and access files in /var.
235 	 */
236 	rc = __init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS,
237 	    smbd.s_uid, smbd.s_gid,
238 	    PRIV_NET_MAC_AWARE, PRIV_NET_PRIVADDR, PRIV_PROC_AUDIT,
239 	    PRIV_SYS_DEVICES, PRIV_SYS_SMB, NULL);
240 
241 	if (rc != 0) {
242 		smbd_report("insufficient privileges");
243 		exit(SMF_EXIT_ERR_FATAL);
244 	}
245 
246 	/*
247 	 * Block all signals prior to the fork and leave them blocked in the
248 	 * parent so we don't get in a situation where the parent gets SIGINT
249 	 * and returns non-zero exit status and the child is actually running.
250 	 * In the child, restore the signal mask once we've done our setsid().
251 	 */
252 	(void) sigfillset(&set);
253 	(void) sigdelset(&set, SIGABRT);
254 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
255 
256 	if (pipe(pfds) == -1) {
257 		smbd_report("unable to create pipe");
258 		exit(SMF_EXIT_ERR_FATAL);
259 	}
260 
261 	closelog();
262 
263 	if ((pid = fork()) == -1) {
264 		openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
265 		smbd_report("unable to fork");
266 		closelog();
267 		exit(SMF_EXIT_ERR_FATAL);
268 	}
269 
270 	/*
271 	 * If we're the parent process, wait for either the child to send us
272 	 * the appropriate exit status over the pipe or for the read to fail
273 	 * (presumably with 0 for EOF if our child terminated abnormally).
274 	 * If the read fails, exit with either the child's exit status if it
275 	 * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
276 	 */
277 	if (pid != 0) {
278 		(void) close(pfds[1]);
279 
280 		if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
281 			_exit(status);
282 
283 		if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
284 			_exit(WEXITSTATUS(status));
285 
286 		_exit(SMF_EXIT_ERR_FATAL);
287 	}
288 
289 	openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
290 	smbd.s_pid = getpid();
291 	(void) setsid();
292 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
293 	(void) chdir("/");
294 	(void) umask(022);
295 	(void) close(pfds[0]);
296 
297 	return (pfds[1]);
298 }
299 
300 static void
301 smbd_daemonize_fini(int fd, int exit_status)
302 {
303 	/*
304 	 * Now that we're running, if a pipe fd was specified, write an exit
305 	 * status to it to indicate that our parent process can safely detach.
306 	 * Then proceed to loading the remaining non-built-in modules.
307 	 */
308 	if (fd >= 0)
309 		(void) write(fd, &exit_status, sizeof (exit_status));
310 
311 	(void) close(fd);
312 
313 	if ((fd = open("/dev/null", O_RDWR)) >= 0) {
314 		(void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
315 		(void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
316 		(void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
317 		(void) close(fd);
318 	}
319 
320 	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
321 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL);
322 }
323 
324 /*
325  * smbd_service_init
326  */
327 static int
328 smbd_service_init(void)
329 {
330 	int	rc;
331 	char	resource_domain[SMB_PI_MAX_DOMAIN];
332 	char	fqdn[MAXHOSTNAMELEN];
333 
334 	smbd.s_drv_fd = -1;
335 
336 	if ((mkdir(SMB_DBDIR, 0700) < 0) && (errno != EEXIST)) {
337 		smbd_report("mkdir %s: %s", SMB_DBDIR, strerror(errno));
338 		return (1);
339 	}
340 
341 	if ((rc = smb_ccache_init(SMB_VARRUN_DIR, SMB_CCACHE_FILE)) != 0) {
342 		if (rc == -1)
343 			smbd_report("mkdir %s: %s", SMB_VARRUN_DIR,
344 			    strerror(errno));
345 		else
346 			smbd_report("unable to set KRB5CCNAME");
347 		return (1);
348 	}
349 
350 
351 	(void) oem_language_set("english");
352 
353 	if (!smb_wka_init()) {
354 		smbd_report("out of memory");
355 		return (1);
356 	}
357 
358 	if (smb_nicmon_start(SMBD_DEFAULT_INSTANCE_FMRI) != 0)
359 		smbd_report("NIC monitoring failed to start");
360 
361 	if (dns_msgid_init() != 0) {
362 		smbd_report("DNS message id initialization failed");
363 		return (1);
364 	}
365 
366 	smbrdr_init();
367 
368 	if (smb_netbios_start() != 0)
369 		smbd_report("NetBIOS services failed to start");
370 	else
371 		smbd_report("NetBIOS services started");
372 
373 	if (smb_netlogon_init() != 0) {
374 		smbd_report("netlogon initialization failed");
375 		return (1);
376 	}
377 
378 	(void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
379 	(void) utf8_strupr(resource_domain);
380 
381 	/* Get the ID map client handle */
382 	if ((rc = smb_idmap_start()) != 0) {
383 		smbd_report("no idmap handle");
384 		return (rc);
385 	}
386 
387 	smbd.s_secmode = smb_config_get_secmode();
388 	if ((rc = nt_domain_init(resource_domain, smbd.s_secmode)) != 0) {
389 		if (rc == SMB_DOMAIN_NOMACHINE_SID) {
390 			smbd_report(
391 			    "no machine SID: check idmap configuration");
392 			return (rc);
393 		}
394 	}
395 
396 	smb_ads_init();
397 	if ((rc = mlsvc_init()) != 0) {
398 		smbd_report("msrpc initialization failed");
399 		return (rc);
400 	}
401 
402 	if (smbd.s_secmode == SMB_SECMODE_DOMAIN) {
403 		if (!smb_match_netlogon_seqnum())
404 			smb_set_netlogon_cred();
405 		else
406 			(void) smbd_locate_dc(resource_domain, "");
407 
408 		(void) lsa_query_primary_domain_info();
409 	}
410 
411 	smbd.s_door_lmshr = smb_share_dsrv_start();
412 	if (smbd.s_door_lmshr < 0) {
413 		smbd_report("share initialization failed");
414 	}
415 
416 	smbd.s_door_srv = smb_door_srv_start();
417 	if (smbd.s_door_srv < 0)
418 		return (rc);
419 
420 	if ((rc = smbd_refresh_init()) != 0)
421 		return (rc);
422 
423 	if (smb_getfqdomainname(fqdn, MAXHOSTNAMELEN) == 0)
424 		(void) dyndns_update_core(fqdn);
425 
426 	(void) smbd_localtime_init();
427 
428 	smbd.s_door_opipe = smbd_opipe_dsrv_start();
429 	if (smbd.s_door_opipe < 0) {
430 		smbd_report("opipe initialization failed %s",
431 		    strerror(errno));
432 		return (rc);
433 	}
434 
435 	(void) smb_lgrp_start();
436 
437 	smb_pwd_init(B_TRUE);
438 
439 	rc = smbd_kernel_bind();
440 	if (rc != 0) {
441 		smbd_report("kernel bind error: %s", strerror(errno));
442 		return (rc);
443 	}
444 
445 	return (smb_shr_start());
446 }
447 
448 /*
449  * Close the kernel service and shutdown smbd services.
450  * This function is registered with atexit(): ensure that anything
451  * called from here is safe to be called multiple times.
452  */
453 static void
454 smbd_service_fini(void)
455 {
456 	smbd_opipe_dsrv_stop();
457 	smb_wka_fini();
458 	smbd_refresh_fini();
459 	smbd_kernel_unbind();
460 	smb_door_srv_stop();
461 	smb_share_dsrv_stop();
462 	smb_shr_stop();
463 	smb_nicmon_stop();
464 	smb_idmap_stop();
465 	smb_lgrp_stop();
466 	smb_ccache_remove(SMB_CCACHE_PATH);
467 	smb_pwd_fini();
468 
469 }
470 
471 
472 /*
473  * smbd_refresh_init()
474  *
475  * SMB service refresh thread initialization.  This thread waits for a
476  * refresh event and updates the daemon's view of the configuration
477  * before going back to sleep.
478  */
479 static int
480 smbd_refresh_init()
481 {
482 	pthread_attr_t		tattr;
483 	pthread_condattr_t	cattr;
484 	int			rc;
485 
486 	(void) pthread_condattr_init(&cattr);
487 	(void) pthread_cond_init(&refresh_cond, &cattr);
488 	(void) pthread_condattr_destroy(&cattr);
489 
490 	(void) pthread_mutex_init(&refresh_mutex, NULL);
491 
492 	(void) pthread_attr_init(&tattr);
493 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
494 	rc = pthread_create(&refresh_thr, &tattr, smbd_refresh_monitor, 0);
495 	(void) pthread_attr_destroy(&tattr);
496 
497 	return (rc);
498 }
499 
500 /*
501  * smbd_refresh_fini()
502  *
503  * Stop the refresh thread.
504  */
505 static void
506 smbd_refresh_fini()
507 {
508 	(void) pthread_cancel(refresh_thr);
509 
510 	(void) pthread_cond_destroy(&refresh_cond);
511 	(void) pthread_mutex_destroy(&refresh_mutex);
512 }
513 
514 /*
515  * smbd_refresh_monitor()
516  *
517  * Wait for a refresh event. When this thread wakes up, update the
518  * smbd configuration from the SMF config information then go back to
519  * wait for the next refresh.
520  */
521 /*ARGSUSED*/
522 static void *
523 smbd_refresh_monitor(void *arg)
524 {
525 	smb_io_t	smb_io;
526 	size_t		len;
527 	char		*new_dom;
528 	int		new_secmod;
529 	char		*old_dom;
530 	char		fqdn[MAXHOSTNAMELEN];
531 	int		rc = 0;
532 
533 	bzero(&smb_io, sizeof (smb_io));
534 	smb_io.sio_version = SMB_IOC_VERSION;
535 
536 	(void) pthread_mutex_lock(&refresh_mutex);
537 	while (pthread_cond_wait(&refresh_cond, &refresh_mutex) == 0) {
538 		/*
539 		 * We've been woken up by a refresh event so go do
540 		 * what is necessary.
541 		 */
542 		smb_ads_refresh();
543 		smb_ccache_remove(SMB_CCACHE_PATH);
544 
545 		if ((rc = smb_getfqdomainname(fqdn, MAXHOSTNAMELEN)) != 0)
546 			smbd_report("failed to get fully qualified domainname");
547 
548 		if (rc == 0)
549 			/* Clear rev zone before creating if list */
550 			if (dyndns_clear_rev_zone(fqdn) != 0)
551 				smbd_report("failed to clear DNS reverse "
552 				    "lookup zone");
553 
554 		/* re-initialize NIC table */
555 		if (smb_nic_init() != 0)
556 			smbd_report("failed to get NIC information");
557 
558 		smb_netbios_name_reconfig();
559 		smb_browser_reconfig();
560 
561 		if (rc == 0)
562 			if (dyndns_update_core(fqdn) != 0)
563 				smbd_report("failed to update dynamic DNS");
564 
565 		smb_set_netlogon_cred();
566 
567 		smb_load_kconfig(&smb_io.sio_data.cfg);
568 		new_dom = smb_io.sio_data.cfg.skc_resource_domain;
569 		old_dom = smbd.s_kcfg.skc_resource_domain;
570 		len = strlen(old_dom);
571 		new_secmod = smb_config_get_secmode();
572 		if ((len != strlen(new_dom)) ||
573 		    (strncasecmp(new_dom, old_dom, len)) ||
574 		    (new_secmod != smbd.s_secmode) ||
575 		    (smbd.s_drv_fd == -1)) {
576 			/*
577 			 * The active sessions have to be disconnected.
578 			 */
579 			smbd_kernel_unbind();
580 			if (smbd_kernel_bind()) {
581 				smbd_report("kernel bind error: %s",
582 				    strerror(errno));
583 			}
584 			continue;
585 		}
586 
587 		bcopy(&smb_io.sio_data.cfg, &smbd.s_kcfg, sizeof (smbd.s_kcfg));
588 		if (ioctl(smbd.s_drv_fd, SMB_IOC_CONFIG, &smb_io) < 0) {
589 			smbd_report("configuration update ioctl: %s",
590 			    strerror(errno));
591 		}
592 	}
593 	return (NULL);
594 }
595 
596 
597 /*
598  * If the door has already been opened by another process (non-zero pid
599  * in target), we assume that another smbd is already running.  If there
600  * is a race here, it will be caught later when smbsrv is opened because
601  * only one process is allowed to open the device at a time.
602  */
603 static int
604 smbd_already_running(void)
605 {
606 	door_info_t info;
607 	int door;
608 
609 	if ((door = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0)
610 		return (0);
611 
612 	if (door_info(door, &info) < 0)
613 		return (0);
614 
615 	if (info.di_target > 0) {
616 		smbd_report("already running: pid %ld\n", info.di_target);
617 		(void) close(door);
618 		return (1);
619 	}
620 
621 	(void) close(door);
622 	return (0);
623 }
624 
625 /*
626  * smbd_kernel_bind
627  *
628  * This function open the smbsrv device and start the kernel service.
629  */
630 static int
631 smbd_kernel_bind(void)
632 {
633 	smb_io_t	smb_io;
634 	int		rc;
635 
636 	bzero(&smb_io, sizeof (smb_io));
637 	smb_io.sio_version = SMB_IOC_VERSION;
638 
639 	if (smbd.s_drv_fd != -1)
640 		(void) close(smbd.s_drv_fd);
641 
642 	if ((smbd.s_drv_fd = open(DRV_DEVICE_PATH, 0)) < 0) {
643 		smbd.s_drv_fd = -1;
644 		return (errno);
645 	}
646 	smb_load_kconfig(&smbd.s_kcfg);
647 	bcopy(&smbd.s_kcfg, &smb_io.sio_data.cfg, sizeof (smb_io.sio_data.cfg));
648 	if (ioctl(smbd.s_drv_fd, SMB_IOC_CONFIG, &smb_io) < 0) {
649 		(void) close(smbd.s_drv_fd);
650 		smbd.s_drv_fd = -1;
651 		return (errno);
652 	}
653 	smb_io.sio_data.gmtoff = (uint32_t)(-altzone);
654 	if (ioctl(smbd.s_drv_fd, SMB_IOC_GMTOFF, &smb_io) < 0) {
655 		(void) close(smbd.s_drv_fd);
656 		smbd.s_drv_fd = -1;
657 		return (errno);
658 	}
659 	smb_io.sio_data.start.opipe = smbd.s_door_opipe;
660 	smb_io.sio_data.start.lmshrd = smbd.s_door_lmshr;
661 	smb_io.sio_data.start.udoor = smbd.s_door_srv;
662 	if (ioctl(smbd.s_drv_fd, SMB_IOC_START, &smb_io) < 0) {
663 		(void) close(smbd.s_drv_fd);
664 		smbd.s_drv_fd = -1;
665 		return (errno);
666 	}
667 
668 	rc = pthread_create(&nbt_listener, NULL, smbd_nbt_listener, NULL);
669 	if (rc == 0) {
670 		rc = pthread_create(&tcp_listener, NULL, smbd_tcp_listener,
671 		    NULL);
672 		if (rc == 0) {
673 			smbd.s_kbound = B_TRUE;
674 			return (0);
675 		}
676 	}
677 
678 	rc = pthread_create(&nbt_listener, NULL, smbd_nbt_listener, NULL);
679 	if (rc == 0) {
680 		rc = pthread_create(&tcp_listener, NULL, smbd_tcp_listener,
681 		    NULL);
682 		if (rc == 0) {
683 			smbd.s_kbound = B_TRUE;
684 			return (0);
685 		}
686 	}
687 	(void) close(smbd.s_drv_fd);
688 	smbd.s_drv_fd = -1;
689 	return (rc);
690 }
691 
692 /*
693  * smbd_kernel_unbind
694  */
695 static void
696 smbd_kernel_unbind(void)
697 {
698 	if (smbd.s_drv_fd != -1) {
699 		(void) close(smbd.s_drv_fd);
700 		smbd.s_drv_fd = -1;
701 		smbd.s_kbound = B_FALSE;
702 	}
703 }
704 
705 /*
706  * Initialization of the localtime thread.
707  * Returns 0 on success, an error number if thread creation fails.
708  */
709 
710 int
711 smbd_localtime_init(void)
712 {
713 	pthread_attr_t tattr;
714 	int rc;
715 
716 	(void) pthread_attr_init(&tattr);
717 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
718 	rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0);
719 	(void) pthread_attr_destroy(&tattr);
720 	return (rc);
721 }
722 
723 /*
724  * Local time thread to kernel land.
725  * Send local gmtoff to kernel module one time at startup
726  * and each time it changes (up to twice a year).
727  * Local gmtoff is checked once every 15 minutes and
728  * since some timezones are aligned on half and qtr hour boundaries,
729  * once an hour would likely suffice.
730  */
731 
732 /*ARGSUSED*/
733 static void *
734 smbd_localtime_monitor(void *arg)
735 {
736 	struct tm local_tm;
737 	time_t secs, gmtoff;
738 	time_t last_gmtoff = -1;
739 	int timeout;
740 
741 	for (;;) {
742 		gmtoff = -altzone;
743 
744 		if ((last_gmtoff != gmtoff) && (smbd.s_drv_fd != -1)) {
745 			if (ioctl(smbd.s_drv_fd, SMB_IOC_GMTOFF, &gmtoff) < 0) {
746 				smbd_report("localtime ioctl: %s",
747 				    strerror(errno));
748 			}
749 		}
750 
751 		/*
752 		 * Align the next iteration on a fifteen minute boundary.
753 		 */
754 		secs = time(0);
755 		(void) localtime_r(&secs, &local_tm);
756 		timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN);
757 		(void) sleep(timeout);
758 
759 		last_gmtoff = gmtoff;
760 	}
761 
762 	/*NOTREACHED*/
763 	return (NULL);
764 }
765 
766 static void
767 smbd_sig_handler(int sigval)
768 {
769 	if (smbd.s_sigval == 0)
770 		smbd.s_sigval = sigval;
771 }
772 
773 /*
774  * Set up configuration options and parse the command line.
775  * This function will determine if we will run as a daemon
776  * or in the foreground.
777  *
778  * Failure to find a uid or gid results in using the default (0).
779  */
780 static int
781 smbd_setup_options(int argc, char *argv[])
782 {
783 	struct passwd *pwd;
784 	struct group *grp;
785 	int c;
786 
787 	if ((pwd = getpwnam("root")) != NULL)
788 		smbd.s_uid = pwd->pw_uid;
789 
790 	if ((grp = getgrnam("sys")) != NULL)
791 		smbd.s_gid = grp->gr_gid;
792 
793 	smbd.s_fg = smb_config_get_fg_flag();
794 
795 	while ((c = getopt(argc, argv, ":f")) != -1) {
796 		switch (c) {
797 		case 'f':
798 			smbd.s_fg = 1;
799 			break;
800 
801 		case ':':
802 		case '?':
803 		default:
804 			smbd_usage(stderr);
805 			return (-1);
806 		}
807 	}
808 
809 	return (0);
810 }
811 
812 static void
813 smbd_usage(FILE *fp)
814 {
815 	static char *help[] = {
816 		"-f  run program in foreground"
817 	};
818 
819 	int i;
820 
821 	(void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname);
822 
823 	for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i)
824 		(void) fprintf(fp, "    %s\n", help[i]);
825 }
826 
827 static void
828 smbd_report(const char *fmt, ...)
829 {
830 	char buf[128];
831 	va_list ap;
832 
833 	if (fmt == NULL)
834 		return;
835 
836 	va_start(ap, fmt);
837 	(void) vsnprintf(buf, 128, fmt, ap);
838 	va_end(ap);
839 
840 	(void) fprintf(stderr, "smbd: %s\n", buf);
841 }
842 
843 /*
844  * Enable libumem debugging by default on DEBUG builds.
845  */
846 #ifdef DEBUG
847 const char *
848 _umem_debug_init(void)
849 {
850 	return ("default,verbose"); /* $UMEM_DEBUG setting */
851 }
852 
853 const char *
854 _umem_logging_init(void)
855 {
856 	return ("fail,contents"); /* $UMEM_LOGGING setting */
857 }
858 #endif
859