xref: /openbsd-src/usr.sbin/ntpd/ntpd.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: ntpd.c,v 1.64 2009/02/10 16:52:09 stevesk Exp $ */
2 
3 /*
4  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/wait.h>
22 #include <netinet/in.h>
23 #include <errno.h>
24 #include <poll.h>
25 #include <pwd.h>
26 #include <resolv.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <err.h>
33 
34 #include "ntpd.h"
35 
36 void		sighdlr(int);
37 __dead void	usage(void);
38 int		main(int, char *[]);
39 int		check_child(pid_t, const char *);
40 int		dispatch_imsg(struct ntpd_conf *);
41 void		reset_adjtime(void);
42 int		ntpd_adjtime(double);
43 void		ntpd_adjfreq(double, int);
44 void		ntpd_settime(double);
45 void		readfreq(void);
46 int		writefreq(double);
47 
48 volatile sig_atomic_t	 quit = 0;
49 volatile sig_atomic_t	 reconfig = 0;
50 volatile sig_atomic_t	 sigchld = 0;
51 struct imsgbuf		*ibuf;
52 int			 debugsyslog = 0;
53 int			 timeout = INFTIM;
54 
55 void
56 sighdlr(int sig)
57 {
58 	switch (sig) {
59 	case SIGTERM:
60 	case SIGINT:
61 		quit = 1;
62 		break;
63 	case SIGCHLD:
64 		sigchld = 1;
65 		break;
66 	case SIGHUP:
67 		reconfig = 1;
68 		break;
69 	}
70 }
71 
72 __dead void
73 usage(void)
74 {
75 	extern char *__progname;
76 
77 	fprintf(stderr, "usage: %s [-dnSsv] [-f file]\n", __progname);
78 	exit(1);
79 }
80 
81 #define POLL_MAX		8
82 #define PFD_PIPE		0
83 
84 int
85 main(int argc, char *argv[])
86 {
87 	struct ntpd_conf	 lconf;
88 	struct pollfd		 pfd[POLL_MAX];
89 	pid_t			 chld_pid = 0, pid;
90 	const char		*conffile;
91 	int			 ch, nfds;
92 	int			 pipe_chld[2];
93 	struct passwd		*pw;
94 
95 	conffile = CONFFILE;
96 
97 	bzero(&lconf, sizeof(lconf));
98 
99 	log_init(1);		/* log to stderr until daemonized */
100 	res_init();		/* XXX */
101 
102 	while ((ch = getopt(argc, argv, "df:nsSv")) != -1) {
103 		switch (ch) {
104 		case 'd':
105 			lconf.debug = 1;
106 			break;
107 		case 'f':
108 			conffile = optarg;
109 			break;
110 		case 'n':
111 			lconf.noaction = 1;
112 			break;
113 		case 's':
114 			lconf.settime = 1;
115 			break;
116 		case 'S':
117 			lconf.settime = 0;
118 			break;
119 		case 'v':
120 			debugsyslog = 1;
121 			break;
122 		default:
123 			usage();
124 			/* NOTREACHED */
125 		}
126 	}
127 
128 	argc -= optind;
129 	argv += optind;
130 	if (argc > 0)
131 		usage();
132 
133 	if (parse_config(conffile, &lconf))
134 		exit(1);
135 
136 	if (lconf.noaction) {
137 		fprintf(stderr, "configuration OK\n");
138 		exit(0);
139 	}
140 
141 	if (geteuid())
142 		errx(1, "need root privileges");
143 
144 	if ((pw = getpwnam(NTPD_USER)) == NULL)
145 		errx(1, "unknown user %s", NTPD_USER);
146 
147 	endpwent();
148 
149 	reset_adjtime();
150 	if (!lconf.settime) {
151 		log_init(lconf.debug);
152 		if (!lconf.debug)
153 			if (daemon(1, 0))
154 				fatal("daemon");
155 	} else
156 		timeout = SETTIME_TIMEOUT * 1000;
157 
158 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_chld) == -1)
159 		fatal("socketpair");
160 
161 	signal(SIGCHLD, sighdlr);
162 	/* fork child process */
163 	chld_pid = ntp_main(pipe_chld, &lconf, pw);
164 
165 	setproctitle("[priv]");
166 	readfreq();
167 
168 	signal(SIGTERM, sighdlr);
169 	signal(SIGINT, sighdlr);
170 	signal(SIGHUP, sighdlr);
171 
172 	close(pipe_chld[1]);
173 
174 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
175 		fatal(NULL);
176 	imsg_init(ibuf, pipe_chld[0]);
177 
178 	while (quit == 0) {
179 		pfd[PFD_PIPE].fd = ibuf->fd;
180 		pfd[PFD_PIPE].events = POLLIN;
181 		if (ibuf->w.queued)
182 			pfd[PFD_PIPE].events |= POLLOUT;
183 
184 		if ((nfds = poll(pfd, 1, timeout)) == -1)
185 			if (errno != EINTR) {
186 				log_warn("poll error");
187 				quit = 1;
188 			}
189 
190 		if (nfds == 0 && lconf.settime) {
191 			lconf.settime = 0;
192 			timeout = INFTIM;
193 			log_init(lconf.debug);
194 			log_debug("no reply received in time, skipping initial "
195 			    "time setting");
196 			if (!lconf.debug)
197 				if (daemon(1, 0))
198 					fatal("daemon");
199 		}
200 
201 		if (nfds > 0 && (pfd[PFD_PIPE].revents & POLLOUT))
202 			if (msgbuf_write(&ibuf->w) < 0) {
203 				log_warn("pipe write error (to child)");
204 				quit = 1;
205 			}
206 
207 		if (nfds > 0 && pfd[PFD_PIPE].revents & POLLIN) {
208 			nfds--;
209 			if (dispatch_imsg(&lconf) == -1)
210 				quit = 1;
211 		}
212 
213 		if (sigchld) {
214 			if (check_child(chld_pid, "child")) {
215 				quit = 1;
216 				chld_pid = 0;
217 			}
218 			sigchld = 0;
219 		}
220 
221 	}
222 
223 	signal(SIGCHLD, SIG_DFL);
224 
225 	if (chld_pid)
226 		kill(chld_pid, SIGTERM);
227 
228 	do {
229 		if ((pid = wait(NULL)) == -1 &&
230 		    errno != EINTR && errno != ECHILD)
231 			fatal("wait");
232 	} while (pid != -1 || (pid == -1 && errno == EINTR));
233 
234 	msgbuf_clear(&ibuf->w);
235 	free(ibuf);
236 	log_info("Terminating");
237 	return (0);
238 }
239 
240 int
241 check_child(pid_t pid, const char *pname)
242 {
243 	int	 status, sig;
244 	char	*signame;
245 
246 	if (waitpid(pid, &status, WNOHANG) > 0) {
247 		if (WIFEXITED(status)) {
248 			log_warnx("Lost child: %s exited", pname);
249 			return (1);
250 		}
251 		if (WIFSIGNALED(status)) {
252 			sig = WTERMSIG(status);
253 			signame = strsignal(sig) ? strsignal(sig) : "unknown";
254 			log_warnx("Lost child: %s terminated; signal %d (%s)",
255 			    pname, sig, signame);
256 			return (1);
257 		}
258 	}
259 
260 	return (0);
261 }
262 
263 int
264 dispatch_imsg(struct ntpd_conf *lconf)
265 {
266 	struct imsg		 imsg;
267 	int			 n, cnt;
268 	double			 d;
269 	char			*name;
270 	struct ntp_addr		*h, *hn;
271 	struct buf		*buf;
272 
273 	if ((n = imsg_read(ibuf)) == -1)
274 		return (-1);
275 
276 	if (n == 0) {	/* connection closed */
277 		log_warnx("dispatch_imsg in main: pipe closed");
278 		return (-1);
279 	}
280 
281 	for (;;) {
282 		if ((n = imsg_get(ibuf, &imsg)) == -1)
283 			return (-1);
284 
285 		if (n == 0)
286 			break;
287 
288 		switch (imsg.hdr.type) {
289 		case IMSG_ADJTIME:
290 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
291 				fatalx("invalid IMSG_ADJTIME received");
292 			memcpy(&d, imsg.data, sizeof(d));
293 			n = ntpd_adjtime(d);
294 			imsg_compose(ibuf, IMSG_ADJTIME, 0, 0, &n, sizeof(n));
295 			break;
296 		case IMSG_ADJFREQ:
297 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
298 				fatalx("invalid IMSG_ADJFREQ received");
299 			memcpy(&d, imsg.data, sizeof(d));
300 			ntpd_adjfreq(d, 1);
301 			break;
302 		case IMSG_SETTIME:
303 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
304 				fatalx("invalid IMSG_SETTIME received");
305 			if (!lconf->settime)
306 				break;
307 			log_init(lconf->debug);
308 			memcpy(&d, imsg.data, sizeof(d));
309 			ntpd_settime(d);
310 			/* daemonize now */
311 			if (!lconf->debug)
312 				if (daemon(1, 0))
313 					fatal("daemon");
314 			lconf->settime = 0;
315 			timeout = INFTIM;
316 			break;
317 		case IMSG_HOST_DNS:
318 			name = imsg.data;
319 			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
320 				fatalx("invalid IMSG_HOST_DNS received");
321 			imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
322 			if (name[imsg.hdr.len] != '\0' ||
323 			    strlen(name) != imsg.hdr.len)
324 				fatalx("invalid IMSG_HOST_DNS received");
325 			if ((cnt = host_dns(name, &hn)) == -1)
326 				break;
327 			buf = imsg_create(ibuf, IMSG_HOST_DNS,
328 			    imsg.hdr.peerid, 0,
329 			    cnt * sizeof(struct sockaddr_storage));
330 			if (buf == NULL)
331 				break;
332 			if (cnt > 0)
333 				for (h = hn; h != NULL; h = h->next)
334 					imsg_add(buf, &h->ss, sizeof(h->ss));
335 
336 			imsg_close(ibuf, buf);
337 			break;
338 		default:
339 			break;
340 		}
341 		imsg_free(&imsg);
342 	}
343 	return (0);
344 }
345 
346 void
347 reset_adjtime(void)
348 {
349 	struct timeval	tv;
350 
351 	tv.tv_sec = 0;
352 	tv.tv_usec = 0;
353 	if (adjtime(&tv, NULL) == -1)
354 		log_warn("reset adjtime failed");
355 }
356 
357 int
358 ntpd_adjtime(double d)
359 {
360 	struct timeval	tv, olddelta;
361 	int		synced = 0;
362 	static int	firstadj = 1;
363 
364 	d += getoffset();
365 	if (d >= (double)LOG_NEGLIGIBLE_ADJTIME / 1000 ||
366 	    d <= -1 * (double)LOG_NEGLIGIBLE_ADJTIME / 1000)
367 		log_info("adjusting local clock by %fs", d);
368 	else
369 		log_debug("adjusting local clock by %fs", d);
370 	d_to_tv(d, &tv);
371 	if (adjtime(&tv, &olddelta) == -1)
372 		log_warn("adjtime failed");
373 	else if (!firstadj && olddelta.tv_sec == 0 && olddelta.tv_usec == 0)
374 		synced = 1;
375 	firstadj = 0;
376 	return (synced);
377 }
378 
379 void
380 ntpd_adjfreq(double relfreq, int wrlog)
381 {
382 	int64_t curfreq;
383 	double ppmfreq;
384 	int r;
385 
386 	if (adjfreq(NULL, &curfreq) == -1) {
387 		log_warn("adjfreq failed");
388 		return;
389 	}
390 
391 	/*
392 	 * adjfreq's unit is ns/s shifted left 32; convert relfreq to
393 	 * that unit before adding. We log values in part per million.
394 	 */
395 	curfreq += relfreq * 1e9 * (1LL << 32);
396 	r = writefreq(curfreq / 1e9 / (1LL << 32));
397 	ppmfreq = relfreq * 1e6;
398 	if (wrlog) {
399 		if (ppmfreq >= LOG_NEGLIGIBLE_ADJFREQ ||
400 		    ppmfreq <= -LOG_NEGLIGIBLE_ADJFREQ)
401 			log_info("adjusting clock frequency by %f to %fppm%s",
402 			    ppmfreq, curfreq / 1e3 / (1LL << 32),
403 			    r ? "" : " (no drift file)");
404 		else
405 			log_debug("adjusting clock frequency by %f to %fppm%s",
406 			    ppmfreq, curfreq / 1e3 / (1LL << 32),
407 			    r ? "" : " (no drift file)");
408 	}
409 
410 	if (adjfreq(&curfreq, NULL) == -1)
411 		log_warn("adjfreq failed");
412 }
413 
414 void
415 ntpd_settime(double d)
416 {
417 	struct timeval	tv, curtime;
418 	char		buf[80];
419 	time_t		tval;
420 
421 	if (gettimeofday(&curtime, NULL) == -1) {
422 		log_warn("gettimeofday");
423 		return;
424 	}
425 	d_to_tv(d, &tv);
426 	curtime.tv_usec += tv.tv_usec + 1000000;
427 	curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000);
428 	curtime.tv_usec %= 1000000;
429 
430 	if (settimeofday(&curtime, NULL) == -1) {
431 		log_warn("settimeofday");
432 		return;
433 	}
434 	tval = curtime.tv_sec;
435 	strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y",
436 	    localtime(&tval));
437 	log_info("set local clock to %s (offset %fs)", buf, d);
438 }
439 
440 void
441 readfreq(void)
442 {
443 	FILE *fp;
444 	int64_t current;
445 	double d;
446 
447 	fp = fopen(DRIFTFILE, "r");
448 	if (fp == NULL) {
449 		/* if the drift file has been deleted by the user, reset */
450 		current = 0;
451 		if (adjfreq(&current, NULL) == -1)
452 			log_warn("adjfreq reset failed");
453 		return;
454 	}
455 
456 	/* if we're adjusting frequency already, don't override */
457 	if (adjfreq(NULL, &current) == -1)
458 		log_warn("adjfreq failed");
459 	else if (current == 0) {
460 		if (fscanf(fp, "%le", &d) == 1)
461 			ntpd_adjfreq(d, 0);
462 		else
463 			log_warnx("can't read %s", DRIFTFILE);
464 	}
465 	fclose(fp);
466 }
467 
468 int
469 writefreq(double d)
470 {
471 	int r;
472 	FILE *fp;
473 	static int warnonce = 1;
474 
475 	fp = fopen(DRIFTFILE, "w");
476 	if (fp == NULL) {
477 		if (warnonce) {
478 			log_warn("can't open %s", DRIFTFILE);
479 			warnonce = 0;
480 		}
481 		return 0;
482 	}
483 
484 	fprintf(fp, "%e\n", d);
485 	r = ferror(fp);
486 	if (fclose(fp) != 0 || r != 0) {
487 		if (warnonce) {
488 			log_warnx("can't write %s", DRIFTFILE);
489 			warnonce = 0;
490 		}
491 		unlink(DRIFTFILE);
492 		return 0;
493 	}
494 	return 1;
495 }
496