xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntpd.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: ntpd.c,v 1.19 2024/08/18 20:47:18 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * ntpd.c - main program for the fixed point NTP daemon
5abb0f93cSkardel  */
6abb0f93cSkardel 
7abb0f93cSkardel #ifdef HAVE_CONFIG_H
8abb0f93cSkardel # include <config.h>
9abb0f93cSkardel #endif
10abb0f93cSkardel 
11abb0f93cSkardel #include "ntp_machine.h"
12abb0f93cSkardel #include "ntpd.h"
13abb0f93cSkardel #include "ntp_io.h"
14abb0f93cSkardel #include "ntp_stdlib.h"
15abb0f93cSkardel #include <ntp_random.h>
16abb0f93cSkardel 
172950cc38Schristos #include "ntp_config.h"
18abb0f93cSkardel #include "ntp_syslog.h"
192950cc38Schristos #include "ntp_assert.h"
20abb0f93cSkardel #include "isc/error.h"
21abb0f93cSkardel #include "isc/strerror.h"
22abb0f93cSkardel #include "isc/formatcheck.h"
232950cc38Schristos #include "iosignal.h"
24abb0f93cSkardel 
25abb0f93cSkardel #ifdef SIM
26abb0f93cSkardel # include "ntpsim.h"
27abb0f93cSkardel #endif
28abb0f93cSkardel 
293123f114Skardel #include "ntp_libopts.h"
30abb0f93cSkardel #include "ntpd-opts.h"
31abb0f93cSkardel 
328b8da087Schristos /* there's a short treatise below what the thread stuff is for.
338b8da087Schristos  * [Bug 2954] enable the threading warm-up only for Linux.
348b8da087Schristos  */
35af12ab5eSchristos #if defined(HAVE_PTHREADS) && HAVE_PTHREADS && !defined(NO_THREADS)
36af12ab5eSchristos # ifdef HAVE_PTHREAD_H
37af12ab5eSchristos #  include <pthread.h>
38af12ab5eSchristos # endif
398b8da087Schristos # if defined(linux)
40af12ab5eSchristos #  define NEED_PTHREAD_WARMUP
41af12ab5eSchristos # endif
42af12ab5eSchristos #endif
43af12ab5eSchristos 
44abb0f93cSkardel #ifdef HAVE_UNISTD_H
45abb0f93cSkardel # include <unistd.h>
46abb0f93cSkardel #endif
47abb0f93cSkardel #ifdef HAVE_SYS_STAT_H
48abb0f93cSkardel # include <sys/stat.h>
49abb0f93cSkardel #endif
50cdfa2a7eSchristos #ifdef HAVE_SYS_WAIT_H
51cdfa2a7eSchristos # include <sys/wait.h>
52cdfa2a7eSchristos #endif
53abb0f93cSkardel #include <stdio.h>
54abb0f93cSkardel #ifdef HAVE_SYS_PARAM_H
55abb0f93cSkardel # include <sys/param.h>
56abb0f93cSkardel #endif
57abb0f93cSkardel #ifdef HAVE_SYS_SIGNAL_H
58abb0f93cSkardel # include <sys/signal.h>
59abb0f93cSkardel #else
60abb0f93cSkardel # include <signal.h>
61abb0f93cSkardel #endif
62abb0f93cSkardel #ifdef HAVE_SYS_IOCTL_H
63abb0f93cSkardel # include <sys/ioctl.h>
64abb0f93cSkardel #endif /* HAVE_SYS_IOCTL_H */
65abb0f93cSkardel #if defined(HAVE_RTPRIO)
66abb0f93cSkardel # ifdef HAVE_SYS_LOCK_H
67abb0f93cSkardel #  include <sys/lock.h>
68abb0f93cSkardel # endif
69abb0f93cSkardel # include <sys/rtprio.h>
70abb0f93cSkardel #else
71abb0f93cSkardel # ifdef HAVE_PLOCK
72abb0f93cSkardel #  ifdef HAVE_SYS_LOCK_H
73abb0f93cSkardel #	include <sys/lock.h>
74abb0f93cSkardel #  endif
75abb0f93cSkardel # endif
76abb0f93cSkardel #endif
77abb0f93cSkardel #if defined(HAVE_SCHED_SETSCHEDULER)
78abb0f93cSkardel # ifdef HAVE_SCHED_H
79abb0f93cSkardel #  include <sched.h>
80abb0f93cSkardel # else
81abb0f93cSkardel #  ifdef HAVE_SYS_SCHED_H
82abb0f93cSkardel #   include <sys/sched.h>
83abb0f93cSkardel #  endif
84abb0f93cSkardel # endif
85abb0f93cSkardel #endif
86abb0f93cSkardel #if defined(HAVE_SYS_MMAN_H)
87abb0f93cSkardel # include <sys/mman.h>
88abb0f93cSkardel #endif
89abb0f93cSkardel 
90cdfa2a7eSchristos #ifdef HAVE_SYSEXITS_H
91cdfa2a7eSchristos # include <sysexits.h>
92cdfa2a7eSchristos #endif
93cdfa2a7eSchristos 
94abb0f93cSkardel #ifdef HAVE_TERMIOS_H
95abb0f93cSkardel # include <termios.h>
96abb0f93cSkardel #endif
97abb0f93cSkardel 
98abb0f93cSkardel #ifdef SYS_DOMAINOS
99abb0f93cSkardel # include <apollo/base.h>
100abb0f93cSkardel #endif /* SYS_DOMAINOS */
101abb0f93cSkardel 
1022950cc38Schristos 
103abb0f93cSkardel #include "recvbuff.h"
104abb0f93cSkardel #include "ntp_cmdargs.h"
105abb0f93cSkardel 
10679045f13Schristos #ifdef SYS_WINNT
10779045f13Schristos # include "ntservice.h"
10879045f13Schristos #endif
10979045f13Schristos 
110abb0f93cSkardel #ifdef _AIX
111abb0f93cSkardel # include <ulimit.h>
112abb0f93cSkardel #endif /* _AIX */
113abb0f93cSkardel 
114abb0f93cSkardel #ifdef SCO5_CLOCK
115abb0f93cSkardel # include <sys/ci/ciioctl.h>
116abb0f93cSkardel #endif
117abb0f93cSkardel 
118abb0f93cSkardel #ifdef HAVE_DROPROOT
119abb0f93cSkardel # include <ctype.h>
120abb0f93cSkardel # include <grp.h>
121abb0f93cSkardel # include <pwd.h>
122abb0f93cSkardel #ifdef HAVE_LINUX_CAPABILITIES
123abb0f93cSkardel # include <sys/capability.h>
124abb0f93cSkardel # include <sys/prctl.h>
1252950cc38Schristos #endif /* HAVE_LINUX_CAPABILITIES */
1262950cc38Schristos #if defined(HAVE_PRIV_H) && defined(HAVE_SOLARIS_PRIVS)
1272950cc38Schristos # include <priv.h>
1282950cc38Schristos #endif /* HAVE_PRIV_H */
12979045f13Schristos #if defined(HAVE_TRUSTEDBSD_MAC)
13079045f13Schristos # include <sys/mac.h>
13179045f13Schristos #endif /* HAVE_TRUSTEDBSD_MAC */
1322950cc38Schristos #endif /* HAVE_DROPROOT */
133abb0f93cSkardel 
134ea66d795Schristos #if defined (LIBSECCOMP) && (KERN_SECCOMP)
135ea66d795Schristos /* # include <sys/types.h> */
136ea66d795Schristos # include <sys/resource.h>
137ea66d795Schristos # include <seccomp.h>
138ea66d795Schristos #endif /* LIBSECCOMP and KERN_SECCOMP */
139ea66d795Schristos 
140*eabc0478Schristos #if defined(__FreeBSD__) &&  __FreeBSD_version < 1400037 && defined(HAVE_SYS_PROCCTL_H)
141cdfa2a7eSchristos # include <sys/procctl.h>
142*eabc0478Schristos # ifdef PROC_STACKGAP_DISABLE
143*eabc0478Schristos #  define DISABLE_FREEBSD_STACKGAP
144cdfa2a7eSchristos # endif
145cdfa2a7eSchristos #endif
146cdfa2a7eSchristos 
147abb0f93cSkardel #ifdef HAVE_DNSREGISTRATION
148abb0f93cSkardel # include <dns_sd.h>
149abb0f93cSkardel DNSServiceRef mdns;
150abb0f93cSkardel #endif
151abb0f93cSkardel 
152cdfa2a7eSchristos /* In case 'sysexits.h' is unavailable, define some exit codes here: */
153cdfa2a7eSchristos #ifndef EX_SOFTWARE
154cdfa2a7eSchristos # define EX_SOFTWARE	70
155cdfa2a7eSchristos #endif
156cdfa2a7eSchristos #ifndef EX_OSERR
157cdfa2a7eSchristos # define EX_OSERR	71
158cdfa2a7eSchristos #endif
159cdfa2a7eSchristos #ifndef EX_IOERR
160cdfa2a7eSchristos # define EX_IOERR	74
161cdfa2a7eSchristos #endif
162cdfa2a7eSchristos #ifndef EX_PROTOCOL
163cdfa2a7eSchristos #define EX_PROTOCOL	76
164cdfa2a7eSchristos #endif
165cdfa2a7eSchristos 
166cdfa2a7eSchristos 
1672950cc38Schristos #ifdef HAVE_SETPGRP_0
1682950cc38Schristos # define ntp_setpgrp(x, y)	setpgrp()
1692950cc38Schristos #else
1702950cc38Schristos # define ntp_setpgrp(x, y)	setpgrp(x, y)
1712950cc38Schristos #endif
1722950cc38Schristos 
1732950cc38Schristos #ifdef HAVE_SOLARIS_PRIVS
1742950cc38Schristos # define LOWPRIVS "basic,sys_time,net_privaddr,proc_setid,!proc_info,!proc_session,!proc_exec"
1752950cc38Schristos static priv_set_t *lowprivs = NULL;
1762950cc38Schristos static priv_set_t *highprivs = NULL;
1772950cc38Schristos #endif /* HAVE_SOLARIS_PRIVS */
178abb0f93cSkardel /*
179abb0f93cSkardel  * Scheduling priority we run at
180abb0f93cSkardel  */
181abb0f93cSkardel #define NTPD_PRIO	(-12)
182abb0f93cSkardel 
183abb0f93cSkardel int priority_done = 2;		/* 0 - Set priority */
184abb0f93cSkardel 				/* 1 - priority is OK where it is */
185abb0f93cSkardel 				/* 2 - Don't set priority */
186abb0f93cSkardel 				/* 1 and 2 are pretty much the same */
187abb0f93cSkardel 
1882950cc38Schristos int listen_to_virtual_ips = TRUE;
189abb0f93cSkardel 
190abb0f93cSkardel /*
191abb0f93cSkardel  * No-fork flag.  If set, we do not become a background daemon.
192abb0f93cSkardel  */
1932950cc38Schristos int nofork;			/* Fork by default */
194abb0f93cSkardel 
195abb0f93cSkardel #ifdef HAVE_DNSREGISTRATION
196abb0f93cSkardel /*
197abb0f93cSkardel  * mDNS registration flag. If set, we attempt to register with the mDNS system, but only
198abb0f93cSkardel  * after we have synched the first time. If the attempt fails, then try again once per
199abb0f93cSkardel  * minute for up to 5 times. After all, we may be starting before mDNS.
200abb0f93cSkardel  */
2012950cc38Schristos int mdnsreg = FALSE;
2022950cc38Schristos int mdnstries = 5;
203abb0f93cSkardel #endif  /* HAVE_DNSREGISTRATION */
204abb0f93cSkardel 
205cdfa2a7eSchristos #ifdef HAVE_LINUX_CAPABILITIES
206cdfa2a7eSchristos int have_caps;		/* runtime check whether capabilities work */
207cdfa2a7eSchristos #endif /* HAVE_LINUX_CAPABILITIES */
208cdfa2a7eSchristos 
209abb0f93cSkardel #ifdef HAVE_DROPROOT
2102950cc38Schristos int droproot;
2112950cc38Schristos int root_dropped;
2122950cc38Schristos char *user;		/* User to switch to */
2132950cc38Schristos char *group;		/* group to switch to */
2142950cc38Schristos const char *chrootdir;	/* directory to chroot to */
215e589aa51Schristos uid_t sw_uid;
216e589aa51Schristos gid_t sw_gid;
217abb0f93cSkardel struct group *gr;
218abb0f93cSkardel struct passwd *pw;
219abb0f93cSkardel #endif /* HAVE_DROPROOT */
220abb0f93cSkardel 
2212950cc38Schristos #ifdef HAVE_WORKING_FORK
222cdfa2a7eSchristos int	daemon_pipe[2] = { -1, -1 };
2232950cc38Schristos #endif
2242950cc38Schristos 
225abb0f93cSkardel /*
226abb0f93cSkardel  * Version declaration
227abb0f93cSkardel  */
228abb0f93cSkardel extern const char *Version;
229abb0f93cSkardel 
230abb0f93cSkardel char const *progname;
231abb0f93cSkardel 
232abb0f93cSkardel int was_alarmed;
233abb0f93cSkardel 
234abb0f93cSkardel #ifdef DECL_SYSCALL
235abb0f93cSkardel /*
236abb0f93cSkardel  * We put this here, since the argument profile is syscall-specific
237abb0f93cSkardel  */
238abb0f93cSkardel extern int syscall	(int, ...);
239abb0f93cSkardel #endif /* DECL_SYSCALL */
240abb0f93cSkardel 
241abb0f93cSkardel 
2422950cc38Schristos #if !defined(SIM) && defined(SIGDIE1)
24368dbbb44Schristos static volatile int signalled	= 0;
24468dbbb44Schristos static volatile int signo	= 0;
24568dbbb44Schristos 
24668dbbb44Schristos /* In an ideal world, 'finish_safe()' would declared as noreturn... */
24768dbbb44Schristos static	void		finish_safe	(int);
248abb0f93cSkardel static	RETSIGTYPE	finish		(int);
2492950cc38Schristos #endif
250abb0f93cSkardel 
2512950cc38Schristos #if !defined(SIM) && defined(HAVE_WORKING_FORK)
252cdfa2a7eSchristos static int	wait_child_sync_if	(int, unsigned long);
253cdfa2a7eSchristos static int	wait_child_exit_if	(pid_t, int);
2542950cc38Schristos #endif
2552950cc38Schristos 
2562950cc38Schristos #if !defined(SIM) && !defined(SYS_WINNT)
257abb0f93cSkardel # ifdef	DEBUG
258abb0f93cSkardel static	RETSIGTYPE	moredebug	(int);
259abb0f93cSkardel static	RETSIGTYPE	lessdebug	(int);
2602950cc38Schristos # else	/* !DEBUG follows */
261abb0f93cSkardel static	RETSIGTYPE	no_debug	(int);
2622950cc38Schristos # endif	/* !DEBUG */
2632950cc38Schristos #endif	/* !SIM && !SYS_WINNT */
264abb0f93cSkardel 
265ccc794f0Schristos #ifndef WORK_FORK
2662950cc38Schristos int	saved_argc;
2672950cc38Schristos char **	saved_argv;
268ccc794f0Schristos #endif
2692950cc38Schristos 
2702950cc38Schristos #ifndef SIM
271abb0f93cSkardel int		ntpdmain		(int, char **);
272abb0f93cSkardel static void	set_process_priority	(void);
2732950cc38Schristos static void	assertion_failed	(const char *, int,
2742950cc38Schristos 					 isc_assertiontype_t,
2752950cc38Schristos 					 const char *)
2762950cc38Schristos 			__attribute__	((__noreturn__));
2772950cc38Schristos static void	library_fatal_error	(const char *, int,
2782950cc38Schristos 					 const char *, va_list)
2792950cc38Schristos 					ISC_FORMAT_PRINTF(3, 0);
2802950cc38Schristos static void	library_unexpected_error(const char *, int,
2812950cc38Schristos 					 const char *, va_list)
2822950cc38Schristos 					ISC_FORMAT_PRINTF(3, 0);
2832950cc38Schristos #endif	/* !SIM */
284abb0f93cSkardel 
285abb0f93cSkardel 
286af12ab5eSchristos /* Bug2332 unearthed a problem in the interaction of reduced user
287af12ab5eSchristos  * privileges, the limits on memory usage and some versions of the
288af12ab5eSchristos  * pthread library on Linux systems. The 'pthread_cancel()' function and
289af12ab5eSchristos  * likely some others need to track the stack of the thread involved,
290af12ab5eSchristos  * and uses a function that comes from GCC (--> libgcc_s.so) to do
291af12ab5eSchristos  * this. Unfortunately the developers of glibc decided to load the
292af12ab5eSchristos  * library on demand, which speeds up program start but can cause
293af12ab5eSchristos  * trouble here: Due to all the things NTPD does to limit its resource
294af12ab5eSchristos  * usage, this deferred load of libgcc_s does not always work once the
295af12ab5eSchristos  * restrictions are in effect.
296af12ab5eSchristos  *
297af12ab5eSchristos  * One way out of this was attempting a forced link against libgcc_s
298af12ab5eSchristos  * when possible because it makes the library available immediately
299af12ab5eSchristos  * without deferred load. (The symbol resolution would still be dynamic
300af12ab5eSchristos  * and on demand, but the code would already be in the process image.)
301af12ab5eSchristos  *
302af12ab5eSchristos  * This is a tricky thing to do, since it's not necessary everywhere,
303af12ab5eSchristos  * not possible everywhere, has shown to break the build of other
304af12ab5eSchristos  * programs in the NTP suite and is now generally frowned upon.
305af12ab5eSchristos  *
306af12ab5eSchristos  * So we take a different approach here: We creat a worker thread that does
307af12ab5eSchristos  * actually nothing except waiting for cancellation and cancel it. If
308af12ab5eSchristos  * this is done before all the limitations are put in place, the
309af12ab5eSchristos  * machinery is pre-heated and all the runtime stuff should be in place
310af12ab5eSchristos  * and useable when needed.
311af12ab5eSchristos  *
312af12ab5eSchristos  * This uses only the standard pthread API and should work with all
313af12ab5eSchristos  * implementations of pthreads. It is not necessary everywhere, but it's
314af12ab5eSchristos  * cheap enough to go on nearly unnoticed.
3158b8da087Schristos  *
3168b8da087Schristos  * Addendum: Bug 2954 showed that the assumption that this should work
3178b8da087Schristos  * with all OS is wrong -- at least FreeBSD bombs heavily.
318af12ab5eSchristos  */
319af12ab5eSchristos #ifdef NEED_PTHREAD_WARMUP
320af12ab5eSchristos 
321af12ab5eSchristos /* simple thread function: sleep until cancelled, just to exercise
322af12ab5eSchristos  * thread cancellation.
323af12ab5eSchristos  */
324af12ab5eSchristos static void*
325af12ab5eSchristos my_pthread_warmup_worker(
326af12ab5eSchristos 	void *thread_args)
327af12ab5eSchristos {
328af12ab5eSchristos 	(void)thread_args;
329af12ab5eSchristos 	for (;;)
330af12ab5eSchristos 		sleep(10);
331af12ab5eSchristos 	return NULL;
332af12ab5eSchristos }
333af12ab5eSchristos 
334af12ab5eSchristos /* pre-heat threading: create a thread and cancel it, just to exercise
335af12ab5eSchristos  * thread cancellation.
336af12ab5eSchristos  */
337af12ab5eSchristos static void
338af12ab5eSchristos my_pthread_warmup(void)
339af12ab5eSchristos {
340af12ab5eSchristos 	pthread_t 	thread;
34168dbbb44Schristos 	pthread_attr_t	thr_attr;
342af12ab5eSchristos 	int       	rc;
34368dbbb44Schristos 
34468dbbb44Schristos 	pthread_attr_init(&thr_attr);
34568dbbb44Schristos #if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \
34668dbbb44Schristos     defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && \
34768dbbb44Schristos     defined(PTHREAD_STACK_MIN)
3484eea345dSchristos 	{
3494eea345dSchristos 		size_t ssmin = 32*1024;	/* 32kB should be minimum */
3504eea345dSchristos 		if (ssmin < PTHREAD_STACK_MIN)
3514eea345dSchristos 			ssmin = PTHREAD_STACK_MIN;
3524eea345dSchristos 		rc = pthread_attr_setstacksize(&thr_attr, ssmin);
35368dbbb44Schristos 		if (0 != rc)
35468dbbb44Schristos 			msyslog(LOG_ERR,
35568dbbb44Schristos 				"my_pthread_warmup: pthread_attr_setstacksize() -> %s",
35668dbbb44Schristos 				strerror(rc));
3574eea345dSchristos 	}
35868dbbb44Schristos #endif
359af12ab5eSchristos 	rc = pthread_create(
36068dbbb44Schristos 		&thread, &thr_attr, my_pthread_warmup_worker, NULL);
36168dbbb44Schristos 	pthread_attr_destroy(&thr_attr);
36268dbbb44Schristos 	if (0 != rc) {
36368dbbb44Schristos 		msyslog(LOG_ERR,
36468dbbb44Schristos 			"my_pthread_warmup: pthread_create() -> %s",
36568dbbb44Schristos 			strerror(rc));
36668dbbb44Schristos 	} else {
367af12ab5eSchristos 		pthread_cancel(thread);
368af12ab5eSchristos 		pthread_join(thread, NULL);
369af12ab5eSchristos 	}
370af12ab5eSchristos }
371af12ab5eSchristos 
372af12ab5eSchristos #endif /*defined(NEED_PTHREAD_WARMUP)*/
3732950cc38Schristos 
37468dbbb44Schristos #ifdef NEED_EARLY_FORK
37568dbbb44Schristos static void
37668dbbb44Schristos dummy_callback(void) { return; }
37768dbbb44Schristos 
37868dbbb44Schristos static void
37968dbbb44Schristos fork_nonchroot_worker(void) {
38068dbbb44Schristos 	getaddrinfo_sometime("localhost", "ntp", NULL, INITIAL_DNS_RETRY,
38168dbbb44Schristos 			     (gai_sometime_callback)&dummy_callback, NULL);
38268dbbb44Schristos }
38368dbbb44Schristos #endif /* NEED_EARLY_FORK */
3842950cc38Schristos 
385abb0f93cSkardel void
3862950cc38Schristos parse_cmdline_opts(
387abb0f93cSkardel 	int *	pargc,
388abb0f93cSkardel 	char ***pargv
389abb0f93cSkardel 	)
390abb0f93cSkardel {
3912950cc38Schristos 	static int	parsed;
3922950cc38Schristos 	static int	optct;
393abb0f93cSkardel 
3942950cc38Schristos 	if (!parsed)
3953123f114Skardel 		optct = ntpOptionProcess(&ntpdOptions, *pargc, *pargv);
3962950cc38Schristos 
3972950cc38Schristos 	parsed = 1;
3982950cc38Schristos 
399abb0f93cSkardel 	*pargc -= optct;
400abb0f93cSkardel 	*pargv += optct;
401abb0f93cSkardel }
402abb0f93cSkardel 
403abb0f93cSkardel 
404abb0f93cSkardel #ifdef SIM
405abb0f93cSkardel int
406abb0f93cSkardel main(
407abb0f93cSkardel 	int argc,
408abb0f93cSkardel 	char *argv[]
409abb0f93cSkardel 	)
410abb0f93cSkardel {
4112950cc38Schristos 	progname = argv[0];
4122950cc38Schristos 	parse_cmdline_opts(&argc, &argv);
4132950cc38Schristos #ifdef DEBUG
4142950cc38Schristos 	debug = OPT_VALUE_SET_DEBUG_LEVEL;
4152950cc38Schristos 	DPRINTF(1, ("%s\n", Version));
4162950cc38Schristos #endif
417abb0f93cSkardel 
418abb0f93cSkardel 	return ntpsim(argc, argv);
419abb0f93cSkardel }
420cdfa2a7eSchristos #elif defined(NO_MAIN_ALLOWED)
421abb0f93cSkardel CALL(ntpd,"ntpd",ntpdmain);
422cdfa2a7eSchristos #elif !defined(SYS_WINNT)
423abb0f93cSkardel int
424abb0f93cSkardel main(
425abb0f93cSkardel 	int argc,
426abb0f93cSkardel 	char *argv[]
427abb0f93cSkardel 	)
428abb0f93cSkardel {
429*eabc0478Schristos # ifdef DISABLE_FREEBSD_STACKGAP
430cdfa2a7eSchristos 	/*
431*eabc0478Schristos 	* We must disable ASLR stack gap on FreeBSD that has
432*eabc0478Schristos 	* PROC_STACKGAP_DISABLE up through early FreeBSD 14
433*eabc0478Schristos 	* versions to avoid a segfault. See:
434*eabc0478Schristos 	*
435*eabc0478Schristos 	* https://bugs.ntp.org/3627
436*eabc0478Schristos 	* https://cgit.freebsd.org/src/commit/?id=889b56c8cd84c9a9f2d9e3b019c154d6f14d9021
437*eabc0478Schristos 	* https://cgit.freebsd.org/src/commit/?id=fc393054398ea50fb0cee52704e9385afe888b48
438*eabc0478Schristos 	* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=253208
439*eabc0478Schristos 	* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=241421
440*eabc0478Schristos 	* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=241960
441cdfa2a7eSchristos 	*/
442cdfa2a7eSchristos 	int aslr_var = PROC_STACKGAP_DISABLE;
443cdfa2a7eSchristos 
444*eabc0478Schristos 	procctl(P_PID, getpid(), PROC_STACKGAP_CTL, &aslr_var);
445*eabc0478Schristos # endif	/* DISABLE_FREEBSD_STACKGAP */
446*eabc0478Schristos 
447abb0f93cSkardel 	return ntpdmain(argc, argv);
448abb0f93cSkardel }
4492950cc38Schristos #endif /* !SYS_WINNT */
450abb0f93cSkardel 
451abb0f93cSkardel #ifdef _AIX
452abb0f93cSkardel /*
453abb0f93cSkardel  * OK. AIX is different than solaris in how it implements plock().
454abb0f93cSkardel  * If you do NOT adjust the stack limit, you will get the MAXIMUM
455abb0f93cSkardel  * stack size allocated and PINNED with you program. To check the
456abb0f93cSkardel  * value, use ulimit -a.
457abb0f93cSkardel  *
458abb0f93cSkardel  * To fix this, we create an automatic variable and set our stack limit
459abb0f93cSkardel  * to that PLUS 32KB of extra space (we need some headroom).
460abb0f93cSkardel  *
461abb0f93cSkardel  * This subroutine gets the stack address.
462abb0f93cSkardel  *
463abb0f93cSkardel  * Grover Davidson and Matt Ladendorf
464abb0f93cSkardel  *
465abb0f93cSkardel  */
466abb0f93cSkardel static char *
467abb0f93cSkardel get_aix_stack(void)
468abb0f93cSkardel {
469abb0f93cSkardel 	char ch;
470abb0f93cSkardel 	return (&ch);
471abb0f93cSkardel }
472abb0f93cSkardel 
473abb0f93cSkardel /*
474abb0f93cSkardel  * Signal handler for SIGDANGER.
475abb0f93cSkardel  */
476abb0f93cSkardel static void
477abb0f93cSkardel catch_danger(int signo)
478abb0f93cSkardel {
479abb0f93cSkardel 	msyslog(LOG_INFO, "ntpd: setpgid(): %m");
480abb0f93cSkardel 	/* Make the system believe we'll free something, but don't do it! */
481abb0f93cSkardel 	return;
482abb0f93cSkardel }
483abb0f93cSkardel #endif /* _AIX */
484abb0f93cSkardel 
485abb0f93cSkardel /*
486abb0f93cSkardel  * Set the process priority
487abb0f93cSkardel  */
4882950cc38Schristos #ifndef SIM
489abb0f93cSkardel static void
490abb0f93cSkardel set_process_priority(void)
491abb0f93cSkardel {
492abb0f93cSkardel 
493abb0f93cSkardel # ifdef DEBUG
494abb0f93cSkardel 	if (debug > 1)
495abb0f93cSkardel 		msyslog(LOG_DEBUG, "set_process_priority: %s: priority_done is <%d>",
496abb0f93cSkardel 			((priority_done)
497abb0f93cSkardel 			 ? "Leave priority alone"
498abb0f93cSkardel 			 : "Attempt to set priority"
499abb0f93cSkardel 				),
500abb0f93cSkardel 			priority_done);
501abb0f93cSkardel # endif /* DEBUG */
502abb0f93cSkardel 
503abb0f93cSkardel # if defined(HAVE_SCHED_SETSCHEDULER)
504abb0f93cSkardel 	if (!priority_done) {
505abb0f93cSkardel 		extern int config_priority_override, config_priority;
506abb0f93cSkardel 		int pmax, pmin;
507abb0f93cSkardel 		struct sched_param sched;
508abb0f93cSkardel 
509abb0f93cSkardel 		pmax = sched_get_priority_max(SCHED_FIFO);
510abb0f93cSkardel 		sched.sched_priority = pmax;
511abb0f93cSkardel 		if ( config_priority_override ) {
512abb0f93cSkardel 			pmin = sched_get_priority_min(SCHED_FIFO);
513abb0f93cSkardel 			if ( config_priority > pmax )
514abb0f93cSkardel 				sched.sched_priority = pmax;
515abb0f93cSkardel 			else if ( config_priority < pmin )
516abb0f93cSkardel 				sched.sched_priority = pmin;
517abb0f93cSkardel 			else
518abb0f93cSkardel 				sched.sched_priority = config_priority;
519abb0f93cSkardel 		}
520abb0f93cSkardel 		if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 )
521abb0f93cSkardel 			msyslog(LOG_ERR, "sched_setscheduler(): %m");
522abb0f93cSkardel 		else
523abb0f93cSkardel 			++priority_done;
524abb0f93cSkardel 	}
525abb0f93cSkardel # endif /* HAVE_SCHED_SETSCHEDULER */
5262950cc38Schristos # ifdef HAVE_RTPRIO
527abb0f93cSkardel #  ifdef RTP_SET
528abb0f93cSkardel 	if (!priority_done) {
529abb0f93cSkardel 		struct rtprio srtp;
530abb0f93cSkardel 
531abb0f93cSkardel 		srtp.type = RTP_PRIO_REALTIME;	/* was: RTP_PRIO_NORMAL */
532abb0f93cSkardel 		srtp.prio = 0;		/* 0 (hi) -> RTP_PRIO_MAX (31,lo) */
533abb0f93cSkardel 
534abb0f93cSkardel 		if (rtprio(RTP_SET, getpid(), &srtp) < 0)
535abb0f93cSkardel 			msyslog(LOG_ERR, "rtprio() error: %m");
536abb0f93cSkardel 		else
537abb0f93cSkardel 			++priority_done;
538abb0f93cSkardel 	}
5392950cc38Schristos #  else	/* !RTP_SET follows */
540abb0f93cSkardel 	if (!priority_done) {
541abb0f93cSkardel 		if (rtprio(0, 120) < 0)
542abb0f93cSkardel 			msyslog(LOG_ERR, "rtprio() error: %m");
543abb0f93cSkardel 		else
544abb0f93cSkardel 			++priority_done;
545abb0f93cSkardel 	}
5462950cc38Schristos #  endif	/* !RTP_SET */
547abb0f93cSkardel # endif	/* HAVE_RTPRIO */
548abb0f93cSkardel # if defined(NTPD_PRIO) && NTPD_PRIO != 0
549abb0f93cSkardel #  ifdef HAVE_ATT_NICE
550abb0f93cSkardel 	if (!priority_done) {
551abb0f93cSkardel 		errno = 0;
552abb0f93cSkardel 		if (-1 == nice (NTPD_PRIO) && errno != 0)
553abb0f93cSkardel 			msyslog(LOG_ERR, "nice() error: %m");
554abb0f93cSkardel 		else
555abb0f93cSkardel 			++priority_done;
556abb0f93cSkardel 	}
557abb0f93cSkardel #  endif	/* HAVE_ATT_NICE */
558abb0f93cSkardel #  ifdef HAVE_BSD_NICE
559abb0f93cSkardel 	if (!priority_done) {
560abb0f93cSkardel 		if (-1 == setpriority(PRIO_PROCESS, 0, NTPD_PRIO))
561abb0f93cSkardel 			msyslog(LOG_ERR, "setpriority() error: %m");
562abb0f93cSkardel 		else
563abb0f93cSkardel 			++priority_done;
564abb0f93cSkardel 	}
565abb0f93cSkardel #  endif	/* HAVE_BSD_NICE */
566abb0f93cSkardel # endif	/* NTPD_PRIO && NTPD_PRIO != 0 */
567abb0f93cSkardel 	if (!priority_done)
568abb0f93cSkardel 		msyslog(LOG_ERR, "set_process_priority: No way found to improve our priority");
569abb0f93cSkardel }
5702950cc38Schristos #endif	/* !SIM */
571abb0f93cSkardel 
57279045f13Schristos #if !defined(SIM) && !defined(SYS_WINNT)
57379045f13Schristos /*
57479045f13Schristos  * Detach from terminal (much like daemon())
57579045f13Schristos  * Nothe that this function calls exit()
57679045f13Schristos  */
577cdfa2a7eSchristos # ifdef HAVE_WORKING_FORK
57879045f13Schristos static void
57979045f13Schristos detach_from_terminal(
580*eabc0478Schristos 	int pipes[2],
58179045f13Schristos 	long wait_sync,
58279045f13Schristos 	const char *logfilename
58379045f13Schristos 	)
58479045f13Schristos {
585cdfa2a7eSchristos 	pid_t	cpid;
58679045f13Schristos 	int	exit_code;
58779045f13Schristos #  if !defined(HAVE_SETSID) && !defined (HAVE_SETPGID) && defined(TIOCNOTTY)
58879045f13Schristos 	int		fid;
58979045f13Schristos #  endif
59079045f13Schristos #  ifdef _AIX
59179045f13Schristos 	struct sigaction sa;
59279045f13Schristos #  endif
59379045f13Schristos 
594cdfa2a7eSchristos 	cpid = fork();
595cdfa2a7eSchristos 	if (0 != cpid) {
59679045f13Schristos 		/* parent */
597cdfa2a7eSchristos 		if (-1 == cpid) {
598cdfa2a7eSchristos 			msyslog(LOG_ERR, "fork: %m");
599cdfa2a7eSchristos 			exit_code = EX_OSERR;
600cdfa2a7eSchristos 		} else {
601*eabc0478Schristos 			close(pipes[1]);
602*eabc0478Schristos 			pipes[1] = -1;
603cdfa2a7eSchristos 			exit_code = wait_child_sync_if(
604*eabc0478Schristos 					pipes[0], wait_sync);
605cdfa2a7eSchristos 			if (exit_code <= 0) {
606cdfa2a7eSchristos 				/* probe daemon exit code -- wait for
607cdfa2a7eSchristos 				 * child process if we have an unexpected
608cdfa2a7eSchristos 				 * EOF on the monitor pipe.
609cdfa2a7eSchristos 				 */
610cdfa2a7eSchristos 				exit_code = wait_child_exit_if(
611cdfa2a7eSchristos 						cpid, (exit_code < 0));
612cdfa2a7eSchristos 			}
613cdfa2a7eSchristos 		}
61479045f13Schristos 		exit(exit_code);
61579045f13Schristos 	}
61679045f13Schristos 
61779045f13Schristos 	/*
61879045f13Schristos 	 * child/daemon
61979045f13Schristos 	 * close all open files excepting waitsync_fd_to_close.
62079045f13Schristos 	 * msyslog() unreliable until after init_logging().
62179045f13Schristos 	 */
62279045f13Schristos 	closelog();
62379045f13Schristos 	if (syslog_file != NULL) {
62479045f13Schristos 		fclose(syslog_file);
62579045f13Schristos 		syslog_file = NULL;
62679045f13Schristos 		syslogit = TRUE;
62779045f13Schristos 	}
628*eabc0478Schristos 	close_all_except(pipes[1]);
629*eabc0478Schristos 	pipes[0] = -1;
63079045f13Schristos 	INSIST(0 == open("/dev/null", 0) && 1 == dup2(0, 1) \
63179045f13Schristos 		&& 2 == dup2(0, 2));
63279045f13Schristos 
63379045f13Schristos 	init_logging(progname, 0, TRUE);
63479045f13Schristos 	/* we lost our logfile (if any) daemonizing */
63579045f13Schristos 	setup_logfile(logfilename);
63679045f13Schristos 
63779045f13Schristos #  ifdef SYS_DOMAINOS
63879045f13Schristos 	{
63979045f13Schristos 		uid_$t puid;
64079045f13Schristos 		status_$t st;
64179045f13Schristos 
64279045f13Schristos 		proc2_$who_am_i(&puid);
64379045f13Schristos 		proc2_$make_server(&puid, &st);
64479045f13Schristos 	}
64579045f13Schristos #  endif	/* SYS_DOMAINOS */
64679045f13Schristos #  ifdef HAVE_SETSID
64779045f13Schristos 	if (setsid() == (pid_t)-1)
64879045f13Schristos 		msyslog(LOG_ERR, "setsid(): %m");
64979045f13Schristos #  elif defined(HAVE_SETPGID)
65079045f13Schristos 	if (setpgid(0, 0) == -1)
65179045f13Schristos 		msyslog(LOG_ERR, "setpgid(): %m");
65279045f13Schristos #  else		/* !HAVE_SETSID && !HAVE_SETPGID follows */
65379045f13Schristos #   ifdef TIOCNOTTY
65479045f13Schristos 	fid = open("/dev/tty", 2);
65579045f13Schristos 	if (fid >= 0) {
65679045f13Schristos 		ioctl(fid, (u_long)TIOCNOTTY, NULL);
65779045f13Schristos 		close(fid);
65879045f13Schristos 	}
65979045f13Schristos #   endif	/* TIOCNOTTY */
66079045f13Schristos 	ntp_setpgrp(0, getpid());
66179045f13Schristos #  endif	/* !HAVE_SETSID && !HAVE_SETPGID */
66279045f13Schristos #  ifdef _AIX
66379045f13Schristos 	/* Don't get killed by low-on-memory signal. */
66479045f13Schristos 	sa.sa_handler = catch_danger;
66579045f13Schristos 	sigemptyset(&sa.sa_mask);
66679045f13Schristos 	sa.sa_flags = SA_RESTART;
66779045f13Schristos 	sigaction(SIGDANGER, &sa, NULL);
66879045f13Schristos #  endif	/* _AIX */
66979045f13Schristos 
67079045f13Schristos 	return;
67179045f13Schristos }
672cdfa2a7eSchristos # endif /* HAVE_WORKING_FORK */
673*eabc0478Schristos #endif /* !SIM && !SYS_WINNT */
67479045f13Schristos 
67579045f13Schristos #ifdef HAVE_DROPROOT
67679045f13Schristos /*
67779045f13Schristos  * Map user name/number to user ID
67879045f13Schristos */
67979045f13Schristos static int
68079045f13Schristos map_user(void)
68179045f13Schristos {
68279045f13Schristos 	char *endp;
68379045f13Schristos 
68479045f13Schristos 	if (isdigit((unsigned char)*user)) {
68579045f13Schristos 		sw_uid = (uid_t)strtoul(user, &endp, 0);
68679045f13Schristos 		if (*endp != '\0')
68779045f13Schristos 			goto getuser;
68879045f13Schristos 
68979045f13Schristos 		if ((pw = getpwuid(sw_uid)) != NULL) {
69079045f13Schristos 			free(user);
69179045f13Schristos 			user = estrdup(pw->pw_name);
69279045f13Schristos 			sw_gid = pw->pw_gid;
69379045f13Schristos 		} else {
69479045f13Schristos 			errno = 0;
69579045f13Schristos 			msyslog(LOG_ERR, "Cannot find user ID %s", user);
69679045f13Schristos 			return 0;
69779045f13Schristos 		}
69879045f13Schristos 
69979045f13Schristos 	} else {
70079045f13Schristos getuser:
70179045f13Schristos 		errno = 0;
70279045f13Schristos 		if ((pw = getpwnam(user)) != NULL) {
70379045f13Schristos 			sw_uid = pw->pw_uid;
70479045f13Schristos 			sw_gid = pw->pw_gid;
70579045f13Schristos 		} else {
70679045f13Schristos 			if (errno)
70779045f13Schristos 				msyslog(LOG_ERR, "getpwnam(%s) failed: %m", user);
70879045f13Schristos 			else
70979045f13Schristos 				msyslog(LOG_ERR, "Cannot find user `%s'", user);
71079045f13Schristos 			return 0;
71179045f13Schristos 		}
71279045f13Schristos 	}
71379045f13Schristos 
71479045f13Schristos 	return 1;
71579045f13Schristos }
71679045f13Schristos 
71779045f13Schristos /*
71879045f13Schristos  * Map group name/number to group ID
71979045f13Schristos */
72079045f13Schristos static int
72179045f13Schristos map_group(void)
72279045f13Schristos {
72379045f13Schristos 	char *endp;
72479045f13Schristos 
72579045f13Schristos 	if (isdigit((unsigned char)*group)) {
72679045f13Schristos 		sw_gid = (gid_t)strtoul(group, &endp, 0);
72779045f13Schristos 		if (*endp != '\0')
72879045f13Schristos 			goto getgroup;
72979045f13Schristos 	} else {
73079045f13Schristos getgroup:
73179045f13Schristos 		if ((gr = getgrnam(group)) != NULL) {
73279045f13Schristos 			sw_gid = gr->gr_gid;
73379045f13Schristos 		} else {
73479045f13Schristos 			errno = 0;
73579045f13Schristos 			msyslog(LOG_ERR, "Cannot find group `%s'", group);
73679045f13Schristos 			return 0;
73779045f13Schristos 		}
73879045f13Schristos 	}
73979045f13Schristos 
74079045f13Schristos 	return 1;
74179045f13Schristos }
74279045f13Schristos 
7431f68464dSchristos static int
7441f68464dSchristos set_group_ids(void)
74579045f13Schristos {
74679045f13Schristos 	if (user && initgroups(user, sw_gid)) {
74779045f13Schristos 		msyslog(LOG_ERR, "Cannot initgroups() to user `%s': %m", user);
74879045f13Schristos 		return 0;
74979045f13Schristos 	}
75079045f13Schristos 	if (group && setgid(sw_gid)) {
75179045f13Schristos 		msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group);
75279045f13Schristos 		return 0;
75379045f13Schristos 	}
75479045f13Schristos 	if (group && setegid(sw_gid)) {
75579045f13Schristos 		msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group);
75679045f13Schristos 		return 0;
75779045f13Schristos 	}
75879045f13Schristos 	if (group) {
75979045f13Schristos 		if (0 != setgroups(1, &sw_gid)) {
76079045f13Schristos 			msyslog(LOG_ERR, "setgroups(1, %d) failed: %m", sw_gid);
76179045f13Schristos 			return 0;
76279045f13Schristos 		}
76379045f13Schristos 	}
76479045f13Schristos 	else if (pw)
76579045f13Schristos 		if (0 != initgroups(pw->pw_name, pw->pw_gid)) {
76679045f13Schristos 			msyslog(LOG_ERR, "initgroups(<%s>, %d) filed: %m", pw->pw_name, pw->pw_gid);
76779045f13Schristos 			return 0;
76879045f13Schristos 		}
7691f68464dSchristos 	return 1;
7701f68464dSchristos }
7711f68464dSchristos 
7721f68464dSchristos static int
7731f68464dSchristos set_user_ids(void)
7741f68464dSchristos {
77579045f13Schristos 	if (user && setuid(sw_uid)) {
77679045f13Schristos 		msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user);
77779045f13Schristos 		return 0;
77879045f13Schristos 	}
77979045f13Schristos 	if (user && seteuid(sw_uid)) {
78079045f13Schristos 		msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user);
78179045f13Schristos 		return 0;
78279045f13Schristos 	}
7831f68464dSchristos 	return 1;
7841f68464dSchristos }
7851f68464dSchristos 
7861f68464dSchristos /*
7871f68464dSchristos  * Change (effective) user and group IDs, also initialize the supplementary group access list
7881f68464dSchristos  */
7891f68464dSchristos int set_user_group_ids(void);
7901f68464dSchristos int
7911f68464dSchristos set_user_group_ids(void)
7921f68464dSchristos {
7931f68464dSchristos 	/* If the the user was already mapped, no need to map it again */
7941f68464dSchristos 	if ((NULL != user) && (0 == sw_uid)) {
7951f68464dSchristos 		if (0 == map_user())
7961f68464dSchristos 			exit (-1);
7971f68464dSchristos 	}
7981f68464dSchristos 	/* same applies for the group */
7991f68464dSchristos 	if ((NULL != group) && (0 == sw_gid)) {
8001f68464dSchristos 		if (0 == map_group())
8011f68464dSchristos 			exit (-1);
8021f68464dSchristos 	}
8031f68464dSchristos 
8041f68464dSchristos 	if (getegid() != sw_gid && 0 == set_group_ids())
8051f68464dSchristos 		return 0;
8061f68464dSchristos 	if (geteuid() != sw_uid && 0 == set_user_ids())
8071f68464dSchristos 		return 0;
80879045f13Schristos 
80979045f13Schristos 	return 1;
81079045f13Schristos }
81179045f13Schristos #endif /* HAVE_DROPROOT */
812abb0f93cSkardel 
813abb0f93cSkardel /*
814abb0f93cSkardel  * Main program.  Initialize us, disconnect us from the tty if necessary,
815abb0f93cSkardel  * and loop waiting for I/O and/or timer expiries.
816abb0f93cSkardel  */
8172950cc38Schristos #ifndef SIM
818abb0f93cSkardel int
819abb0f93cSkardel ntpdmain(
820abb0f93cSkardel 	int argc,
821abb0f93cSkardel 	char *argv[]
822abb0f93cSkardel 	)
823abb0f93cSkardel {
824abb0f93cSkardel 	l_fp		now;
825abb0f93cSkardel 	struct recvbuf *rbuf;
8262950cc38Schristos 	const char *	logfilename;
8272950cc38Schristos # ifdef HAVE_UMASK
8282950cc38Schristos 	mode_t		uv;
8292950cc38Schristos # endif
8302950cc38Schristos # if defined(HAVE_GETUID) && !defined(MPE) /* MPE lacks the concept of root */
8312950cc38Schristos 	uid_t		uid;
8322950cc38Schristos # endif
8332950cc38Schristos # if defined(HAVE_WORKING_FORK)
8342950cc38Schristos 	long		wait_sync = 0;
8352950cc38Schristos # endif	/* HAVE_WORKING_FORK*/
8362950cc38Schristos # ifdef SCO5_CLOCK
8372950cc38Schristos 	int		fd;
8382950cc38Schristos 	int		zero;
8392950cc38Schristos # endif
840abb0f93cSkardel 
841af12ab5eSchristos # ifdef NEED_PTHREAD_WARMUP
842af12ab5eSchristos 	my_pthread_warmup();
843af12ab5eSchristos # endif
844af12ab5eSchristos 
845abb0f93cSkardel # ifdef HAVE_UMASK
846abb0f93cSkardel 	uv = umask(0);
847abb0f93cSkardel 	if (uv)
8482950cc38Schristos 		umask(uv);
849abb0f93cSkardel 	else
8502950cc38Schristos 		umask(022);
8512950cc38Schristos # endif
8522950cc38Schristos 	saved_argc = argc;
8532950cc38Schristos 	saved_argv = argv;
8542950cc38Schristos 	progname = argv[0];
8552950cc38Schristos 	initializing = TRUE;		/* mark that we are initializing */
8562950cc38Schristos 	parse_cmdline_opts(&argc, &argv);
8572950cc38Schristos # ifdef DEBUG
8582950cc38Schristos 	debug = OPT_VALUE_SET_DEBUG_LEVEL;
8592950cc38Schristos #  ifdef HAVE_SETLINEBUF
8602950cc38Schristos 	setlinebuf(stdout);
8612950cc38Schristos #  endif
862abb0f93cSkardel # endif
863abb0f93cSkardel 
8642950cc38Schristos 	if (HAVE_OPT(NOFORK) || HAVE_OPT(QUIT)
8652950cc38Schristos # ifdef DEBUG
8662950cc38Schristos 	    || debug
8672950cc38Schristos # endif
8682950cc38Schristos 	    || HAVE_OPT(SAVECONFIGQUIT))
8692950cc38Schristos 		nofork = TRUE;
870abb0f93cSkardel 
8712950cc38Schristos 	init_logging(progname, NLOG_SYNCMASK, TRUE);
8722950cc38Schristos 	/* honor -l/--logfile option to log to a file */
8732950cc38Schristos 	if (HAVE_OPT(LOGFILE)) {
8742950cc38Schristos 		logfilename = OPT_ARG(LOGFILE);
8752950cc38Schristos 		syslogit = FALSE;
8762950cc38Schristos 		change_logfile(logfilename, FALSE);
8772950cc38Schristos 	} else {
8782950cc38Schristos 		logfilename = NULL;
8792950cc38Schristos 		if (nofork)
8802950cc38Schristos 			msyslog_term = TRUE;
8812950cc38Schristos 		if (HAVE_OPT(SAVECONFIGQUIT))
8822950cc38Schristos 			syslogit = FALSE;
8832950cc38Schristos 	}
8842950cc38Schristos 	msyslog(LOG_NOTICE, "%s: Starting", Version);
8852950cc38Schristos 
8862950cc38Schristos 	{
8872950cc38Schristos 		int i;
8882950cc38Schristos 		char buf[1024];	/* Secret knowledge of msyslog buf length */
8892950cc38Schristos 		char *cp = buf;
8902950cc38Schristos 
8912950cc38Schristos 		/* Note that every arg has an initial space character */
8922950cc38Schristos 		snprintf(cp, sizeof(buf), "Command line:");
8932950cc38Schristos 		cp += strlen(cp);
8942950cc38Schristos 
8952950cc38Schristos 		for (i = 0; i < saved_argc ; ++i) {
8962950cc38Schristos 			snprintf(cp, sizeof(buf) - (cp - buf),
8972950cc38Schristos 				" %s", saved_argv[i]);
8982950cc38Schristos 			cp += strlen(cp);
8992950cc38Schristos 		}
900cdfa2a7eSchristos 		msyslog(LOG_NOTICE, "%s", buf);
9012950cc38Schristos 	}
9022950cc38Schristos 
903cdfa2a7eSchristos 	msyslog(LOG_NOTICE, "----------------------------------------------------");
904cdfa2a7eSchristos 	msyslog(LOG_NOTICE, "ntp-4 is maintained by Network Time Foundation,");
905cdfa2a7eSchristos 	msyslog(LOG_NOTICE, "Inc. (NTF), a non-profit 501(c)(3) public-benefit");
906cdfa2a7eSchristos 	msyslog(LOG_NOTICE, "corporation.  Support and training for ntp-4 are");
907cdfa2a7eSchristos 	msyslog(LOG_NOTICE, "available at https://www.nwtime.org/support");
908cdfa2a7eSchristos 	msyslog(LOG_NOTICE, "----------------------------------------------------");
909*eabc0478Schristos #ifdef DEBUG
910*eabc0478Schristos 	msyslog(LOG_NOTICE, "DEBUG behavior is enabled - a violation of any"
911*eabc0478Schristos 			    " diagnostic assertion will cause %s to abort",
912*eabc0478Schristos 			    progname);
913*eabc0478Schristos #endif
914*eabc0478Schristos 
915*eabc0478Schristos 	ssl_check_version();
916cdfa2a7eSchristos 
9172950cc38Schristos 	/*
9182950cc38Schristos 	 * Install trap handlers to log errors and assertion failures.
9192950cc38Schristos 	 * Default handlers print to stderr which doesn't work if detached.
9202950cc38Schristos 	 */
9212950cc38Schristos 	isc_assertion_setcallback(assertion_failed);
9222950cc38Schristos 	isc_error_setfatal(library_fatal_error);
9232950cc38Schristos 	isc_error_setunexpected(library_unexpected_error);
9242950cc38Schristos 
9252950cc38Schristos 	/* MPE lacks the concept of root */
9262950cc38Schristos # if defined(HAVE_GETUID) && !defined(MPE)
927abb0f93cSkardel 	uid = getuid();
92879045f13Schristos 	if (uid && !HAVE_OPT( SAVECONFIGQUIT )
92979045f13Schristos #  if defined(HAVE_TRUSTEDBSD_MAC)
93079045f13Schristos 	    /* We can run as non-root if the mac_ntpd policy is enabled. */
93179045f13Schristos 	    && mac_is_present("ntpd") != 1
93279045f13Schristos #  endif
93379045f13Schristos 	    ) {
9342950cc38Schristos 		msyslog_term = TRUE;
9352950cc38Schristos 		msyslog(LOG_ERR,
9362950cc38Schristos 			"must be run as root, not uid %ld", (long)uid);
937abb0f93cSkardel 		exit(1);
938abb0f93cSkardel 	}
939abb0f93cSkardel # endif
940abb0f93cSkardel 
941abb0f93cSkardel /*
942abb0f93cSkardel  * Enable the Multi-Media Timer for Windows?
943abb0f93cSkardel  */
944abb0f93cSkardel # ifdef SYS_WINNT
945abb0f93cSkardel 	if (HAVE_OPT( MODIFYMMTIMER ))
946abb0f93cSkardel 		set_mm_timer(MM_TIMER_HIRES);
947abb0f93cSkardel # endif
948abb0f93cSkardel 
9492950cc38Schristos #ifdef HAVE_DNSREGISTRATION
9502950cc38Schristos /*
9512950cc38Schristos  * Enable mDNS registrations?
9522950cc38Schristos  */
9532950cc38Schristos 	if (HAVE_OPT( MDNS )) {
9542950cc38Schristos 		mdnsreg = TRUE;
9552950cc38Schristos 	}
9562950cc38Schristos #endif  /* HAVE_DNSREGISTRATION */
957abb0f93cSkardel 
958abb0f93cSkardel 	if (HAVE_OPT( NOVIRTUALIPS ))
959abb0f93cSkardel 		listen_to_virtual_ips = 0;
960abb0f93cSkardel 
961abb0f93cSkardel 	/*
962abb0f93cSkardel 	 * --interface, listen on specified interfaces
963abb0f93cSkardel 	 */
964abb0f93cSkardel 	if (HAVE_OPT( INTERFACE )) {
965abb0f93cSkardel 		int		ifacect = STACKCT_OPT( INTERFACE );
966abb0f93cSkardel 		const char**	ifaces  = STACKLST_OPT( INTERFACE );
9673123f114Skardel 		sockaddr_u	addr;
968abb0f93cSkardel 
969abb0f93cSkardel 		while (ifacect-- > 0) {
970abb0f93cSkardel 			add_nic_rule(
9712950cc38Schristos 				is_ip_address(*ifaces, AF_UNSPEC, &addr)
972abb0f93cSkardel 					? MATCH_IFADDR
973abb0f93cSkardel 					: MATCH_IFNAME,
974abb0f93cSkardel 				*ifaces, -1, ACTION_LISTEN);
975abb0f93cSkardel 			ifaces++;
976abb0f93cSkardel 		}
977abb0f93cSkardel 	}
978abb0f93cSkardel 
979abb0f93cSkardel 	if (HAVE_OPT( NICE ))
980abb0f93cSkardel 		priority_done = 0;
981abb0f93cSkardel 
9822950cc38Schristos # ifdef HAVE_SCHED_SETSCHEDULER
983abb0f93cSkardel 	if (HAVE_OPT( PRIORITY )) {
984abb0f93cSkardel 		config_priority = OPT_VALUE_PRIORITY;
985abb0f93cSkardel 		config_priority_override = 1;
986abb0f93cSkardel 		priority_done = 0;
987abb0f93cSkardel 	}
988abb0f93cSkardel # endif
989abb0f93cSkardel 
9902950cc38Schristos # ifdef HAVE_WORKING_FORK
991cdfa2a7eSchristos 	/* make sure the FDs are initialised
992cdfa2a7eSchristos 	 *
993cdfa2a7eSchristos 	 * note: if WAIT_SYNC is requested, we *have* to fork. This will
994cdfa2a7eSchristos 	 * overide any '-n' (nofork) or '-d' (debug) option presented on
995cdfa2a7eSchristos 	 * the command line!
996cdfa2a7eSchristos 	 */
997cdfa2a7eSchristos 	if (HAVE_OPT(WAIT_SYNC)) {
9982950cc38Schristos 		wait_sync = OPT_VALUE_WAIT_SYNC;
999cdfa2a7eSchristos 		if (wait_sync <= 0)
10002950cc38Schristos 			wait_sync = 0;
1001cdfa2a7eSchristos 		else
10022950cc38Schristos 			nofork = FALSE;
10032950cc38Schristos 	}
1004cdfa2a7eSchristos 	if ( !nofork && pipe(daemon_pipe)) {
1005cdfa2a7eSchristos 		msyslog(LOG_ERR,
1006cdfa2a7eSchristos 			"Pipe creation failed for --wait-sync/daemon: %m");
1007cdfa2a7eSchristos 		exit(EX_OSERR);
1008cdfa2a7eSchristos 	}
10092950cc38Schristos # endif	/* HAVE_WORKING_FORK */
10102950cc38Schristos 
10112950cc38Schristos 	init_lib();
1012abb0f93cSkardel # ifdef SYS_WINNT
1013abb0f93cSkardel 	/*
101479045f13Schristos 	 * Make sure the service is initialized before we do anything else
101579045f13Schristos 	 */
101679045f13Schristos 	ntservice_init();
101779045f13Schristos 
101879045f13Schristos 	/*
1019abb0f93cSkardel 	 * Start interpolation thread, must occur before first
1020abb0f93cSkardel 	 * get_systime()
1021abb0f93cSkardel 	 */
1022abb0f93cSkardel 	init_winnt_time();
1023abb0f93cSkardel # endif
1024abb0f93cSkardel 	/*
1025abb0f93cSkardel 	 * Initialize random generator and public key pair
1026abb0f93cSkardel 	 */
1027abb0f93cSkardel 	get_systime(&now);
1028abb0f93cSkardel 
1029abb0f93cSkardel 	ntp_srandom((int)(now.l_i * now.l_uf));
1030abb0f93cSkardel 
1031abb0f93cSkardel 	/*
1032abb0f93cSkardel 	 * Detach us from the terminal.  May need an #ifndef GIZMO.
1033abb0f93cSkardel 	 */
10342950cc38Schristos # ifdef HAVE_WORKING_FORK
1035cdfa2a7eSchristos 	if (!nofork) {
1036cdfa2a7eSchristos 		detach_from_terminal(daemon_pipe, wait_sync, logfilename);
1037abb0f93cSkardel 	}
1038cdfa2a7eSchristos # endif		/* HAVE_WORKING_FORK */
1039abb0f93cSkardel 
1040abb0f93cSkardel # ifdef SCO5_CLOCK
1041abb0f93cSkardel 	/*
1042abb0f93cSkardel 	 * SCO OpenServer's system clock offers much more precise timekeeping
1043abb0f93cSkardel 	 * on the base CPU than the other CPUs (for multiprocessor systems),
1044abb0f93cSkardel 	 * so we must lock to the base CPU.
1045abb0f93cSkardel 	 */
10462950cc38Schristos 	fd = open("/dev/at1", O_RDONLY);
1047abb0f93cSkardel 	if (fd >= 0) {
10482950cc38Schristos 		zero = 0;
1049abb0f93cSkardel 		if (ioctl(fd, ACPU_LOCK, &zero) < 0)
1050abb0f93cSkardel 			msyslog(LOG_ERR, "cannot lock to base CPU: %m");
1051abb0f93cSkardel 		close(fd);
1052abb0f93cSkardel 	}
1053abb0f93cSkardel # endif
1054abb0f93cSkardel 
10552950cc38Schristos 	/* Setup stack size in preparation for locking pages in memory. */
10562950cc38Schristos # if defined(HAVE_MLOCKALL)
1057abb0f93cSkardel #  ifdef HAVE_SETRLIMIT
10582950cc38Schristos 	ntp_rlimit(RLIMIT_STACK, DFLT_RLIMIT_STACK * 4096, 4096, "4k");
1059abb0f93cSkardel #   ifdef RLIMIT_MEMLOCK
1060abb0f93cSkardel 	/*
1061abb0f93cSkardel 	 * The default RLIMIT_MEMLOCK is very low on Linux systems.
1062abb0f93cSkardel 	 * Unless we increase this limit malloc calls are likely to
10632950cc38Schristos 	 * fail if we drop root privilege.  To be useful the value
1064abb0f93cSkardel 	 * has to be larger than the largest ntpd resident set size.
1065abb0f93cSkardel 	 */
10662950cc38Schristos 	ntp_rlimit(RLIMIT_MEMLOCK, DFLT_RLIMIT_MEMLOCK * 1024 * 1024, 1024 * 1024, "MB");
1067abb0f93cSkardel #   endif	/* RLIMIT_MEMLOCK */
1068abb0f93cSkardel #  endif	/* HAVE_SETRLIMIT */
10692950cc38Schristos # else	/* !HAVE_MLOCKALL follows */
1070abb0f93cSkardel #  ifdef HAVE_PLOCK
1071abb0f93cSkardel #   ifdef PROCLOCK
1072abb0f93cSkardel #    ifdef _AIX
1073abb0f93cSkardel 	/*
1074abb0f93cSkardel 	 * set the stack limit for AIX for plock().
1075abb0f93cSkardel 	 * see get_aix_stack() for more info.
1076abb0f93cSkardel 	 */
1077abb0f93cSkardel 	if (ulimit(SET_STACKLIM, (get_aix_stack() - 8 * 4096)) < 0)
10782950cc38Schristos 		msyslog(LOG_ERR,
10792950cc38Schristos 			"Cannot adjust stack limit for plock: %m");
1080abb0f93cSkardel #    endif	/* _AIX */
10812950cc38Schristos #   endif	/* PROCLOCK */
1082abb0f93cSkardel #  endif	/* HAVE_PLOCK */
10832950cc38Schristos # endif	/* !HAVE_MLOCKALL */
1084abb0f93cSkardel 
1085abb0f93cSkardel 	/*
1086abb0f93cSkardel 	 * Set up signals we pay attention to locally.
1087abb0f93cSkardel 	 */
1088abb0f93cSkardel # ifdef SIGDIE1
10892950cc38Schristos 	signal_no_reset(SIGDIE1, finish);
10902950cc38Schristos 	signal_no_reset(SIGDIE2, finish);
10912950cc38Schristos 	signal_no_reset(SIGDIE3, finish);
10922950cc38Schristos 	signal_no_reset(SIGDIE4, finish);
10932950cc38Schristos # endif
1094abb0f93cSkardel # ifdef SIGBUS
10952950cc38Schristos 	signal_no_reset(SIGBUS, finish);
10962950cc38Schristos # endif
1097abb0f93cSkardel 
1098abb0f93cSkardel # if !defined(SYS_WINNT) && !defined(VMS)
1099abb0f93cSkardel #  ifdef DEBUG
1100abb0f93cSkardel 	(void) signal_no_reset(MOREDEBUGSIG, moredebug);
1101abb0f93cSkardel 	(void) signal_no_reset(LESSDEBUGSIG, lessdebug);
1102abb0f93cSkardel #  else
1103abb0f93cSkardel 	(void) signal_no_reset(MOREDEBUGSIG, no_debug);
1104abb0f93cSkardel 	(void) signal_no_reset(LESSDEBUGSIG, no_debug);
1105abb0f93cSkardel #  endif	/* DEBUG */
1106abb0f93cSkardel # endif	/* !SYS_WINNT && !VMS */
1107abb0f93cSkardel 
1108abb0f93cSkardel 	/*
1109abb0f93cSkardel 	 * Set up signals we should never pay attention to.
1110abb0f93cSkardel 	 */
11112950cc38Schristos # ifdef SIGPIPE
11122950cc38Schristos 	signal_no_reset(SIGPIPE, SIG_IGN);
11132950cc38Schristos # endif
1114abb0f93cSkardel 
1115abb0f93cSkardel 	/*
1116abb0f93cSkardel 	 * Call the init_ routines to initialize the data structures.
1117abb0f93cSkardel 	 *
1118abb0f93cSkardel 	 * Exactly what command-line options are we expecting here?
1119abb0f93cSkardel 	 */
11202950cc38Schristos 	INIT_SSL();
1121abb0f93cSkardel 	init_auth();
1122abb0f93cSkardel 	init_util();
1123abb0f93cSkardel 	init_restrict();
1124abb0f93cSkardel 	init_mon();
1125abb0f93cSkardel 	init_timer();
1126abb0f93cSkardel 	init_request();
1127abb0f93cSkardel 	init_control();
1128abb0f93cSkardel 	init_peer();
1129abb0f93cSkardel # ifdef REFCLOCK
1130abb0f93cSkardel 	init_refclock();
1131abb0f93cSkardel # endif
1132abb0f93cSkardel 	set_process_priority();
1133abb0f93cSkardel 	init_proto();		/* Call at high priority */
1134abb0f93cSkardel 	init_io();
1135abb0f93cSkardel 	init_loopfilter();
1136abb0f93cSkardel 	mon_start(MON_ON);	/* monitor on by default now	  */
1137abb0f93cSkardel 				/* turn off in config if unwanted */
1138abb0f93cSkardel 
1139abb0f93cSkardel 	/*
1140abb0f93cSkardel 	 * Get the configuration.  This is done in a separate module
1141abb0f93cSkardel 	 * since this will definitely be different for the gizmo board.
1142abb0f93cSkardel 	 */
1143abb0f93cSkardel 	getconfig(argc, argv);
11442950cc38Schristos 
1145af12ab5eSchristos 	if (-1 == cur_memlock) {
11462950cc38Schristos # if defined(HAVE_MLOCKALL)
11472950cc38Schristos 		/*
11482950cc38Schristos 		 * lock the process into memory
11492950cc38Schristos 		 */
1150af12ab5eSchristos 		if (   !HAVE_OPT(SAVECONFIGQUIT)
1151af12ab5eSchristos #  ifdef RLIMIT_MEMLOCK
1152af12ab5eSchristos 		    && -1 != DFLT_RLIMIT_MEMLOCK
1153af12ab5eSchristos #  endif
1154af12ab5eSchristos 		    && 0 != mlockall(MCL_CURRENT|MCL_FUTURE))
11552950cc38Schristos 			msyslog(LOG_ERR, "mlockall(): %m");
11562950cc38Schristos # else	/* !HAVE_MLOCKALL follows */
11572950cc38Schristos #  ifdef HAVE_PLOCK
11582950cc38Schristos #   ifdef PROCLOCK
11592950cc38Schristos 		/*
11602950cc38Schristos 		 * lock the process into memory
11612950cc38Schristos 		 */
11622950cc38Schristos 		if (!HAVE_OPT(SAVECONFIGQUIT) && 0 != plock(PROCLOCK))
11632950cc38Schristos 			msyslog(LOG_ERR, "plock(PROCLOCK): %m");
11642950cc38Schristos #   else	/* !PROCLOCK follows  */
11652950cc38Schristos #    ifdef TXTLOCK
11662950cc38Schristos 		/*
11672950cc38Schristos 		 * Lock text into ram
11682950cc38Schristos 		 */
11692950cc38Schristos 		if (!HAVE_OPT(SAVECONFIGQUIT) && 0 != plock(TXTLOCK))
11702950cc38Schristos 			msyslog(LOG_ERR, "plock(TXTLOCK) error: %m");
11712950cc38Schristos #    else	/* !TXTLOCK follows */
11722950cc38Schristos 		msyslog(LOG_ERR, "plock() - don't know what to lock!");
11732950cc38Schristos #    endif	/* !TXTLOCK */
11742950cc38Schristos #   endif	/* !PROCLOCK */
11752950cc38Schristos #  endif	/* HAVE_PLOCK */
11762950cc38Schristos # endif	/* !HAVE_MLOCKALL */
11772950cc38Schristos 	}
11782950cc38Schristos 
11792950cc38Schristos 	loop_config(LOOP_DRIFTINIT, 0);
1180abb0f93cSkardel 	report_event(EVNT_SYSRESTART, NULL, NULL);
11812950cc38Schristos 	initializing = FALSE;
1182abb0f93cSkardel 
1183cdfa2a7eSchristos # ifdef HAVE_LINUX_CAPABILITIES
1184cdfa2a7eSchristos 	{
1185cdfa2a7eSchristos 		/*  Check that setting capabilities actually works; we might be
1186cdfa2a7eSchristos 		 *  run on a kernel with disabled capabilities. We must not
1187cdfa2a7eSchristos 		 *  drop privileges in this case.
1188cdfa2a7eSchristos 		 */
1189cdfa2a7eSchristos 		cap_t caps;
1190cdfa2a7eSchristos 		caps = cap_from_text("cap_sys_time,cap_setuid,cap_setgid,cap_sys_chroot,cap_net_bind_service=pe");
1191cdfa2a7eSchristos 		if ( ! caps) {
1192cdfa2a7eSchristos 			msyslog( LOG_ERR, "cap_from_text() failed: %m" );
1193cdfa2a7eSchristos 			exit(-1);
1194cdfa2a7eSchristos 		}
1195cdfa2a7eSchristos 		have_caps = (cap_set_proc(caps) == 0);
1196cdfa2a7eSchristos 		cap_free(caps);	/* caps not NULL here! */
1197cdfa2a7eSchristos 	}
1198cdfa2a7eSchristos # endif /* HAVE_LINUX_CAPABILITIES */
1199cdfa2a7eSchristos 
1200abb0f93cSkardel # ifdef HAVE_DROPROOT
1201cdfa2a7eSchristos #  ifdef HAVE_LINUX_CAPABILITIES
1202cdfa2a7eSchristos 	if (droproot && have_caps) {
1203cdfa2a7eSchristos #  else
1204abb0f93cSkardel 	if (droproot) {
1205cdfa2a7eSchristos #  endif /*HAVE_LINUX_CAPABILITIES*/
120668dbbb44Schristos 
120768dbbb44Schristos #  ifdef NEED_EARLY_FORK
120868dbbb44Schristos 		fork_nonchroot_worker();
120968dbbb44Schristos #  endif
121068dbbb44Schristos 
1211abb0f93cSkardel 		/* Drop super-user privileges and chroot now if the OS supports this */
1212abb0f93cSkardel 
1213abb0f93cSkardel #  ifdef HAVE_LINUX_CAPABILITIES
1214abb0f93cSkardel 		/* set flag: keep privileges accross setuid() call (we only really need cap_sys_time): */
1215abb0f93cSkardel 		if (prctl( PR_SET_KEEPCAPS, 1L, 0L, 0L, 0L ) == -1) {
1216abb0f93cSkardel 			msyslog( LOG_ERR, "prctl( PR_SET_KEEPCAPS, 1L ) failed: %m" );
1217abb0f93cSkardel 			exit(-1);
1218abb0f93cSkardel 		}
12192950cc38Schristos #  elif HAVE_SOLARIS_PRIVS
12202950cc38Schristos 		/* Nothing to do here */
1221abb0f93cSkardel #  else
1222abb0f93cSkardel 		/* we need a user to switch to */
1223abb0f93cSkardel 		if (user == NULL) {
1224abb0f93cSkardel 			msyslog(LOG_ERR, "Need user name to drop root privileges (see -u flag!)" );
1225abb0f93cSkardel 			exit(-1);
1226abb0f93cSkardel 		}
12272950cc38Schristos #  endif	/* HAVE_LINUX_CAPABILITIES || HAVE_SOLARIS_PRIVS */
1228abb0f93cSkardel 
1229abb0f93cSkardel 		if (user != NULL) {
123079045f13Schristos 			if (0 == map_user())
1231abb0f93cSkardel 				exit (-1);
1232abb0f93cSkardel 		}
1233abb0f93cSkardel 		if (group != NULL) {
123479045f13Schristos 			if (0 == map_group())
1235abb0f93cSkardel 				exit (-1);
1236abb0f93cSkardel 		}
1237abb0f93cSkardel 
1238abb0f93cSkardel 		if (chrootdir ) {
1239abb0f93cSkardel 			/* make sure cwd is inside the jail: */
1240abb0f93cSkardel 			if (chdir(chrootdir)) {
1241abb0f93cSkardel 				msyslog(LOG_ERR, "Cannot chdir() to `%s': %m", chrootdir);
1242abb0f93cSkardel 				exit (-1);
1243abb0f93cSkardel 			}
1244abb0f93cSkardel 			if (chroot(chrootdir)) {
1245abb0f93cSkardel 				msyslog(LOG_ERR, "Cannot chroot() to `%s': %m", chrootdir);
1246abb0f93cSkardel 				exit (-1);
1247abb0f93cSkardel 			}
1248abb0f93cSkardel 			if (chdir("/")) {
1249abb0f93cSkardel 				msyslog(LOG_ERR, "Cannot chdir() to`root after chroot(): %m");
1250abb0f93cSkardel 				exit (-1);
1251abb0f93cSkardel 			}
1252abb0f93cSkardel 		}
12532950cc38Schristos #  ifdef HAVE_SOLARIS_PRIVS
12542950cc38Schristos 		if ((lowprivs = priv_str_to_set(LOWPRIVS, ",", NULL)) == NULL) {
12552950cc38Schristos 			msyslog(LOG_ERR, "priv_str_to_set() failed:%m");
12562950cc38Schristos 			exit(-1);
12572950cc38Schristos 		}
12582950cc38Schristos 		if ((highprivs = priv_allocset()) == NULL) {
12592950cc38Schristos 			msyslog(LOG_ERR, "priv_allocset() failed:%m");
12602950cc38Schristos 			exit(-1);
12612950cc38Schristos 		}
12622950cc38Schristos 		(void) getppriv(PRIV_PERMITTED, highprivs);
12632950cc38Schristos 		(void) priv_intersect(highprivs, lowprivs);
12642950cc38Schristos 		if (setppriv(PRIV_SET, PRIV_PERMITTED, lowprivs) == -1) {
12652950cc38Schristos 			msyslog(LOG_ERR, "setppriv() failed:%m");
12662950cc38Schristos 			exit(-1);
12672950cc38Schristos 		}
12682950cc38Schristos #  endif /* HAVE_SOLARIS_PRIVS */
126979045f13Schristos 		if (0 == set_user_group_ids())
1270abb0f93cSkardel 			exit(-1);
1271abb0f93cSkardel 
127279045f13Schristos #  if defined(HAVE_TRUSTEDBSD_MAC)
127379045f13Schristos 		/*
127479045f13Schristos 		 * To manipulate system time and (re-)bind to NTP_PORT as needed
127579045f13Schristos 		 * following interface changes, we must either run as uid 0 or
127679045f13Schristos 		 * the mac_ntpd policy module must be enabled.
127779045f13Schristos 		 */
127879045f13Schristos 		if (sw_uid != 0 && mac_is_present("ntpd") != 1) {
127979045f13Schristos 			msyslog(LOG_ERR, "Need MAC 'ntpd' policy enabled to drop root privileges");
128079045f13Schristos 			exit (-1);
128179045f13Schristos 		}
128279045f13Schristos #  elif !defined(HAVE_LINUX_CAPABILITIES) && !defined(HAVE_SOLARIS_PRIVS)
1283abb0f93cSkardel 		/*
1284abb0f93cSkardel 		 * for now assume that the privilege to bind to privileged ports
1285abb0f93cSkardel 		 * is associated with running with uid 0 - should be refined on
1286abb0f93cSkardel 		 * ports that allow binding to NTP_PORT with uid != 0
1287abb0f93cSkardel 		 */
1288*eabc0478Schristos 		scan_addrs_once |= (sw_uid != 0);  /* used by routing socket code */
12892950cc38Schristos #  endif /* !HAVE_LINUX_CAPABILITIES && !HAVE_SOLARIS_PRIVS */
1290abb0f93cSkardel 
1291*eabc0478Schristos 		if (scan_addrs_once) {
12922950cc38Schristos 			msyslog(LOG_INFO, "running as non-root disables dynamic interface tracking");
1293abb0f93cSkardel 		}
1294abb0f93cSkardel 
1295abb0f93cSkardel #  ifdef HAVE_LINUX_CAPABILITIES
12962950cc38Schristos 		{
1297abb0f93cSkardel 			/*
1298abb0f93cSkardel 			 *  We may be running under non-root uid now, but we still hold full root privileges!
1299abb0f93cSkardel 			 *  We drop all of them, except for the crucial one or two: cap_sys_time and
1300abb0f93cSkardel 			 *  cap_net_bind_service if doing dynamic interface tracking.
1301abb0f93cSkardel 			 */
1302abb0f93cSkardel 			cap_t caps;
13032950cc38Schristos 			char *captext;
13042950cc38Schristos 
1305*eabc0478Schristos 			captext = (scan_addrs_once)
1306*eabc0478Schristos 				    ? "cap_sys_time=pe"
1307*eabc0478Schristos 				    : "cap_sys_time,cap_net_bind_service=pe";
13082950cc38Schristos 			caps = cap_from_text(captext);
13092950cc38Schristos 			if (!caps) {
13102950cc38Schristos 				msyslog(LOG_ERR,
13112950cc38Schristos 					"cap_from_text(%s) failed: %m",
13122950cc38Schristos 					captext);
1313abb0f93cSkardel 				exit(-1);
1314abb0f93cSkardel 			}
13152950cc38Schristos 			if (-1 == cap_set_proc(caps)) {
13162950cc38Schristos 				msyslog(LOG_ERR,
13172950cc38Schristos 					"cap_set_proc() failed to drop root privs: %m");
1318abb0f93cSkardel 				exit(-1);
1319abb0f93cSkardel 			}
1320abb0f93cSkardel 			cap_free(caps);
13212950cc38Schristos 		}
1322abb0f93cSkardel #  endif	/* HAVE_LINUX_CAPABILITIES */
13232950cc38Schristos #  ifdef HAVE_SOLARIS_PRIVS
13242950cc38Schristos 		if (priv_delset(lowprivs, "proc_setid") == -1) {
13252950cc38Schristos 			msyslog(LOG_ERR, "priv_delset() failed:%m");
13262950cc38Schristos 			exit(-1);
13272950cc38Schristos 		}
13282950cc38Schristos 		if (setppriv(PRIV_SET, PRIV_PERMITTED, lowprivs) == -1) {
13292950cc38Schristos 			msyslog(LOG_ERR, "setppriv() failed:%m");
13302950cc38Schristos 			exit(-1);
13312950cc38Schristos 		}
13322950cc38Schristos 		priv_freeset(lowprivs);
13332950cc38Schristos 		priv_freeset(highprivs);
13342950cc38Schristos #  endif /* HAVE_SOLARIS_PRIVS */
13352950cc38Schristos 		root_dropped = TRUE;
13362950cc38Schristos 		fork_deferred_worker();
1337abb0f93cSkardel 	}	/* if (droproot) */
1338abb0f93cSkardel # endif	/* HAVE_DROPROOT */
1339abb0f93cSkardel 
1340ea66d795Schristos /* libssecomp sandboxing */
1341ea66d795Schristos #if defined (LIBSECCOMP) && (KERN_SECCOMP)
1342ea66d795Schristos 	scmp_filter_ctx ctx;
1343ea66d795Schristos 
1344ea66d795Schristos 	if ((ctx = seccomp_init(SCMP_ACT_KILL)) < 0)
1345ea66d795Schristos 		msyslog(LOG_ERR, "%s: seccomp_init(SCMP_ACT_KILL) failed: %m", __func__);
1346ea66d795Schristos 	else {
1347ea66d795Schristos 		msyslog(LOG_DEBUG, "%s: seccomp_init(SCMP_ACT_KILL) succeeded", __func__);
1348ea66d795Schristos 	}
1349ea66d795Schristos 
1350ea66d795Schristos #ifdef __x86_64__
1351ea66d795Schristos int scmp_sc[] = {
1352ea66d795Schristos 	SCMP_SYS(adjtimex),
1353ea66d795Schristos 	SCMP_SYS(bind),
1354ea66d795Schristos 	SCMP_SYS(brk),
1355ea66d795Schristos 	SCMP_SYS(chdir),
1356ea66d795Schristos 	SCMP_SYS(clock_gettime),
1357ea66d795Schristos 	SCMP_SYS(clock_settime),
1358ea66d795Schristos 	SCMP_SYS(close),
1359ea66d795Schristos 	SCMP_SYS(connect),
1360ea66d795Schristos 	SCMP_SYS(exit_group),
1361ea66d795Schristos 	SCMP_SYS(fstat),
1362ea66d795Schristos 	SCMP_SYS(fsync),
1363ea66d795Schristos 	SCMP_SYS(futex),
1364ea66d795Schristos 	SCMP_SYS(getitimer),
1365ea66d795Schristos 	SCMP_SYS(getsockname),
1366ea66d795Schristos 	SCMP_SYS(ioctl),
1367ea66d795Schristos 	SCMP_SYS(lseek),
1368ea66d795Schristos 	SCMP_SYS(madvise),
1369ea66d795Schristos 	SCMP_SYS(mmap),
1370ea66d795Schristos 	SCMP_SYS(munmap),
1371ea66d795Schristos 	SCMP_SYS(open),
1372ea66d795Schristos 	SCMP_SYS(poll),
1373ea66d795Schristos 	SCMP_SYS(read),
1374ea66d795Schristos 	SCMP_SYS(recvmsg),
1375ea66d795Schristos 	SCMP_SYS(rename),
1376ea66d795Schristos 	SCMP_SYS(rt_sigaction),
1377ea66d795Schristos 	SCMP_SYS(rt_sigprocmask),
1378ea66d795Schristos 	SCMP_SYS(rt_sigreturn),
1379ea66d795Schristos 	SCMP_SYS(select),
1380ea66d795Schristos 	SCMP_SYS(sendto),
1381ea66d795Schristos 	SCMP_SYS(setitimer),
1382ea66d795Schristos 	SCMP_SYS(setsid),
1383ea66d795Schristos 	SCMP_SYS(socket),
1384ea66d795Schristos 	SCMP_SYS(stat),
1385ea66d795Schristos 	SCMP_SYS(time),
1386ea66d795Schristos 	SCMP_SYS(write),
1387ea66d795Schristos };
1388ea66d795Schristos #endif
1389ea66d795Schristos #ifdef __i386__
1390ea66d795Schristos int scmp_sc[] = {
1391ea66d795Schristos 	SCMP_SYS(_newselect),
1392ea66d795Schristos 	SCMP_SYS(adjtimex),
1393ea66d795Schristos 	SCMP_SYS(brk),
1394ea66d795Schristos 	SCMP_SYS(chdir),
1395ea66d795Schristos 	SCMP_SYS(clock_gettime),
1396ea66d795Schristos 	SCMP_SYS(clock_settime),
1397ea66d795Schristos 	SCMP_SYS(close),
1398ea66d795Schristos 	SCMP_SYS(exit_group),
1399ea66d795Schristos 	SCMP_SYS(fsync),
1400ea66d795Schristos 	SCMP_SYS(futex),
1401ea66d795Schristos 	SCMP_SYS(getitimer),
1402ea66d795Schristos 	SCMP_SYS(madvise),
1403ea66d795Schristos 	SCMP_SYS(mmap),
1404ea66d795Schristos 	SCMP_SYS(mmap2),
1405ea66d795Schristos 	SCMP_SYS(munmap),
1406ea66d795Schristos 	SCMP_SYS(open),
1407ea66d795Schristos 	SCMP_SYS(poll),
1408ea66d795Schristos 	SCMP_SYS(read),
1409ea66d795Schristos 	SCMP_SYS(rename),
1410ea66d795Schristos 	SCMP_SYS(rt_sigaction),
1411ea66d795Schristos 	SCMP_SYS(rt_sigprocmask),
1412ea66d795Schristos 	SCMP_SYS(select),
1413ea66d795Schristos 	SCMP_SYS(setitimer),
1414ea66d795Schristos 	SCMP_SYS(setsid),
1415ea66d795Schristos 	SCMP_SYS(sigprocmask),
1416ea66d795Schristos 	SCMP_SYS(sigreturn),
1417ea66d795Schristos 	SCMP_SYS(socketcall),
1418ea66d795Schristos 	SCMP_SYS(stat64),
1419ea66d795Schristos 	SCMP_SYS(time),
1420ea66d795Schristos 	SCMP_SYS(write),
1421ea66d795Schristos };
1422ea66d795Schristos #endif
1423ea66d795Schristos 	{
1424ea66d795Schristos 		int i;
1425ea66d795Schristos 
1426ea66d795Schristos 		for (i = 0; i < COUNTOF(scmp_sc); i++) {
1427ea66d795Schristos 			if (seccomp_rule_add(ctx,
1428ea66d795Schristos 			    SCMP_ACT_ALLOW, scmp_sc[i], 0) < 0) {
1429ea66d795Schristos 				msyslog(LOG_ERR,
1430ea66d795Schristos 				    "%s: seccomp_rule_add() failed: %m",
1431ea66d795Schristos 				    __func__);
1432ea66d795Schristos 			}
1433ea66d795Schristos 		}
1434ea66d795Schristos 	}
1435ea66d795Schristos 
1436ea66d795Schristos 	if (seccomp_load(ctx) < 0)
1437ea66d795Schristos 		msyslog(LOG_ERR, "%s: seccomp_load() failed: %m",
1438ea66d795Schristos 		    __func__);
1439ea66d795Schristos 	else {
1440ea66d795Schristos 		msyslog(LOG_DEBUG, "%s: seccomp_load() succeeded", __func__);
1441ea66d795Schristos 	}
1442ea66d795Schristos #endif /* LIBSECCOMP and KERN_SECCOMP */
1443ea66d795Schristos 
144479045f13Schristos 	ntservice_isup();
1445*eabc0478Schristos #if defined(HAVE_WORKING_FORK)
1446*eabc0478Schristos 	if (daemon_pipe[1] != -1 && 0 == wait_sync) {
1447*eabc0478Schristos 		if (2 != write(daemon_pipe[1], "R\n", 2)) {
1448*eabc0478Schristos 			msyslog(LOG_ERR, "daemon failed to notify parent ntpd after init");
1449*eabc0478Schristos 		}
1450*eabc0478Schristos 		close(daemon_pipe[1]);
1451*eabc0478Schristos 		daemon_pipe[1] = -1;
1452cdfa2a7eSchristos 	}
1453cdfa2a7eSchristos #endif /* HAVE_WORKING_FORK */
145479045f13Schristos 
1455*eabc0478Schristos 	if (scan_addrs_once || no_periodic_scan) {
1456*eabc0478Schristos 		endpt_scan_timer = 0;
1457*eabc0478Schristos 	}
1458*eabc0478Schristos 
1459cdfa2a7eSchristos # ifndef HAVE_IO_COMPLETION_PORT
1460abb0f93cSkardel 	BLOCK_IO_AND_ALARM();
14612950cc38Schristos 	was_alarmed = FALSE;
1462cdfa2a7eSchristos # endif
1463abb0f93cSkardel 
14642950cc38Schristos 	for (;;) {
146568dbbb44Schristos #if !defined(SIM) && defined(SIGDIE1)
146668dbbb44Schristos 		if (signalled)
146768dbbb44Schristos 			finish_safe(signo);
146868dbbb44Schristos #endif
1469cdfa2a7eSchristos # ifdef HAVE_IO_COMPLETION_PORT
1470cdfa2a7eSchristos 		GetReceivedBuffers();
1471cdfa2a7eSchristos 
1472cdfa2a7eSchristos # else /* normal I/O */
14732950cc38Schristos 		if (alarm_flag) {	/* alarmed? */
14742950cc38Schristos 			was_alarmed = TRUE;
14752950cc38Schristos 			alarm_flag = FALSE;
1476abb0f93cSkardel 		}
1477abb0f93cSkardel 
147868dbbb44Schristos 		/* collect async name/addr results */
147968dbbb44Schristos 		if (!was_alarmed)
148068dbbb44Schristos 		    harvest_blocking_responses();
148168dbbb44Schristos 
14822950cc38Schristos 		if (!was_alarmed && !has_full_recv_buffer()) {
1483abb0f93cSkardel 			/*
1484abb0f93cSkardel 			 * Nothing to do.  Wait for something.
1485abb0f93cSkardel 			 */
14862950cc38Schristos 			io_handler();
1487abb0f93cSkardel 		}
1488abb0f93cSkardel 
14892950cc38Schristos 		if (alarm_flag) {	/* alarmed? */
14902950cc38Schristos 			was_alarmed = TRUE;
14912950cc38Schristos 			alarm_flag = FALSE;
14922950cc38Schristos 		}
14932950cc38Schristos 
14942950cc38Schristos 		if (was_alarmed) {
1495abb0f93cSkardel 			UNBLOCK_IO_AND_ALARM();
1496abb0f93cSkardel 			/*
1497abb0f93cSkardel 			 * Out here, signals are unblocked.  Call timer routine
1498abb0f93cSkardel 			 * to process expiry.
1499abb0f93cSkardel 			 */
1500abb0f93cSkardel 			timer();
15012950cc38Schristos 			was_alarmed = FALSE;
1502abb0f93cSkardel 			BLOCK_IO_AND_ALARM();
1503abb0f93cSkardel 		}
1504abb0f93cSkardel 
1505abb0f93cSkardel # endif		/* !HAVE_IO_COMPLETION_PORT */
1506abb0f93cSkardel 
1507abb0f93cSkardel # ifdef DEBUG_TIMING
1508abb0f93cSkardel 		{
1509abb0f93cSkardel 			l_fp pts;
1510abb0f93cSkardel 			l_fp tsa, tsb;
1511abb0f93cSkardel 			int bufcount = 0;
1512abb0f93cSkardel 
1513abb0f93cSkardel 			get_systime(&pts);
1514abb0f93cSkardel 			tsa = pts;
1515abb0f93cSkardel # endif
1516abb0f93cSkardel 			rbuf = get_full_recv_buffer();
15172950cc38Schristos 			while (rbuf != NULL) {
15182950cc38Schristos 				if (alarm_flag) {
15192950cc38Schristos 					was_alarmed = TRUE;
15202950cc38Schristos 					alarm_flag = FALSE;
1521abb0f93cSkardel 				}
1522abb0f93cSkardel 				UNBLOCK_IO_AND_ALARM();
1523abb0f93cSkardel 
15242950cc38Schristos 				if (was_alarmed) {
15252950cc38Schristos 					/* avoid timer starvation during lengthy I/O handling */
1526abb0f93cSkardel 					timer();
15272950cc38Schristos 					was_alarmed = FALSE;
1528abb0f93cSkardel 				}
1529abb0f93cSkardel 
1530abb0f93cSkardel 				/*
1531abb0f93cSkardel 				 * Call the data procedure to handle each received
1532abb0f93cSkardel 				 * packet.
1533abb0f93cSkardel 				 */
15342950cc38Schristos 				if (rbuf->receiver != NULL) {
1535abb0f93cSkardel # ifdef DEBUG_TIMING
1536abb0f93cSkardel 					l_fp dts = pts;
1537abb0f93cSkardel 
1538abb0f93cSkardel 					L_SUB(&dts, &rbuf->recv_time);
1539abb0f93cSkardel 					DPRINTF(2, ("processing timestamp delta %s (with prec. fuzz)\n", lfptoa(&dts, 9)));
1540abb0f93cSkardel 					collect_timing(rbuf, "buffer processing delay", 1, &dts);
1541abb0f93cSkardel 					bufcount++;
1542abb0f93cSkardel # endif
15432950cc38Schristos 					(*rbuf->receiver)(rbuf);
1544abb0f93cSkardel 				} else {
15452950cc38Schristos 					msyslog(LOG_ERR, "fatal: receive buffer callback NULL");
1546abb0f93cSkardel 					abort();
1547abb0f93cSkardel 				}
1548abb0f93cSkardel 
1549abb0f93cSkardel 				BLOCK_IO_AND_ALARM();
1550abb0f93cSkardel 				freerecvbuf(rbuf);
1551abb0f93cSkardel 				rbuf = get_full_recv_buffer();
1552abb0f93cSkardel 			}
1553abb0f93cSkardel # ifdef DEBUG_TIMING
1554abb0f93cSkardel 			get_systime(&tsb);
1555abb0f93cSkardel 			L_SUB(&tsb, &tsa);
1556abb0f93cSkardel 			if (bufcount) {
1557abb0f93cSkardel 				collect_timing(NULL, "processing", bufcount, &tsb);
1558abb0f93cSkardel 				DPRINTF(2, ("processing time for %d buffers %s\n", bufcount, lfptoa(&tsb, 9)));
1559abb0f93cSkardel 			}
1560abb0f93cSkardel 		}
1561abb0f93cSkardel # endif
1562abb0f93cSkardel 
1563abb0f93cSkardel 		/*
1564abb0f93cSkardel 		 * Go around again
1565abb0f93cSkardel 		 */
1566abb0f93cSkardel 
1567abb0f93cSkardel # ifdef HAVE_DNSREGISTRATION
1568abb0f93cSkardel 		if (mdnsreg && (current_time - mdnsreg ) > 60 && mdnstries && sys_leap != LEAP_NOTINSYNC) {
1569abb0f93cSkardel 			mdnsreg = current_time;
15703b2862d1Schristos 			msyslog(LOG_INFO, "Attempting to register mDNS");
1571abb0f93cSkardel 			if ( DNSServiceRegister (&mdns, 0, 0, NULL, "_ntp._udp", NULL, NULL,
1572abb0f93cSkardel 			    htons(NTP_PORT), 0, NULL, NULL, NULL) != kDNSServiceErr_NoError ) {
1573abb0f93cSkardel 				if (!--mdnstries) {
1574abb0f93cSkardel 					msyslog(LOG_ERR, "Unable to register mDNS, giving up.");
1575abb0f93cSkardel 				} else {
1576abb0f93cSkardel 					msyslog(LOG_INFO, "Unable to register mDNS, will try later.");
1577abb0f93cSkardel 				}
1578abb0f93cSkardel 			} else {
1579abb0f93cSkardel 				msyslog(LOG_INFO, "mDNS service registered.");
15802950cc38Schristos 				mdnsreg = FALSE;
1581abb0f93cSkardel 			}
1582abb0f93cSkardel 		}
1583abb0f93cSkardel # endif /* HAVE_DNSREGISTRATION */
1584abb0f93cSkardel 
1585abb0f93cSkardel 	}
1586abb0f93cSkardel 	UNBLOCK_IO_AND_ALARM();
1587abb0f93cSkardel 	return 1;
1588abb0f93cSkardel }
15892950cc38Schristos #endif	/* !SIM */
1590abb0f93cSkardel 
1591abb0f93cSkardel 
15922950cc38Schristos #if !defined(SIM) && defined(SIGDIE1)
1593abb0f93cSkardel /*
1594abb0f93cSkardel  * finish - exit gracefully
1595abb0f93cSkardel  */
159668dbbb44Schristos static void
159768dbbb44Schristos finish_safe(
1598abb0f93cSkardel 	int	sig
1599abb0f93cSkardel 	)
1600abb0f93cSkardel {
16012950cc38Schristos 	const char *sig_desc;
16022950cc38Schristos 
16032950cc38Schristos 	sig_desc = NULL;
16042950cc38Schristos #ifdef HAVE_STRSIGNAL
16052950cc38Schristos 	sig_desc = strsignal(sig);
16062950cc38Schristos #endif
16072950cc38Schristos 	if (sig_desc == NULL)
16082950cc38Schristos 		sig_desc = "";
16092950cc38Schristos 	msyslog(LOG_NOTICE, "%s exiting on signal %d (%s)", progname,
16102950cc38Schristos 		sig, sig_desc);
1611ea66d795Schristos 	/* See Bug 2513 and Bug 2522 re the unlink of PIDFILE */
1612abb0f93cSkardel # ifdef HAVE_DNSREGISTRATION
1613abb0f93cSkardel 	if (mdns != NULL)
1614abb0f93cSkardel 		DNSServiceRefDeallocate(mdns);
1615abb0f93cSkardel # endif
16167476e6e4Schristos 	peer_cleanup();
1617abb0f93cSkardel 	exit(0);
1618abb0f93cSkardel }
161968dbbb44Schristos 
162068dbbb44Schristos static RETSIGTYPE
162168dbbb44Schristos finish(
162268dbbb44Schristos 	int	sig
162368dbbb44Schristos 	)
162468dbbb44Schristos {
162568dbbb44Schristos 	signalled = 1;
162668dbbb44Schristos 	signo = sig;
162768dbbb44Schristos }
162868dbbb44Schristos 
16292950cc38Schristos #endif	/* !SIM && SIGDIE1 */
1630abb0f93cSkardel 
1631abb0f93cSkardel 
16322950cc38Schristos #ifndef SIM
16332950cc38Schristos /*
16342950cc38Schristos  * wait_child_sync_if - implements parent side of -w/--wait-sync
1635abb0f93cSkardel  */
16362950cc38Schristos # ifdef HAVE_WORKING_FORK
1637cdfa2a7eSchristos 
16382950cc38Schristos static int
16392950cc38Schristos wait_child_sync_if(
16402950cc38Schristos 	int		pipe_read_fd,
1641cdfa2a7eSchristos 	unsigned long	wait_sync
16422950cc38Schristos 	)
16432950cc38Schristos {
16442950cc38Schristos 	int	rc;
1645cdfa2a7eSchristos 	char	ch;
16462950cc38Schristos 	time_t	wait_end_time;
16472950cc38Schristos 	time_t	cur_time;
16482950cc38Schristos 	time_t	wait_rem;
16492950cc38Schristos 	fd_set	readset;
16502950cc38Schristos 	struct timeval wtimeout;
16512950cc38Schristos 
1652cdfa2a7eSchristos 	/* we wait a bit for the child in *any* case, because on failure
1653cdfa2a7eSchristos 	 * of the child we have to get and inspect the exit code!
1654cdfa2a7eSchristos 	 */
1655cdfa2a7eSchristos 	wait_end_time = time(NULL);
1656cdfa2a7eSchristos 	if (wait_sync)
1657cdfa2a7eSchristos 		wait_end_time += wait_sync;
1658cdfa2a7eSchristos 	else
1659cdfa2a7eSchristos 		wait_end_time += 30;
16602950cc38Schristos 
16612950cc38Schristos 	do {
16622950cc38Schristos 		cur_time = time(NULL);
16632950cc38Schristos 		wait_rem = (wait_end_time > cur_time)
16642950cc38Schristos 				? (wait_end_time - cur_time)
16652950cc38Schristos 				: 0;
16662950cc38Schristos 		wtimeout.tv_sec = wait_rem;
16672950cc38Schristos 		wtimeout.tv_usec = 0;
16682950cc38Schristos 		FD_ZERO(&readset);
16692950cc38Schristos 		FD_SET(pipe_read_fd, &readset);
16702950cc38Schristos 		rc = select(pipe_read_fd + 1, &readset, NULL, NULL,
16712950cc38Schristos 			    &wtimeout);
16722950cc38Schristos 		if (-1 == rc) {
16732950cc38Schristos 			if (EINTR == errno)
16742950cc38Schristos 				continue;
16752950cc38Schristos 			msyslog(LOG_ERR,
1676cdfa2a7eSchristos 				"daemon startup: select failed: %m");
1677cdfa2a7eSchristos 			return EX_IOERR;
16782950cc38Schristos 		}
16792950cc38Schristos 		if (0 == rc) {
16802950cc38Schristos 			/*
16812950cc38Schristos 			 * select() indicated a timeout, but in case
16822950cc38Schristos 			 * its timeouts are affected by a step of the
16832950cc38Schristos 			 * system clock, select() again with a zero
16842950cc38Schristos 			 * timeout to confirm.
16852950cc38Schristos 			 */
16862950cc38Schristos 			FD_ZERO(&readset);
16872950cc38Schristos 			FD_SET(pipe_read_fd, &readset);
16882950cc38Schristos 			wtimeout.tv_sec = 0;
16892950cc38Schristos 			wtimeout.tv_usec = 0;
16902950cc38Schristos 			rc = select(pipe_read_fd + 1, &readset, NULL,
16912950cc38Schristos 				    NULL, &wtimeout);
16922950cc38Schristos 			if (0 == rc)	/* select() timeout */
16932950cc38Schristos 				break;
1694cdfa2a7eSchristos 		}
1695cdfa2a7eSchristos 		rc = read(pipe_read_fd, &ch, 1);
1696cdfa2a7eSchristos 		if (rc == 0) {
1697*eabc0478Schristos 			/* DPRINTF is useless here as -d/-D disable forking */
1698*eabc0478Schristos 			fprintf(stderr, "daemon control: got EOF\n");
1699cdfa2a7eSchristos 			return -1;	/* unexpected EOF, check daemon */
1700cdfa2a7eSchristos 		} else if (rc == 1) {
1701*eabc0478Schristos 			if (   ('S' == ch && wait_sync > 0)
1702*eabc0478Schristos 			    || ('R' == ch && 0 == wait_sync)) {
17032950cc38Schristos 				return 0;
1704*eabc0478Schristos 			}
1705cdfa2a7eSchristos 		} else {
1706*eabc0478Schristos 			mfprintf(stderr, "%s: daemon control: read 1 char failed: %m\n",
1707*eabc0478Schristos 				 progname);
1708*eabc0478Schristos 			msyslog(LOG_ERR, "daemon control: read 1 char failed: %m");
1709cdfa2a7eSchristos 			return EX_IOERR;
1710cdfa2a7eSchristos 		}
17112950cc38Schristos 	} while (wait_rem > 0);
17122950cc38Schristos 
1713*eabc0478Schristos 	if (wait_sync > 0) {
17142950cc38Schristos 		fprintf(stderr, "%s: -w/--wait-sync %ld timed out.\n",
17152950cc38Schristos 			progname, wait_sync);
1716*eabc0478Schristos 		msyslog(LOG_ERR, "-w/--wait-sync %ld timed out.", wait_sync);
1717cdfa2a7eSchristos 		return EX_PROTOCOL;
1718cdfa2a7eSchristos 	} else {
1719cdfa2a7eSchristos 		fprintf(stderr, "%s: daemon startup monitoring timed out.\n",
1720cdfa2a7eSchristos 			progname);
1721*eabc0478Schristos 		msyslog(LOG_ERR, "daemon startup monitoring timed out.");
1722cdfa2a7eSchristos 		return 0;
17232950cc38Schristos 	}
1724cdfa2a7eSchristos }
1725cdfa2a7eSchristos 
1726cdfa2a7eSchristos 
1727cdfa2a7eSchristos static int
1728cdfa2a7eSchristos wait_child_exit_if(
1729cdfa2a7eSchristos 	pid_t	cpid,
1730cdfa2a7eSchristos 	int	blocking
1731cdfa2a7eSchristos 	)
1732cdfa2a7eSchristos {
1733cdfa2a7eSchristos #    ifdef HAVE_WAITPID
1734cdfa2a7eSchristos 	int	rc = 0;
1735cdfa2a7eSchristos 	int	wstatus;
1736cdfa2a7eSchristos 	if (cpid == waitpid(cpid, &wstatus, (blocking ? 0 : WNOHANG))) {
1737cdfa2a7eSchristos 		if (WIFEXITED(wstatus)) {
1738cdfa2a7eSchristos 			rc = WEXITSTATUS(wstatus);
1739cdfa2a7eSchristos 			msyslog(LOG_ERR, "daemon child exited with code %d",
1740cdfa2a7eSchristos 				rc);
1741cdfa2a7eSchristos 		} else if (WIFSIGNALED(wstatus)) {
1742cdfa2a7eSchristos 			rc = EX_SOFTWARE;
1743cdfa2a7eSchristos 			msyslog(LOG_ERR, "daemon child died with signal %d",
1744cdfa2a7eSchristos 				WTERMSIG(wstatus));
1745cdfa2a7eSchristos 		} else {
1746cdfa2a7eSchristos 			rc = EX_SOFTWARE;
1747cdfa2a7eSchristos 			msyslog(LOG_ERR, "daemon child died with unknown cause");
1748cdfa2a7eSchristos 		}
1749cdfa2a7eSchristos 	}
1750cdfa2a7eSchristos 	return rc;
1751cdfa2a7eSchristos #    else
1752cdfa2a7eSchristos 	UNUSED_ARG(cpid);
1753cdfa2a7eSchristos 	return 0;
1754cdfa2a7eSchristos #    endif
1755cdfa2a7eSchristos }
1756cdfa2a7eSchristos 
17572950cc38Schristos # endif	/* HAVE_WORKING_FORK */
17582950cc38Schristos 
1759abb0f93cSkardel 
1760abb0f93cSkardel /*
17612950cc38Schristos  * assertion_failed - Redirect assertion failures to msyslog().
1762abb0f93cSkardel  */
1763abb0f93cSkardel static void
17642950cc38Schristos assertion_failed(
17652950cc38Schristos 	const char *file,
17662950cc38Schristos 	int line,
17672950cc38Schristos 	isc_assertiontype_t type,
17682950cc38Schristos 	const char *cond
17692950cc38Schristos 	)
1770abb0f93cSkardel {
1771abb0f93cSkardel 	isc_assertion_setcallback(NULL);    /* Avoid recursion */
1772abb0f93cSkardel 
1773abb0f93cSkardel 	msyslog(LOG_ERR, "%s:%d: %s(%s) failed",
1774abb0f93cSkardel 		file, line, isc_assertion_typetotext(type), cond);
1775abb0f93cSkardel 	msyslog(LOG_ERR, "exiting (due to assertion failure)");
1776abb0f93cSkardel 
17772950cc38Schristos #if defined(DEBUG) && defined(SYS_WINNT)
17782950cc38Schristos 	if (debug)
17792950cc38Schristos 		DebugBreak();
17802950cc38Schristos #endif
17812950cc38Schristos 
1782abb0f93cSkardel 	abort();
1783abb0f93cSkardel }
1784abb0f93cSkardel 
17852950cc38Schristos 
1786abb0f93cSkardel /*
1787abb0f93cSkardel  * library_fatal_error - Handle fatal errors from our libraries.
1788abb0f93cSkardel  */
1789abb0f93cSkardel static void
17902950cc38Schristos library_fatal_error(
17912950cc38Schristos 	const char *file,
17922950cc38Schristos 	int line,
17932950cc38Schristos 	const char *format,
17942950cc38Schristos 	va_list args
17952950cc38Schristos 	)
1796abb0f93cSkardel {
1797abb0f93cSkardel 	char errbuf[256];
1798abb0f93cSkardel 
1799abb0f93cSkardel 	isc_error_setfatal(NULL);  /* Avoid recursion */
1800abb0f93cSkardel 
1801abb0f93cSkardel 	msyslog(LOG_ERR, "%s:%d: fatal error:", file, line);
1802abb0f93cSkardel 	vsnprintf(errbuf, sizeof(errbuf), format, args);
18037fdb569fSchristos 	msyslog(LOG_ERR, "%s", errbuf);
1804abb0f93cSkardel 	msyslog(LOG_ERR, "exiting (due to fatal error in library)");
1805abb0f93cSkardel 
18062950cc38Schristos #if defined(DEBUG) && defined(SYS_WINNT)
18072950cc38Schristos 	if (debug)
18082950cc38Schristos 		DebugBreak();
18092950cc38Schristos #endif
18102950cc38Schristos 
1811abb0f93cSkardel 	abort();
1812abb0f93cSkardel }
1813abb0f93cSkardel 
18142950cc38Schristos 
1815abb0f93cSkardel /*
1816abb0f93cSkardel  * library_unexpected_error - Handle non fatal errors from our libraries.
1817abb0f93cSkardel  */
1818abb0f93cSkardel # define MAX_UNEXPECTED_ERRORS 100
1819abb0f93cSkardel int unexpected_error_cnt = 0;
1820abb0f93cSkardel static void
18212950cc38Schristos library_unexpected_error(
18222950cc38Schristos 	const char *file,
18232950cc38Schristos 	int line,
18242950cc38Schristos 	const char *format,
18252950cc38Schristos 	va_list args
18262950cc38Schristos 	)
1827abb0f93cSkardel {
1828abb0f93cSkardel 	char errbuf[256];
1829abb0f93cSkardel 
1830abb0f93cSkardel 	if (unexpected_error_cnt >= MAX_UNEXPECTED_ERRORS)
1831abb0f93cSkardel 		return;	/* avoid clutter in log */
1832abb0f93cSkardel 
1833abb0f93cSkardel 	msyslog(LOG_ERR, "%s:%d: unexpected error:", file, line);
1834abb0f93cSkardel 	vsnprintf(errbuf, sizeof(errbuf), format, args);
18357fdb569fSchristos 	msyslog(LOG_ERR, "%s", errbuf);
1836abb0f93cSkardel 
1837abb0f93cSkardel 	if (++unexpected_error_cnt == MAX_UNEXPECTED_ERRORS)
1838abb0f93cSkardel 		msyslog(LOG_ERR, "Too many errors.  Shutting up.");
1839abb0f93cSkardel 
1840abb0f93cSkardel }
18412950cc38Schristos #endif	/* !SIM */
1842abb0f93cSkardel 
18432950cc38Schristos #if !defined(SIM) && !defined(SYS_WINNT)
1844abb0f93cSkardel # ifdef DEBUG
18452950cc38Schristos 
1846abb0f93cSkardel /*
1847abb0f93cSkardel  * moredebug - increase debugging verbosity
1848abb0f93cSkardel  */
1849abb0f93cSkardel static RETSIGTYPE
1850abb0f93cSkardel moredebug(
1851abb0f93cSkardel 	int sig
1852abb0f93cSkardel 	)
1853abb0f93cSkardel {
1854abb0f93cSkardel 	int saved_errno = errno;
1855abb0f93cSkardel 
1856abb0f93cSkardel 	if (debug < 255)
1857abb0f93cSkardel 	{
1858abb0f93cSkardel 		debug++;
1859abb0f93cSkardel 		msyslog(LOG_DEBUG, "debug raised to %d", debug);
1860abb0f93cSkardel 	}
1861abb0f93cSkardel 	errno = saved_errno;
1862abb0f93cSkardel }
1863abb0f93cSkardel 
18642950cc38Schristos 
1865abb0f93cSkardel /*
1866abb0f93cSkardel  * lessdebug - decrease debugging verbosity
1867abb0f93cSkardel  */
1868abb0f93cSkardel static RETSIGTYPE
1869abb0f93cSkardel lessdebug(
1870abb0f93cSkardel 	int sig
1871abb0f93cSkardel 	)
1872abb0f93cSkardel {
1873abb0f93cSkardel 	int saved_errno = errno;
1874abb0f93cSkardel 
1875abb0f93cSkardel 	if (debug > 0)
1876abb0f93cSkardel 	{
1877abb0f93cSkardel 		debug--;
1878abb0f93cSkardel 		msyslog(LOG_DEBUG, "debug lowered to %d", debug);
1879abb0f93cSkardel 	}
1880abb0f93cSkardel 	errno = saved_errno;
1881abb0f93cSkardel }
18822950cc38Schristos 
18832950cc38Schristos # else	/* !DEBUG follows */
18842950cc38Schristos 
18852950cc38Schristos 
1886abb0f93cSkardel /*
1887abb0f93cSkardel  * no_debug - We don't do the debug here.
1888abb0f93cSkardel  */
1889abb0f93cSkardel static RETSIGTYPE
1890abb0f93cSkardel no_debug(
1891abb0f93cSkardel 	int sig
1892abb0f93cSkardel 	)
1893abb0f93cSkardel {
1894abb0f93cSkardel 	int saved_errno = errno;
1895abb0f93cSkardel 
1896abb0f93cSkardel 	msyslog(LOG_DEBUG, "ntpd not compiled for debugging (signal %d)", sig);
1897abb0f93cSkardel 	errno = saved_errno;
1898abb0f93cSkardel }
18992950cc38Schristos # endif	/* !DEBUG */
19002950cc38Schristos #endif	/* !SIM && !SYS_WINNT */
1901