Add rfcomm_sppd(1) - RFCOMM Serial Port Profile daemon.
[dragonfly.git] / contrib / ntpd / ntp.c
blob6ea9482d9a559ec3d5adc2fd039608601b795e93
1 /* $OpenBSD: src/usr.sbin/ntpd/ntp.c,v 1.57 2005/04/18 14:12:50 henning Exp $ */
3 /*
4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/param.h>
21 #include <sys/time.h>
22 #include <sys/stat.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <paths.h>
26 #include <poll.h>
27 #include <pwd.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
34 #include "ntpd.h"
35 #include "ntp.h"
37 #define PFD_PIPE_MAIN 0
38 #define PFD_MAX 1
40 volatile sig_atomic_t ntp_quit = 0;
41 struct imsgbuf *ibuf_main;
42 struct ntpd_conf *conf;
43 u_int peer_cnt;
45 void ntp_sighdlr(int);
46 int ntp_dispatch_imsg(void);
47 void peer_add(struct ntp_peer *);
48 void peer_remove(struct ntp_peer *);
49 int offset_compare(const void *, const void *);
51 void
52 ntp_sighdlr(int sig)
54 switch (sig) {
55 case SIGINT:
56 case SIGTERM:
57 ntp_quit = 1;
58 break;
62 pid_t
63 ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf)
65 int a, b, nfds, i, j, idx_peers, timeout, nullfd;
66 u_int pfd_elms = 0, idx2peer_elms = 0;
67 u_int listener_cnt, new_cnt, sent_cnt, trial_cnt;
68 pid_t pid;
69 struct pollfd *pfd = NULL;
70 struct passwd *pw;
71 struct servent *se;
72 struct listen_addr *la;
73 struct ntp_peer *p;
74 struct ntp_peer **idx2peer = NULL;
75 struct timespec tp;
76 struct stat stb;
77 time_t nextaction;
78 void *newp;
80 switch (pid = fork()) {
81 case -1:
82 fatal("cannot fork");
83 break;
84 case 0:
85 break;
86 default:
87 return (pid);
90 if ((se = getservbyname("ntp", "udp")) == NULL)
91 fatal("getservbyname");
93 if ((pw = getpwnam(NTPD_USER)) == NULL)
94 fatal("getpwnam");
96 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
97 fatal(NULL);
99 if (stat(pw->pw_dir, &stb) == -1)
100 fatal("stat");
101 if (stb.st_uid != 0 || (stb.st_mode & (S_IWGRP|S_IWOTH)) != 0)
102 fatal("bad privsep dir permissions");
103 if (chroot(pw->pw_dir) == -1)
104 fatal("chroot");
105 if (chdir("/") == -1)
106 fatal("chdir(\"/\")");
108 if (!nconf->debug) {
109 dup2(nullfd, STDIN_FILENO);
110 dup2(nullfd, STDOUT_FILENO);
111 dup2(nullfd, STDERR_FILENO);
113 close(nullfd);
115 setproctitle("ntp engine");
117 conf = nconf;
118 setup_listeners(se, conf, &listener_cnt);
120 if (setgroups(1, &pw->pw_gid) ||
121 setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
122 seteuid(pw->pw_uid) || setuid(pw->pw_uid))
123 fatal("can't drop privileges");
125 endpwent();
126 endservent();
128 signal(SIGTERM, ntp_sighdlr);
129 signal(SIGINT, ntp_sighdlr);
130 signal(SIGPIPE, SIG_IGN);
131 signal(SIGHUP, SIG_IGN);
133 close(pipe_prnt[0]);
134 if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
135 fatal(NULL);
136 imsg_init(ibuf_main, pipe_prnt[1]);
138 TAILQ_FOREACH(p, &conf->ntp_peers, entry)
139 client_peer_init(p);
141 bzero(&conf->status, sizeof(conf->status));
142 conf->status.leap = LI_ALARM;
143 clock_getres(CLOCK_REALTIME, &tp);
144 b = 1000000000 / tp.tv_nsec; /* convert to Hz */
145 for (a = 0; b > 1; a--, b >>= 1)
147 conf->status.precision = a;
148 conf->scale = 1;
150 log_info("ntp engine ready");
152 peer_cnt = 0;
153 TAILQ_FOREACH(p, &conf->ntp_peers, entry)
154 peer_cnt++;
156 while (ntp_quit == 0) {
157 if (peer_cnt > idx2peer_elms) {
158 if ((newp = realloc(idx2peer, sizeof(void *) *
159 peer_cnt)) == NULL) {
160 /* panic for now */
161 log_warn("could not resize idx2peer from %u -> "
162 "%u entries", idx2peer_elms, peer_cnt);
163 fatalx("exiting");
165 idx2peer = newp;
166 idx2peer_elms = peer_cnt;
169 new_cnt = PFD_MAX + peer_cnt + listener_cnt;
170 if (new_cnt > pfd_elms) {
171 if ((newp = realloc(pfd, sizeof(struct pollfd) *
172 new_cnt)) == NULL) {
173 /* panic for now */
174 log_warn("could not resize pfd from %u -> "
175 "%u entries", pfd_elms, new_cnt);
176 fatalx("exiting");
178 pfd = newp;
179 pfd_elms = new_cnt;
182 bzero(pfd, sizeof(struct pollfd) * pfd_elms);
183 bzero(idx2peer, sizeof(void *) * idx2peer_elms);
184 nextaction = time(NULL) + 3600;
185 pfd[PFD_PIPE_MAIN].fd = ibuf_main->fd;
186 pfd[PFD_PIPE_MAIN].events = POLLIN;
188 i = 1;
189 TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
190 pfd[i].fd = la->fd;
191 pfd[i].events = POLLIN;
192 i++;
195 idx_peers = i;
196 sent_cnt = trial_cnt = 0;
197 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
198 if (p->next > 0 && p->next < nextaction)
199 nextaction = p->next;
200 if (p->next > 0 && p->next <= time(NULL)) {
201 trial_cnt++;
202 if (client_query(p) == 0)
203 sent_cnt++;
206 if (p->deadline > 0 && p->deadline < nextaction)
207 nextaction = p->deadline;
208 if (p->deadline > 0 && p->deadline <= time(NULL)) {
209 timeout = error_interval();
210 log_debug("no reply from %s received in time, "
211 "next query %ds", log_sockaddr(
212 (struct sockaddr *)&p->addr->ss), timeout);
213 if (p->trustlevel >= TRUSTLEVEL_BADPEER &&
214 (p->trustlevel /= 2) < TRUSTLEVEL_BADPEER)
215 log_info("peer %s now invalid",
216 log_sockaddr(
217 (struct sockaddr *)&p->addr->ss));
218 client_nextaddr(p);
219 set_next(p, timeout);
222 if (p->state == STATE_QUERY_SENT) {
223 pfd[i].fd = p->query->fd;
224 pfd[i].events = POLLIN;
225 idx2peer[i - idx_peers] = p;
226 i++;
230 if (trial_cnt > 0 && sent_cnt == 0 && conf->settime)
231 priv_settime(0); /* no good peers, don't wait */
233 if (ibuf_main->w.queued > 0)
234 pfd[PFD_PIPE_MAIN].events |= POLLOUT;
236 timeout = nextaction - time(NULL);
237 if (timeout < 0)
238 timeout = 0;
240 if ((nfds = poll(pfd, i, timeout * 1000)) == -1)
241 if (errno != EINTR) {
242 log_warn("poll error");
243 ntp_quit = 1;
246 if (nfds > 0 && (pfd[PFD_PIPE_MAIN].revents & POLLOUT))
247 if (msgbuf_write(&ibuf_main->w) < 0) {
248 log_warn("pipe write error (to parent)");
249 ntp_quit = 1;
252 if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & (POLLIN|POLLERR)) {
253 nfds--;
254 if (ntp_dispatch_imsg() == -1)
255 ntp_quit = 1;
258 for (j = 1; nfds > 0 && j < idx_peers; j++)
259 if (pfd[j].revents & (POLLIN|POLLERR)) {
260 nfds--;
261 if (server_dispatch(pfd[j].fd, conf) == -1)
262 ntp_quit = 1;
265 for (; nfds > 0 && j < i; j++)
266 if (pfd[j].revents & (POLLIN|POLLERR)) {
267 nfds--;
268 if (client_dispatch(idx2peer[j - idx_peers],
269 conf->settime) == -1)
270 ntp_quit = 1;
274 msgbuf_write(&ibuf_main->w);
275 msgbuf_clear(&ibuf_main->w);
276 free(ibuf_main);
278 log_info("ntp engine exiting");
279 _exit(0);
283 ntp_dispatch_imsg(void)
285 struct imsg imsg;
286 int n;
287 struct ntp_peer *peer, *npeer;
288 u_int16_t dlen;
289 u_char *p;
290 struct ntp_addr *h;
292 if ((n = imsg_read(ibuf_main)) == -1)
293 return (-1);
295 if (n == 0) { /* connection closed */
296 log_warnx("ntp_dispatch_imsg in ntp engine: pipe closed");
297 return (-1);
300 for (;;) {
301 if ((n = imsg_get(ibuf_main, &imsg)) == -1)
302 return (-1);
304 if (n == 0)
305 break;
307 switch (imsg.hdr.type) {
308 case IMSG_HOST_DNS:
309 TAILQ_FOREACH(peer, &conf->ntp_peers, entry)
310 if (peer->id == imsg.hdr.peerid)
311 break;
312 if (peer == NULL) {
313 log_warnx("IMSG_HOST_DNS with invalid peerID");
314 break;
316 if (peer->addr != NULL) {
317 log_warnx("IMSG_HOST_DNS but addr != NULL!");
318 break;
320 dlen = imsg.hdr.len - IMSG_HEADER_SIZE;
321 p = (u_char *)imsg.data;
322 while (dlen >= sizeof(struct sockaddr_storage)) {
323 if ((h = calloc(1, sizeof(struct ntp_addr))) ==
324 NULL)
325 fatal(NULL);
326 memcpy(&h->ss, p, sizeof(h->ss));
327 p += sizeof(h->ss);
328 dlen -= sizeof(h->ss);
329 if (peer->addr_head.pool) {
330 npeer = new_peer();
331 h->next = NULL;
332 npeer->addr = h;
333 npeer->addr_head.a = h;
334 client_peer_init(npeer);
335 peer_add(npeer);
336 } else {
337 h->next = peer->addr;
338 peer->addr = h;
339 peer->addr_head.a = peer->addr;
342 if (dlen != 0)
343 fatalx("IMSG_HOST_DNS: dlen != 0");
344 if (peer->addr_head.pool)
345 peer_remove(peer);
346 else
347 client_addr_init(peer);
348 break;
349 default:
350 break;
352 imsg_free(&imsg);
354 return (0);
357 void
358 peer_add(struct ntp_peer *p)
360 TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
361 peer_cnt++;
364 void
365 peer_remove(struct ntp_peer *p)
367 TAILQ_REMOVE(&conf->ntp_peers, p, entry);
368 free(p);
369 peer_cnt--;
372 void
373 priv_adjtime(void)
375 struct ntp_peer *p;
376 int offset_cnt = 0, i = 0;
377 struct ntp_peer **peers;
378 double offset_median;
380 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
381 if (p->trustlevel < TRUSTLEVEL_BADPEER)
382 continue;
383 if (!p->update.good)
384 return;
385 offset_cnt++;
388 if ((peers = calloc(offset_cnt, sizeof(struct ntp_peer *))) == NULL)
389 fatal("calloc ntp_adjtime");
391 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
392 if (p->trustlevel < TRUSTLEVEL_BADPEER)
393 continue;
394 peers[i++] = p;
397 qsort(peers, offset_cnt, sizeof(struct ntp_peer *), offset_compare);
399 if (offset_cnt > 0) {
400 if (offset_cnt > 1 && offset_cnt % 2 == 0) {
401 offset_median =
402 (peers[offset_cnt / 2 - 1]->update.offset +
403 peers[offset_cnt / 2]->update.offset) / 2;
404 conf->status.rootdelay =
405 (peers[offset_cnt / 2 - 1]->update.delay +
406 peers[offset_cnt / 2]->update.delay) / 2;
407 conf->status.stratum = MAX(
408 peers[offset_cnt / 2 - 1]->update.status.stratum,
409 peers[offset_cnt / 2]->update.status.stratum);
410 } else {
411 offset_median = peers[offset_cnt / 2]->update.offset;
412 conf->status.rootdelay =
413 peers[offset_cnt / 2]->update.delay;
414 conf->status.stratum =
415 peers[offset_cnt / 2]->update.status.stratum;
418 imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0,
419 &offset_median, sizeof(offset_median));
421 conf->status.reftime = gettime();
422 conf->status.leap = LI_NOWARNING;
423 conf->status.stratum++; /* one more than selected peer */
424 update_scale(offset_median);
426 if (peers[offset_cnt / 2]->addr->ss.ss_family == AF_INET)
427 conf->status.refid = ((struct sockaddr_in *)
428 &peers[offset_cnt / 2]->addr->ss)->sin_addr.s_addr;
431 free(peers);
433 TAILQ_FOREACH(p, &conf->ntp_peers, entry)
434 p->update.good = 0;
438 offset_compare(const void *aa, const void *bb)
440 const struct ntp_peer * const *a;
441 const struct ntp_peer * const *b;
443 a = aa;
444 b = bb;
446 if ((*a)->update.offset < (*b)->update.offset)
447 return (-1);
448 else if ((*a)->update.offset > (*b)->update.offset)
449 return (1);
450 else
451 return (0);
454 void
455 priv_settime(double offset)
457 struct ntp_peer *p;
459 imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &offset, sizeof(offset));
460 conf->settime = 0;
462 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
463 if (p->next)
464 p->next -= offset;
465 if (p->deadline)
466 p->deadline -= offset;
470 void
471 priv_host_dns(char *name, u_int32_t peerid)
473 u_int16_t dlen;
475 dlen = strlen(name) + 1;
476 imsg_compose(ibuf_main, IMSG_HOST_DNS, peerid, 0, name, dlen);
479 void
480 update_scale(double offset)
482 if (offset < 0)
483 offset = -offset;
485 if (offset > QSCALE_OFF_MAX)
486 conf->scale = 1;
487 else if (offset < QSCALE_OFF_MIN)
488 conf->scale = QSCALE_OFF_MAX / QSCALE_OFF_MIN;
489 else
490 conf->scale = QSCALE_OFF_MAX / offset;
493 time_t
494 scale_interval(time_t requested)
496 time_t interval, r;
498 interval = requested * conf->scale;
499 r = arc4random() % MAX(5, interval / 10);
500 return (interval + r);
503 time_t
504 error_interval(void)
506 time_t interval, r;
508 interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN;
509 r = arc4random() % (interval / 10);
510 return (interval + r);