Sync with OpenBSD. This fixes the bug of -s not working and allows
[dragonfly.git] / contrib / ntpd / ntp.c
1 /*      $OpenBSD: src/usr.sbin/ntpd/ntp.c,v 1.55 2005/03/24 14:50:07 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, 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;
79
80         switch (pid = fork()) {
81         case -1:
82                 fatal("cannot fork");
83                 break;
84         case 0:
85                 break;
86         default:
87                 return (pid);
88         }
89
90         if ((se = getservbyname("ntp", "udp")) == NULL)
91                 fatal("getservbyname");
92
93         if ((pw = getpwnam(NTPD_USER)) == NULL)
94                 fatal("getpwnam");
95
96         if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
97                 fatal(NULL);
98
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(\"/\")");
107
108         if (!nconf->debug) {
109                 dup2(nullfd, STDIN_FILENO);
110                 dup2(nullfd, STDOUT_FILENO);
111                 dup2(nullfd, STDERR_FILENO);
112         }
113         close(nullfd);
114
115         setproctitle("ntp engine");
116
117         conf = nconf;
118         setup_listeners(se, conf, &listener_cnt);
119
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");
124
125         endpwent();
126         endservent();
127
128         signal(SIGTERM, ntp_sighdlr);
129         signal(SIGINT, ntp_sighdlr);
130         signal(SIGPIPE, SIG_IGN);
131         signal(SIGHUP, SIG_IGN);
132
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]);
137
138         TAILQ_FOREACH(p, &conf->ntp_peers, entry)
139                 client_peer_init(p);
140
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)
146                 ;
147         conf->status.precision = a;
148         conf->scale = 1;
149
150         log_info("ntp engine ready");
151
152         peer_cnt = 0;
153         TAILQ_FOREACH(p, &conf->ntp_peers, entry)
154                 peer_cnt++;
155
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");
164                         }
165                         idx2peer = newp;
166                         idx2peer_elms = peer_cnt;
167                 }
168
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");
177                         }
178                         pfd = newp;
179                         pfd_elms = new_cnt;
180                 }
181
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;
187
188                 i = 1;
189                 TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
190                         pfd[i].fd = la->fd;
191                         pfd[i].events = POLLIN;
192                         i++;
193                 }
194
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++;
204                         }
205
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);
220                         }
221
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++;
227                         }
228                 }
229
230                 if (trial_cnt > 0 && sent_cnt == 0 && conf->settime)
231                         priv_settime(0);        /* no good peers, don't wait */
232
233                 if (ibuf_main->w.queued > 0)
234                         pfd[PFD_PIPE_MAIN].events |= POLLOUT;
235
236                 timeout = nextaction - time(NULL);
237                 if (timeout < 0)
238                         timeout = 0;
239
240                 if ((nfds = poll(pfd, i, timeout * 1000)) == -1)
241                         if (errno != EINTR) {
242                                 log_warn("poll error");
243                                 ntp_quit = 1;
244                         }
245
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;
250                         }
251
252                 if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & (POLLIN|POLLERR)) {
253                         nfds--;
254                         if (ntp_dispatch_imsg() == -1)
255                                 ntp_quit = 1;
256                 }
257
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;
263                         }
264
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;
271                         }
272         }
273
274         msgbuf_write(&ibuf_main->w);
275         msgbuf_clear(&ibuf_main->w);
276         free(ibuf_main);
277
278         log_info("ntp engine exiting");
279         _exit(0);
280 }
281
282 int
283 ntp_dispatch_imsg(void)
284 {
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;
291
292         if ((n = imsg_read(ibuf_main)) == -1)
293                 return (-1);
294
295         if (n == 0) {   /* connection closed */
296                 log_warnx("ntp_dispatch_imsg in ntp engine: pipe closed");
297                 return (-1);
298         }
299
300         for (;;) {
301                 if ((n = imsg_get(ibuf_main, &imsg)) == -1)
302                         return (-1);
303
304                 if (n == 0)
305                         break;
306
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;
315                         }
316                         if (peer->addr != NULL) {
317                                 log_warnx("IMSG_HOST_DNS but addr != NULL!");
318                                 break;
319                         }
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;
340                                 }
341                         }
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;
351                 }
352                 imsg_free(&imsg);
353         }
354         return (0);
355 }
356
357 void
358 peer_add(struct ntp_peer *p)
359 {
360         TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
361         peer_cnt++;
362 }
363
364 void
365 peer_remove(struct ntp_peer *p)
366 {
367         TAILQ_REMOVE(&conf->ntp_peers, p, entry);
368         free(p);
369         peer_cnt--;
370 }
371
372 void
373 priv_adjtime(void)
374 {
375         struct ntp_peer  *p;
376         int               offset_cnt = 0, i = 0;
377         struct ntp_peer **peers;
378         double            offset_median;
379
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++;
386         }
387
388         if ((peers = calloc(offset_cnt, sizeof(struct ntp_peer *))) == NULL)
389                 fatal("calloc ntp_adjtime");
390
391         TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
392                 if (p->trustlevel < TRUSTLEVEL_BADPEER)
393                         continue;
394                 peers[i++] = p;
395         }
396
397         qsort(peers, offset_cnt, sizeof(struct ntp_peer *), offset_compare);
398
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;
416                 }
417
418                 imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0,
419                     &offset_median, sizeof(offset_median));
420
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);
425
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;
429         }
430
431         free(peers);
432
433         TAILQ_FOREACH(p, &conf->ntp_peers, entry)
434                 p->update.good = 0;
435 }
436
437 int
438 offset_compare(const void *aa, const void *bb)
439 {
440         const struct ntp_peer * const *a;
441         const struct ntp_peer * const *b;
442
443         a = aa;
444         b = bb;
445
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);
452 }
453
454 void
455 priv_settime(double offset)
456 {
457         imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &offset, sizeof(offset));
458         conf->settime = 0;
459 }
460
461 void
462 priv_host_dns(char *name, u_int32_t peerid)
463 {
464         u_int16_t       dlen;
465
466         dlen = strlen(name) + 1;
467         imsg_compose(ibuf_main, IMSG_HOST_DNS, peerid, 0, name, dlen);
468 }
469
470 void
471 update_scale(double offset)
472 {
473         if (offset < 0)
474                 offset = -offset;
475
476         if (offset > QSCALE_OFF_MAX)
477                 conf->scale = 1;
478         else if (offset < QSCALE_OFF_MIN)
479                 conf->scale = QSCALE_OFF_MAX / QSCALE_OFF_MIN;
480         else
481                 conf->scale = QSCALE_OFF_MAX / offset;
482 }
483
484 time_t
485 scale_interval(time_t requested)
486 {
487         time_t interval, r;
488
489         interval = requested * conf->scale;
490         r = arc4random() % MAX(5, interval / 10);
491         return (interval + r);
492 }
493
494 time_t
495 error_interval(void)
496 {
497         time_t interval, r;
498
499         interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN;
500         r = arc4random() % (interval / 10);
501         return (interval + r);
502 }
503