Sync OpenNTPD with OpenBSD.
[dragonfly.git] / contrib / ntpd / ntp.c
1 /*      $OpenBSD: ntp.c,v 1.50 2005/02/02 19:03:52 henning Exp $ */
2
3 /*
4  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org>
6  *
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.
10  *
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.
18  */
19
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>
33
34 #include "ntpd.h"
35 #include "ntp.h"
36
37 #define PFD_PIPE_MAIN   0
38 #define PFD_MAX         1
39
40 volatile sig_atomic_t    ntp_quit = 0;
41 struct imsgbuf          *ibuf_main;
42 struct ntpd_conf        *conf;
43 u_int                    peer_cnt;
44
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 *);
50
51 void
52 ntp_sighdlr(int sig)
53 {
54         switch (sig) {
55         case SIGINT:
56         case SIGTERM:
57                 ntp_quit = 1;
58                 break;
59         }
60 }
61
62 pid_t
63 ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf)
64 {
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;
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;
79
80         switch (pid = fork()) {
81         case -1:
82                 fatal("cannot fork");
83         case 0:
84                 break;
85         default:
86                 return (pid);
87         }
88
89         if ((se = getservbyname("ntp", "udp")) == NULL)
90                 fatal("getservbyname");
91
92         if ((pw = getpwnam(NTPD_USER)) == NULL)
93                 fatal("getpwnam");
94
95         if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
96                 fatal(NULL);
97
98         if (stat(pw->pw_dir, &stb) == -1)
99                 fatal("stat");
100         if (stb.st_uid != 0 || (stb.st_mode & (S_IWGRP|S_IWOTH)) != 0)
101                 fatal("bad privsep dir permissions");
102         if (chroot(pw->pw_dir) == -1)
103                 fatal("chroot");
104         if (chdir("/") == -1)
105                 fatal("chdir(\"/\")");
106
107         if (!nconf->debug) {
108                 dup2(nullfd, STDIN_FILENO);
109                 dup2(nullfd, STDOUT_FILENO);
110                 dup2(nullfd, STDERR_FILENO);
111         }
112         close(nullfd);
113
114         setproctitle("ntp engine");
115
116         conf = nconf;
117         setup_listeners(se, conf, &listener_cnt);
118
119         if (setgroups(1, &pw->pw_gid) ||
120             setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
121             seteuid(pw->pw_uid) || setuid(pw->pw_uid))
122                 fatal("can't drop privileges");
123
124         endpwent();
125         endservent();
126
127         signal(SIGTERM, ntp_sighdlr);
128         signal(SIGINT, ntp_sighdlr);
129         signal(SIGPIPE, SIG_IGN);
130         signal(SIGHUP, SIG_IGN);
131
132         close(pipe_prnt[0]);
133         if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
134                 fatal(NULL);
135         imsg_init(ibuf_main, pipe_prnt[1]);
136
137         TAILQ_FOREACH(p, &conf->ntp_peers, entry)
138                 client_peer_init(p);
139
140         bzero(&conf->status, sizeof(conf->status));
141         conf->status.leap = LI_ALARM;
142         clock_getres(CLOCK_REALTIME, &tp);
143         b = 1000000000 / tp.tv_nsec;    /* convert to Hz */
144         for (a = 0; b > 1; a--, b >>= 1);
145         conf->status.precision = a;
146         conf->scale = 1;
147
148         log_info("ntp engine ready");
149
150         peer_cnt = 0;
151         TAILQ_FOREACH(p, &conf->ntp_peers, entry)
152                 peer_cnt++;
153
154         while (ntp_quit == 0) {
155                 if (peer_cnt > idx2peer_elms) {
156                         if ((newp = realloc(idx2peer, sizeof(void *) *
157                             peer_cnt)) == NULL) {
158                                 /* panic for now */
159                                 log_warn("could not resize idx2peer from %u -> "
160                                     "%u entries", idx2peer_elms, peer_cnt);
161                                 fatalx("exiting");
162                         }
163                         idx2peer = newp;
164                         idx2peer_elms = peer_cnt;
165                 }
166
167                 new_cnt = PFD_MAX + peer_cnt + listener_cnt;
168                 if (new_cnt > pfd_elms) {
169                         if ((newp = realloc(pfd, sizeof(struct pollfd) *
170                             new_cnt)) == NULL) {
171                                 /* panic for now */
172                                 log_warn("could not resize pfd from %u -> "
173                                     "%u entries", pfd_elms, new_cnt);
174                                 fatalx("exiting");
175                         }
176                         pfd = newp;
177                         pfd_elms = new_cnt;
178                 }
179
180                 bzero(pfd, sizeof(struct pollfd) * pfd_elms);
181                 bzero(idx2peer, sizeof(void *) * idx2peer_elms);
182                 nextaction = time(NULL) + 3600;
183                 pfd[PFD_PIPE_MAIN].fd = ibuf_main->fd;
184                 pfd[PFD_PIPE_MAIN].events = POLLIN;
185
186                 i = 1;
187                 TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
188                         pfd[i].fd = la->fd;
189                         pfd[i].events = POLLIN;
190                         i++;
191                 }
192
193                 idx_peers = i;
194                 sent_cnt = 0;
195                 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
196                         if (p->next > 0 && p->next < nextaction)
197                                 nextaction = p->next;
198                         if (p->next > 0 && p->next <= time(NULL))
199                                 if (client_query(p) == 0)
200                                         sent_cnt++;
201
202                         if (p->deadline > 0 && p->deadline < nextaction)
203                                 nextaction = p->deadline;
204                         if (p->deadline > 0 && p->deadline <= time(NULL)) {
205                                 timeout = error_interval();
206                                 log_debug("no reply from %s received in time, "
207                                     "next query %ds", log_sockaddr(
208                                     (struct sockaddr *)&p->addr->ss), timeout);
209                                 if (p->trustlevel >= TRUSTLEVEL_BADPEER &&
210                                     (p->trustlevel /= 2) < TRUSTLEVEL_BADPEER)
211                                         log_info("peer %s now invalid",
212                                             log_sockaddr(
213                                             (struct sockaddr *)&p->addr->ss));
214                                 client_nextaddr(p);
215                                 set_next(p, timeout);
216                         }
217
218                         if (p->state == STATE_QUERY_SENT) {
219                                 pfd[i].fd = p->query->fd;
220                                 pfd[i].events = POLLIN;
221                                 idx2peer[i - idx_peers] = p;
222                                 i++;
223                         }
224                 }
225
226                 if (sent_cnt == 0 && conf->settime)
227                         priv_settime(0);        /* no good peers, don't wait */
228
229                 if (ibuf_main->w.queued > 0)
230                         pfd[PFD_PIPE_MAIN].events |= POLLOUT;
231
232                 timeout = nextaction - time(NULL);
233                 if (timeout < 0)
234                         timeout = 0;
235
236                 if ((nfds = poll(pfd, i, timeout * 1000)) == -1)
237                         if (errno != EINTR) {
238                                 log_warn("poll error");
239                                 ntp_quit = 1;
240                         }
241
242                 if (nfds > 0 && (pfd[PFD_PIPE_MAIN].revents & POLLOUT))
243                         if (msgbuf_write(&ibuf_main->w) < 0) {
244                                 log_warn("pipe write error (to parent)");
245                                 ntp_quit = 1;
246                         }
247
248                 if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & (POLLIN|POLLERR)) {
249                         nfds--;
250                         if (ntp_dispatch_imsg() == -1)
251                                 ntp_quit = 1;
252                 }
253
254                 for (j = 1; nfds > 0 && j < idx_peers; j++)
255                         if (pfd[j].revents & (POLLIN|POLLERR)) {
256                                 nfds--;
257                                 if (server_dispatch(pfd[j].fd, conf) == -1)
258                                         ntp_quit = 1;
259                         }
260
261                 for (; nfds > 0 && j < i; j++)
262                         if (pfd[j].revents & (POLLIN|POLLERR)) {
263                                 nfds--;
264                                 if (client_dispatch(idx2peer[j - idx_peers],
265                                     conf->settime) == -1)
266                                         ntp_quit = 1;
267                         }
268         }
269
270         msgbuf_write(&ibuf_main->w);
271         msgbuf_clear(&ibuf_main->w);
272         free(ibuf_main);
273
274         log_info("ntp engine exiting");
275         _exit(0);
276 }
277
278 int
279 ntp_dispatch_imsg(void)
280 {
281         struct imsg              imsg;
282         int                      n;
283         struct ntp_peer         *peer, *npeer;
284         u_int16_t                dlen;
285         u_char                  *p;
286         struct ntp_addr         *h;
287
288         if ((n = imsg_read(ibuf_main)) == -1)
289                 return (-1);
290
291         if (n == 0) {   /* connection closed */
292                 log_warnx("ntp_dispatch_imsg in ntp engine: pipe closed");
293                 return (-1);
294         }
295
296         for (;;) {
297                 if ((n = imsg_get(ibuf_main, &imsg)) == -1)
298                         return (-1);
299
300                 if (n == 0)
301                         break;
302
303                 switch (imsg.hdr.type) {
304                 case IMSG_HOST_DNS:
305                         TAILQ_FOREACH(peer, &conf->ntp_peers, entry)
306                                 if (peer->id == imsg.hdr.peerid)
307                                         break;
308                         if (peer == NULL) {
309                                 log_warnx("IMSG_HOST_DNS with invalid peerID");
310                                 break;
311                         }
312                         if (peer->addr != NULL) {
313                                 log_warnx("IMSG_HOST_DNS but addr != NULL!");
314                                 break;
315                         }
316                         dlen = imsg.hdr.len - IMSG_HEADER_SIZE;
317                         p = (u_char *)imsg.data;
318                         while (dlen >= sizeof(struct sockaddr_storage)) {
319                                 if ((h = calloc(1, sizeof(struct ntp_addr))) ==
320                                     NULL)
321                                         fatal(NULL);
322                                 memcpy(&h->ss, p, sizeof(h->ss));
323                                 p += sizeof(h->ss);
324                                 dlen -= sizeof(h->ss);
325                                 if (peer->addr_head.pool) {
326                                         npeer = new_peer();
327                                         h->next = NULL;
328                                         npeer->addr = h;
329                                         npeer->addr_head.a = h;
330                                         client_peer_init(npeer);
331                                         peer_add(npeer);
332                                 } else {
333                                         h->next = peer->addr;
334                                         peer->addr = h;
335                                         peer->addr_head.a = peer->addr;
336                                 }
337                         }
338                         if (dlen != 0)
339                                 fatal("IMSG_HOST_DNS: dlen != 0");
340                         if (peer->addr_head.pool)
341                                 peer_remove(peer);
342                         else
343                                 client_addr_init(peer);
344                         break;
345                 default:
346                         break;
347                 }
348                 imsg_free(&imsg);
349         }
350         return (0);
351 }
352
353 void
354 peer_add(struct ntp_peer *p)
355 {
356         TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
357         peer_cnt++;
358 }
359
360 void
361 peer_remove(struct ntp_peer *p)
362 {
363         TAILQ_REMOVE(&conf->ntp_peers, p, entry);
364         free(p);
365         peer_cnt--;
366 }
367
368 void
369 priv_adjtime(void)
370 {
371         struct ntp_peer  *p;
372         int               offset_cnt = 0, i = 0;
373         struct ntp_peer **peers;
374         double            offset_median;
375
376         TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
377                 if (p->trustlevel < TRUSTLEVEL_BADPEER)
378                         continue;
379                 if (!p->update.good)
380                         return;
381                 offset_cnt++;
382         }
383
384         if ((peers = calloc(offset_cnt, sizeof(struct ntp_peer *))) == NULL)
385                 fatal("calloc ntp_adjtime");
386
387         TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
388                 if (p->trustlevel < TRUSTLEVEL_BADPEER)
389                         continue;
390                 peers[i++] = p;
391         }
392
393         qsort(peers, offset_cnt, sizeof(struct ntp_peer *), offset_compare);
394
395         if (offset_cnt > 0) {
396                 if (offset_cnt > 1 && offset_cnt % 2 == 0) {
397                         offset_median =
398                             (peers[offset_cnt / 2 - 1]->update.offset +
399                             peers[offset_cnt / 2]->update.offset) / 2;
400                         conf->status.rootdelay =
401                             (peers[offset_cnt / 2 - 1]->update.delay +
402                             peers[offset_cnt / 2]->update.delay) / 2;
403                         conf->status.stratum = MAX(
404                             peers[offset_cnt / 2 - 1]->update.status.stratum,
405                             peers[offset_cnt / 2]->update.status.stratum);
406                 } else {
407                         offset_median = peers[offset_cnt / 2]->update.offset;
408                         conf->status.rootdelay =
409                             peers[offset_cnt / 2]->update.delay;
410                         conf->status.stratum =
411                             peers[offset_cnt / 2]->update.status.stratum;
412                 }
413
414                 imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0,
415                     &offset_median, sizeof(offset_median));
416
417                 conf->status.reftime = gettime();
418                 conf->status.leap = LI_NOWARNING;
419                 conf->status.stratum++; /* one more than selected peer */
420                 update_scale(offset_median);
421
422                 if (peers[offset_cnt / 2]->addr->ss.ss_family == AF_INET)
423                         conf->status.refid = ((struct sockaddr_in *)
424                             &peers[offset_cnt / 2]->addr->ss)->sin_addr.s_addr;
425         }
426
427         free(peers);
428
429         TAILQ_FOREACH(p, &conf->ntp_peers, entry)
430                 p->update.good = 0;
431 }
432
433 int
434 offset_compare(const void *aa, const void *bb)
435 {
436         const struct ntp_peer * const *a;
437         const struct ntp_peer * const *b;
438
439         a = aa;
440         b = bb;
441
442         if ((*a)->update.offset < (*b)->update.offset)
443                 return (-1);
444         else if ((*a)->update.offset > (*b)->update.offset)
445                 return (1);
446         else
447                 return (0);
448 }
449
450 void
451 priv_settime(double offset)
452 {
453         imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &offset, sizeof(offset));
454         conf->settime = 0;
455 }
456
457 void
458 priv_host_dns(char *name, u_int32_t peerid)
459 {
460         u_int16_t       dlen;
461
462         dlen = strlen(name) + 1;
463         imsg_compose(ibuf_main, IMSG_HOST_DNS, peerid, 0, name, dlen);
464 }
465
466 void
467 update_scale(double offset)
468 {
469         if (offset < 0)
470                 offset = -offset;
471
472         if (offset > QSCALE_OFF_MAX)
473                 conf->scale = 1;
474         else if (offset < QSCALE_OFF_MIN)
475                 conf->scale = QSCALE_OFF_MAX / QSCALE_OFF_MIN;
476         else
477                 conf->scale = QSCALE_OFF_MAX / offset;
478 }
479
480 time_t
481 scale_interval(time_t requested)
482 {
483         time_t interval, r;
484
485         interval = requested * conf->scale;
486         r = arc4random() % MAX(5, interval / 10);
487         return (interval + r);
488 }
489
490 time_t
491 error_interval(void)
492 {
493         time_t interval, r;
494
495         interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN;
496         r = arc4random() % (interval / 10);
497         return (interval + r);
498 }
499