xref: /titanic_50/usr/src/cmd/smbsrv/smbd/smbd_main.c (revision 275c9da86e89f8abf71135cf63d9fc23671b2e60)
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(int, int, int);
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 
90 static pthread_t localtime_thr;
91 
92 static int smbd_refresh_init(void);
93 static void smbd_refresh_fini(void);
94 static void *smbd_refresh_monitor(void *);
95 static pthread_t nbt_listener;
96 static pthread_t tcp_listener;
97 static pthread_t refresh_thr;
98 static pthread_cond_t refresh_cond;
99 static pthread_mutex_t refresh_mutex;
100 
101 smbd_t smbd;
102 
103 /*
104  * smbd user land daemon
105  *
106  * Use SMF error codes only on return or exit.
107  */
108 int
109 main(int argc, char *argv[])
110 {
111 	struct sigaction act;
112 	sigset_t set;
113 	uid_t uid;
114 	int pfd = -1;
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 		(void) sigsuspend(&set);
187 
188 		switch (smbd.s_sigval) {
189 		case 0:
190 			break;
191 
192 		case SIGPIPE:
193 			break;
194 
195 		case SIGHUP:
196 			/* Refresh config was triggered */
197 			if (smbd.s_fg)
198 				smbd_report("reconfiguration requested");
199 			(void) pthread_cond_signal(&refresh_cond);
200 			break;
201 
202 		default:
203 			/*
204 			 * Typically SIGINT or SIGTERM.
205 			 */
206 			smbd.s_shutdown_flag = 1;
207 			break;
208 		}
209 
210 		smbd.s_sigval = 0;
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		id_winpipe_door;
331 	int		id_lmshr_door;
332 	int		id_srv_door;
333 	int		rc;
334 	uint32_t	mode;
335 	char		resource_domain[SMB_PI_MAX_DOMAIN];
336 	char		fqdn[MAXHOSTNAMELEN];
337 	smbd.s_drv_fd = -1;
338 
339 
340 	if ((mkdir(SMB_DBDIR, 0700) < 0) && (errno != EEXIST)) {
341 		smbd_report("mkdir %s: %s", SMB_DBDIR, strerror(errno));
342 		return (1);
343 	}
344 
345 	if ((rc = smb_ccache_init(SMB_VARRUN_DIR, SMB_CCACHE_FILE)) != 0) {
346 		if (rc == -1)
347 			smbd_report("mkdir %s: %s", SMB_VARRUN_DIR,
348 			    strerror(errno));
349 		else
350 			smbd_report("unable to set KRB5CCNAME");
351 		return (1);
352 	}
353 
354 
355 	(void) oem_language_set("english");
356 
357 	if (!nt_builtin_init()) {
358 		smbd_report("out of memory");
359 		return (1);
360 	}
361 
362 	(void) smb_nicmon_start();
363 	if (dns_msgid_init() != 0) {
364 		smbd_report("DNS message id initialization failed");
365 		return (1);
366 	}
367 
368 	smbrdr_init();
369 
370 	if (smb_netbios_start() != 0)
371 		smbd_report("NetBIOS services failed to start");
372 	else
373 		smbd_report("NetBIOS services started");
374 
375 	if (smb_netlogon_init() != 0) {
376 		smbd_report("netlogon initialization failed");
377 		return (1);
378 	}
379 
380 	(void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
381 	(void) utf8_strupr(resource_domain);
382 
383 	/* Get the ID map client handle */
384 	if ((rc = smb_idmap_start()) != 0) {
385 		smbd_report("no idmap handle");
386 		return (rc);
387 	}
388 
389 	mode = smb_config_get_secmode();
390 	if ((rc = nt_domain_init(resource_domain, mode)) != 0) {
391 		if (rc == SMB_DOMAIN_NOMACHINE_SID) {
392 			smbd_report(
393 			    "no machine SID: check idmap configuration");
394 			return (rc);
395 		}
396 	}
397 
398 	ads_init();
399 	if ((rc = mlsvc_init()) != 0) {
400 		smbd_report("msrpc initialization failed");
401 		return (rc);
402 	}
403 
404 	if (mode == SMB_SECMODE_DOMAIN) {
405 		if (!smb_match_netlogon_seqnum())
406 			smb_set_netlogon_cred();
407 		else
408 			(void) smbd_locate_dc(resource_domain, "");
409 
410 		(void) lsa_query_primary_domain_info();
411 	}
412 
413 	id_lmshr_door = smb_lmshrd_srv_start();
414 	if (id_lmshr_door < 0) {
415 		smbd_report("share initialization failed");
416 	}
417 
418 	id_srv_door = smb_door_srv_start();
419 	if (id_srv_door < 0)
420 		return (rc);
421 
422 	if ((rc = smbd_refresh_init()) != 0)
423 		return (rc);
424 
425 	if (smb_getfqdomainname(fqdn, MAXHOSTNAMELEN) == 0)
426 		(void) dyndns_update(fqdn, B_FALSE);
427 
428 	(void) smbd_localtime_init();
429 
430 	id_winpipe_door = smb_winpipe_doorsvc_start();
431 	if (id_winpipe_door < 0) {
432 		smbd_report("winpipe initialization failed %s",
433 		    strerror(errno));
434 		return (rc);
435 	}
436 
437 	(void) smb_lgrp_start();
438 
439 	(void) smb_pwd_init();
440 
441 	rc = smbd_kernel_bind(id_lmshr_door, id_srv_door, id_winpipe_door);
442 	if (rc != 0)
443 		smbd_report("kernel bind error: %s", strerror(errno));
444 
445 	return (lmshare_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 	smb_winpipe_doorsvc_stop();
457 	nt_builtin_fini();
458 	smbd_refresh_fini();
459 	smbd_kernel_unbind();
460 	smb_door_srv_stop();
461 	smb_lmshrd_srv_stop();
462 	lmshare_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 	return (rc);
497 
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 	int dummy = 0;
526 
527 	(void) pthread_mutex_lock(&refresh_mutex);
528 	while (pthread_cond_wait(&refresh_cond, &refresh_mutex) == 0) {
529 		/*
530 		 * We've been woken up by a refresh event so go do
531 		 * what is necessary.
532 		 */
533 		ads_refresh();
534 		smb_ccache_remove(SMB_CCACHE_PATH);
535 		smb_nicmon_reconfig();
536 		smb_set_netlogon_cred();
537 		if (ioctl(smbd.s_drv_fd, SMB_IOC_CONFIG, &dummy) < 0) {
538 			smbd_report("configuration update ioctl: %s",
539 			    strerror(errno));
540 		}
541 	}
542 	return (NULL);
543 }
544 
545 
546 /*
547  * If the door has already been opened by another process (non-zero pid
548  * in target), we assume that another smbd is already running.  If there
549  * is a race here, it will be caught later when smbsrv is opened because
550  * only one process is allowed to open the device at a time.
551  */
552 static int
553 smbd_already_running(void)
554 {
555 	door_info_t info;
556 	int door;
557 
558 	if ((door = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0)
559 		return (0);
560 
561 	if (door_info(door, &info) < 0)
562 		return (0);
563 
564 	if (info.di_target > 0) {
565 		smbd_report("already running: pid %ld\n", info.di_target);
566 		(void) close(door);
567 		return (1);
568 	}
569 
570 	(void) close(door);
571 	return (0);
572 }
573 
574 /*
575  * smbd_kernel_bind
576  */
577 static int
578 smbd_kernel_bind(int id_lmshr_door, int id_srv_door, int id_winpipe_door)
579 {
580 	smb_io_t	smb_io;
581 	int		rc;
582 
583 	bzero(&smb_io, sizeof (smb_io));
584 	smb_io.sio_version = SMB_IOC_VERSION;
585 
586 	if (smbd.s_drv_fd != -1)
587 		(void) close(smbd.s_drv_fd);
588 
589 	if ((smbd.s_drv_fd = open(DRV_DEVICE_PATH, 0)) < 0) {
590 		smbd.s_drv_fd = -1;
591 		return (errno);
592 	}
593 	smb_load_kconfig(&smb_io.sio_data.cfg);
594 	if (ioctl(smbd.s_drv_fd, SMB_IOC_CONFIG, &smb_io) < 0) {
595 		(void) close(smbd.s_drv_fd);
596 		smbd.s_drv_fd = -1;
597 		return (errno);
598 	}
599 	smb_io.sio_data.gmtoff = (uint32_t)(-altzone);
600 	if (ioctl(smbd.s_drv_fd, SMB_IOC_GMTOFF, &smb_io) < 0) {
601 		(void) close(smbd.s_drv_fd);
602 		smbd.s_drv_fd = -1;
603 		return (errno);
604 	}
605 	smb_io.sio_data.start.winpipe = id_winpipe_door;
606 	smb_io.sio_data.start.lmshrd = id_lmshr_door;
607 	smb_io.sio_data.start.udoor = id_srv_door;
608 	if (ioctl(smbd.s_drv_fd, SMB_IOC_START, &smb_io) < 0) {
609 		(void) close(smbd.s_drv_fd);
610 		smbd.s_drv_fd = -1;
611 		return (errno);
612 	}
613 
614 	rc = pthread_create(&nbt_listener, NULL, smbd_nbt_listener, NULL);
615 	if (rc == 0) {
616 		rc = pthread_create(&tcp_listener, NULL, smbd_tcp_listener,
617 		    NULL);
618 		if (rc == 0)
619 			return (0);
620 	}
621 	(void) close(smbd.s_drv_fd);
622 	smbd.s_drv_fd = -1;
623 	return (rc);
624 }
625 
626 /*
627  * smbd_kernel_unbind
628  */
629 static void
630 smbd_kernel_unbind(void)
631 {
632 	if (smbd.s_drv_fd != -1) {
633 		(void) close(smbd.s_drv_fd);
634 		smbd.s_drv_fd = -1;
635 	}
636 }
637 
638 /*
639  * Initialization of the localtime thread.
640  * Returns 0 on success, an error number if thread creation fails.
641  */
642 
643 int
644 smbd_localtime_init(void)
645 {
646 	pthread_attr_t tattr;
647 	int rc;
648 
649 	(void) pthread_attr_init(&tattr);
650 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
651 	rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0);
652 	(void) pthread_attr_destroy(&tattr);
653 	return (rc);
654 }
655 
656 /*
657  * Local time thread to kernel land.
658  * Send local gmtoff to kernel module one time at startup
659  * and each time it changes (up to twice a year).
660  * Local gmtoff is checked once every 15 minutes and
661  * since some timezones are aligned on half and qtr hour boundaries,
662  * once an hour would likely suffice.
663  */
664 
665 /*ARGSUSED*/
666 static void *
667 smbd_localtime_monitor(void *arg)
668 {
669 	struct tm local_tm;
670 	time_t secs, gmtoff;
671 	time_t last_gmtoff = -1;
672 	int timeout;
673 
674 	for (;;) {
675 		gmtoff = -altzone;
676 
677 		if ((last_gmtoff != gmtoff) && (smbd.s_drv_fd != -1)) {
678 			if (ioctl(smbd.s_drv_fd, SMB_IOC_GMTOFF, &gmtoff) < 0) {
679 				smbd_report("localtime ioctl: %s",
680 				    strerror(errno));
681 			}
682 		}
683 
684 		/*
685 		 * Align the next iteration on a fifteen minute boundary.
686 		 */
687 		secs = time(0);
688 		(void) localtime_r(&secs, &local_tm);
689 		timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN);
690 		(void) sleep(timeout);
691 
692 		last_gmtoff = gmtoff;
693 	}
694 
695 	/*NOTREACHED*/
696 	return (NULL);
697 }
698 
699 static void
700 smbd_sig_handler(int sigval)
701 {
702 	if (smbd.s_sigval == 0)
703 		smbd.s_sigval = sigval;
704 }
705 
706 /*
707  * Set up configuration options and parse the command line.
708  * This function will determine if we will run as a daemon
709  * or in the foreground.
710  *
711  * Failure to find a uid or gid results in using the default (0).
712  */
713 static int
714 smbd_setup_options(int argc, char *argv[])
715 {
716 	struct passwd *pwd;
717 	struct group *grp;
718 	int c;
719 
720 	if ((pwd = getpwnam("root")) != NULL)
721 		smbd.s_uid = pwd->pw_uid;
722 
723 	if ((grp = getgrnam("sys")) != NULL)
724 		smbd.s_gid = grp->gr_gid;
725 
726 	smbd.s_fg = smb_config_get_fg_flag();
727 
728 	while ((c = getopt(argc, argv, ":f")) != -1) {
729 		switch (c) {
730 		case 'f':
731 			smbd.s_fg = 1;
732 			break;
733 
734 		case ':':
735 		case '?':
736 		default:
737 			smbd_usage(stderr);
738 			return (-1);
739 		}
740 	}
741 
742 	return (0);
743 }
744 
745 static void
746 smbd_usage(FILE *fp)
747 {
748 	static char *help[] = {
749 		"-f  run program in foreground"
750 	};
751 
752 	int i;
753 
754 	(void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname);
755 
756 	for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i)
757 		(void) fprintf(fp, "    %s\n", help[i]);
758 }
759 
760 static void
761 smbd_report(const char *fmt, ...)
762 {
763 	char buf[128];
764 	va_list ap;
765 
766 	if (fmt == NULL)
767 		return;
768 
769 	va_start(ap, fmt);
770 	(void) vsnprintf(buf, 128, fmt, ap);
771 	va_end(ap);
772 
773 	(void) fprintf(stderr, "smbd: %s\n", buf);
774 }
775 
776 /*
777  * Enable libumem debugging by default on DEBUG builds.
778  */
779 #ifdef DEBUG
780 const char *
781 _umem_debug_init(void)
782 {
783 	return ("default,verbose"); /* $UMEM_DEBUG setting */
784 }
785 
786 const char *
787 _umem_logging_init(void)
788 {
789 	return ("fail,contents"); /* $UMEM_LOGGING setting */
790 }
791 #endif
792