1 /* $OpenBSD: src/usr.sbin/ntpd/ntp.c,v 1.44 2004/12/13 12:39:15 dtucker Exp $ */
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>
37 #define PFD_PIPE_MAIN 0
40 volatile sig_atomic_t ntp_quit = 0;
41 struct imsgbuf *ibuf_main;
42 struct ntpd_conf *conf;
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 *);
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;
69 struct pollfd *pfd = NULL;
72 struct listen_addr *la;
74 struct ntp_peer **idx2peer = NULL;
80 switch (pid = fork()) {
89 if ((se = getservbyname("ntp", "udp")) == NULL)
90 fatal("getservbyname");
92 if ((pw = getpwnam(NTPD_USER)) == NULL)
95 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
98 if (stat(pw->pw_dir, &stb) == -1)
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)
104 if (chdir("/") == -1)
105 fatal("chdir(\"/\")");
108 dup2(nullfd, STDIN_FILENO);
109 dup2(nullfd, STDOUT_FILENO);
110 dup2(nullfd, STDERR_FILENO);
114 setproctitle("ntp engine");
117 setup_listeners(se, conf, &listener_cnt);
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");
127 signal(SIGTERM, ntp_sighdlr);
128 signal(SIGINT, ntp_sighdlr);
129 signal(SIGPIPE, SIG_IGN);
130 signal(SIGHUP, SIG_IGN);
133 if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
135 imsg_init(ibuf_main, pipe_prnt[1]);
137 TAILQ_FOREACH(p, &conf->ntp_peers, entry)
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;
148 log_info("ntp engine ready");
151 TAILQ_FOREACH(p, &conf->ntp_peers, entry)
154 while (ntp_quit == 0) {
155 if (peer_cnt > idx2peer_elms) {
156 if ((newp = realloc(idx2peer, sizeof(void *) *
157 peer_cnt)) == NULL) {
159 log_warn("could not resize idx2peer from %u -> "
160 "%u entries", idx2peer_elms, peer_cnt);
164 idx2peer_elms = peer_cnt;
167 new_cnt = PFD_MAX + peer_cnt + listener_cnt;
168 if (new_cnt > pfd_elms) {
169 if ((newp = realloc(pfd, sizeof(struct pollfd) *
172 log_warn("could not resize pfd from %u -> "
173 "%u entries", pfd_elms, new_cnt);
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;
187 TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
189 pfd[i].events = POLLIN;
194 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
195 if (p->next > 0 && p->next < nextaction)
196 nextaction = p->next;
197 if (p->next > 0 && p->next <= time(NULL))
200 if (p->deadline > 0 && p->deadline < nextaction)
201 nextaction = p->deadline;
202 if (p->deadline > 0 && p->deadline <= time(NULL)) {
203 log_debug("no reply from %s received in time",
205 (struct sockaddr *)&p->addr->ss));
206 if (p->trustlevel >= TRUSTLEVEL_BADPEER &&
207 (p->trustlevel /= 2) < TRUSTLEVEL_BADPEER)
208 log_info("peer %s now invalid",
210 (struct sockaddr *)&p->addr->ss));
215 if (p->state == STATE_QUERY_SENT) {
216 pfd[i].fd = p->query->fd;
217 pfd[i].events = POLLIN;
218 idx2peer[i - idx_peers] = p;
223 if (ibuf_main->w.queued > 0)
224 pfd[PFD_PIPE_MAIN].events |= POLLOUT;
226 timeout = nextaction - time(NULL);
230 if ((nfds = poll(pfd, i, timeout * 1000)) == -1)
231 if (errno != EINTR) {
232 log_warn("poll error");
236 if (nfds > 0 && (pfd[PFD_PIPE_MAIN].revents & POLLOUT))
237 if (msgbuf_write(&ibuf_main->w) < 0) {
238 log_warn("pipe write error (to parent)");
242 if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & (POLLIN|POLLERR)) {
244 if (ntp_dispatch_imsg() == -1)
248 for (j = 1; nfds > 0 && j < idx_peers; j++)
249 if (pfd[j].revents & (POLLIN|POLLERR)) {
251 if (server_dispatch(pfd[j].fd, conf) == -1)
255 for (; nfds > 0 && j < i; j++)
256 if (pfd[j].revents & (POLLIN|POLLERR)) {
258 if (client_dispatch(idx2peer[j - idx_peers],
259 conf->settime) == -1)
264 msgbuf_write(&ibuf_main->w);
265 msgbuf_clear(&ibuf_main->w);
268 log_info("ntp engine exiting");
273 ntp_dispatch_imsg(void)
277 struct ntp_peer *peer, *npeer;
282 if ((n = imsg_read(ibuf_main)) == -1)
285 if (n == 0) { /* connection closed */
286 log_warnx("ntp_dispatch_imsg in ntp engine: pipe closed");
291 if ((n = imsg_get(ibuf_main, &imsg)) == -1)
297 switch (imsg.hdr.type) {
299 TAILQ_FOREACH(peer, &conf->ntp_peers, entry)
300 if (peer->id == imsg.hdr.peerid)
303 log_warnx("IMSG_HOST_DNS with invalid peerID");
306 if (peer->addr != NULL) {
307 log_warnx("IMSG_HOST_DNS but addr != NULL!");
310 dlen = imsg.hdr.len - IMSG_HEADER_SIZE;
311 p = (u_char *)imsg.data;
312 while (dlen >= sizeof(struct sockaddr_storage)) {
313 if ((h = calloc(1, sizeof(struct ntp_addr))) ==
316 memcpy(&h->ss, p, sizeof(h->ss));
318 dlen -= sizeof(h->ss);
319 if (peer->addr_head.pool) {
323 npeer->addr_head.a = h;
324 client_peer_init(npeer);
327 h->next = peer->addr;
329 peer->addr_head.a = peer->addr;
333 fatal("IMSG_HOST_DNS: dlen != 0");
334 if (peer->addr_head.pool)
337 client_addr_init(peer);
348 peer_add(struct ntp_peer *p)
350 TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
355 peer_remove(struct ntp_peer *p)
357 TAILQ_REMOVE(&conf->ntp_peers, p, entry);
366 int offset_cnt = 0, i = 0;
367 struct ntp_peer **peers;
368 double offset_median;
370 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
371 if (p->trustlevel < TRUSTLEVEL_BADPEER)
378 if ((peers = calloc(offset_cnt, sizeof(struct ntp_peer *))) == NULL)
379 fatal("calloc ntp_adjtime");
381 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
382 if (p->trustlevel < TRUSTLEVEL_BADPEER)
387 qsort(peers, offset_cnt, sizeof(struct ntp_peer *), offset_compare);
389 if (offset_cnt > 0) {
390 if (offset_cnt > 1 && offset_cnt % 2 == 0) {
392 (peers[offset_cnt / 2 - 1]->update.offset +
393 peers[offset_cnt / 2]->update.offset) / 2;
394 conf->status.rootdelay =
395 (peers[offset_cnt / 2 - 1]->update.delay +
396 peers[offset_cnt / 2]->update.delay) / 2;
397 conf->status.stratum = MAX(
398 peers[offset_cnt / 2 - 1]->update.status.stratum,
399 peers[offset_cnt / 2]->update.status.stratum);
401 offset_median = peers[offset_cnt / 2]->update.offset;
402 conf->status.rootdelay =
403 peers[offset_cnt / 2]->update.delay;
404 conf->status.stratum =
405 peers[offset_cnt / 2]->update.status.stratum;
408 imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0,
409 &offset_median, sizeof(offset_median));
411 conf->status.reftime = gettime();
412 conf->status.leap = LI_NOWARNING;
413 conf->status.stratum++; /* one more than selected peer */
415 if (peers[offset_cnt / 2]->addr->ss.ss_family == AF_INET)
416 conf->status.refid = ((struct sockaddr_in *)
417 &peers[offset_cnt / 2]->addr->ss)->sin_addr.s_addr;
422 TAILQ_FOREACH(p, &conf->ntp_peers, entry)
427 offset_compare(const void *aa, const void *bb)
429 const struct ntp_peer * const *a;
430 const struct ntp_peer * const *b;
435 if ((*a)->update.offset < (*b)->update.offset)
437 else if ((*a)->update.offset > (*b)->update.offset)
444 priv_settime(double offset)
446 imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &offset, sizeof(offset));
451 priv_host_dns(char *name, u_int32_t peerid)
455 dlen = strlen(name) + 1;
456 imsg_compose(ibuf_main, IMSG_HOST_DNS, peerid, 0, name, dlen);