-/* $OpenBSD: constraint.c,v 1.18 2015/10/09 03:50:40 deraadt Exp $ */
+/* $OpenBSD: constraint.c,v 1.19 2015/10/12 06:50:08 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/resource.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <fcntl.h>
#include <imsg.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
+#include <ctype.h>
#include <tls.h>
-#include <err.h>
+#include <pwd.h>
#include "log.h"
#include "ntpd.h"
constraint_byfd(int);
struct constraint *
constraint_bypid(pid_t);
-int constraint_close(int);
+int constraint_close(u_int32_t);
void constraint_update(void);
void constraint_reset(void);
int constraint_cmp(const void *, const void *);
+void priv_constraint_close(int, int);
+void priv_constraint_child(struct constraint *, struct ntp_addr_msg *,
+ u_int8_t *, int[2]);
+
struct httpsdate *
httpsdate_init(const char *, const char *, const char *,
const char *, const u_int8_t *, size_t);
char *tls_readline(struct tls *, size_t *, size_t *, struct timeval *);
-extern u_int constraint_cnt;
+u_int constraint_cnt;
extern u_int peer_cnt;
+extern struct imsgbuf *ibuf; /* priv */
+extern struct imsgbuf *ibuf_main; /* chld */
struct httpsdate {
char *tls_host;
int
constraint_query(struct constraint *cstr)
{
- int pipes[2];
- struct timeval rectv, xmttv;
- void *ctx;
- static char hname[NI_MAXHOST];
- time_t now;
- struct iovec iov[2];
+ time_t now;
+ struct ntp_addr_msg am;
+ struct iovec iov[3];
+ int iov_cnt = 0;
now = getmonotime();
/* Reset and retry */
cstr->senderrors = 0;
- constraint_close(cstr->fd);
+ constraint_close(cstr->id);
break;
case STATE_REPLY_RECEIVED:
default:
}
cstr->last = now;
- if (getnameinfo((struct sockaddr *)&cstr->addr->ss,
- SA_LEN((struct sockaddr *)&cstr->addr->ss),
- hname, sizeof(hname), NULL, 0,
- NI_NUMERICHOST) != 0)
- fatalx("%s getnameinfo %s", __func__, cstr->addr_head.name);
+ cstr->state = STATE_QUERY_SENT;
- log_debug("constraint request to %s", hname);
+ memset(&am, 0, sizeof(am));
+ memcpy(&am.a, cstr->addr, sizeof(am.a));
+
+ iov[iov_cnt].iov_base = &am;
+ iov[iov_cnt++].iov_len = sizeof(am);
+ if (cstr->addr_head.name) {
+ am.namelen = strlen(cstr->addr_head.name) + 1;
+ iov[iov_cnt].iov_base = cstr->addr_head.name;
+ iov[iov_cnt++].iov_len = am.namelen;
+ }
+ if (cstr->addr_head.path) {
+ am.pathlen = strlen(cstr->addr_head.path) + 1;
+ iov[iov_cnt].iov_base = cstr->addr_head.path;
+ iov[iov_cnt++].iov_len = am.pathlen;
+ }
+
+ imsg_composev(ibuf_main, IMSG_CONSTRAINT_QUERY,
+ cstr->id, 0, -1, iov, iov_cnt);
+
+ return (0);
+}
+
+void
+priv_constraint_msg(u_int32_t id, u_int8_t *data, size_t len)
+{
+ struct ntp_addr_msg am;
+ struct ntp_addr *h;
+ struct constraint *cstr;
+ int pipes[2];
+
+ if ((cstr = constraint_byid(id)) != NULL) {
+ log_warnx("IMSG_CONSTRAINT_QUERY repeated for id %d", id);
+ return;
+ }
+
+ if (len < sizeof(am)) {
+ log_warnx("invalid IMSG_CONSTRAINT_QUERY received");
+ return;
+ }
+ memcpy(&am, data, sizeof(am));
+ if (len != (sizeof(am) + am.namelen + am.pathlen)) {
+ log_warnx("invalid IMSG_CONSTRAINT_QUERY received");
+ return;
+ }
+ /* Additional imsg data is obtained in the unpriv child */
+
+ if ((h = calloc(1, sizeof(*h))) == NULL)
+ fatal("calloc ntp_addr");
+ memcpy(h, &am.a, sizeof(*h));
+ h->next = NULL;
+
+ cstr = new_constraint();
+ cstr->id = id;
+ cstr->addr = h;
+ cstr->addr_head.a = h;
+ constraint_add(cstr);
+ constraint_cnt++;
if (socketpair(AF_UNIX, SOCK_DGRAM, AF_UNSPEC, pipes) == -1)
fatal("%s pipes", __func__);
- /* Fork child handlers */
+ /*
+ * Fork child handlers and make sure to do any sensitive work in the
+ * the (unprivileged) child. The parent should not do any parsing,
+ * certificate loading etc.
+ */
switch (cstr->pid = fork()) {
case -1:
cstr->senderrors++;
close(pipes[0]);
close(pipes[1]);
- return (-1);
+ return;
case 0:
- setproctitle("constraint from %s", hname);
-
- if (pledge("stdio inet", NULL) == -1)
- err(1, "pledge");
-
- /* Child process */
- if (dup2(pipes[1], CONSTRAINT_PASSFD) == -1)
- fatal("%s dup2 CONSTRAINT_PASSFD", __func__);
- if (pipes[0] != CONSTRAINT_PASSFD)
- close(pipes[0]);
- if (pipes[1] != CONSTRAINT_PASSFD)
- close(pipes[1]);
- (void)closefrom(CONSTRAINT_PASSFD + 1);
-
- if (fcntl(CONSTRAINT_PASSFD, F_SETFD, FD_CLOEXEC) == -1)
- fatal("%s fcntl F_SETFD", __func__);
-
- cstr->fd = CONSTRAINT_PASSFD;
- imsg_init(&cstr->ibuf, cstr->fd);
-
- if ((ctx = httpsdate_query(hname,
- CONSTRAINT_PORT, cstr->addr_head.name, cstr->addr_head.path,
- conf->ca, conf->ca_len, &rectv, &xmttv)) == NULL) {
- /* Abort with failure but without warning */
- exit(1);
- }
-
- iov[0].iov_base = &rectv;
- iov[0].iov_len = sizeof(rectv);
- iov[1].iov_base = &xmttv;
- iov[1].iov_len = sizeof(xmttv);
- imsg_composev(&cstr->ibuf, IMSG_CONSTRAINT, 0, 0, -1, iov, 2);
- imsg_flush(&cstr->ibuf);
-
- /* Tear down the TLS connection after sending the result */
- httpsdate_free(ctx);
+ priv_constraint_child(cstr, &am, data + sizeof(am), pipes);
_exit(0);
/* NOTREACHED */
/* Parent */
close(pipes[1]);
cstr->fd = pipes[0];
- cstr->state = STATE_QUERY_SENT;
imsg_init(&cstr->ibuf, cstr->fd);
break;
}
+}
+
+void
+priv_constraint_child(struct constraint *cstr, struct ntp_addr_msg *am,
+ u_int8_t *data, int pipes[2])
+{
+ static char hname[NI_MAXHOST];
+ struct timeval rectv, xmttv;
+ struct sigaction sa;
+ struct passwd *pw;
+ void *ctx;
+ struct iovec iov[2];
+ int i;
+
+ if (setpriority(PRIO_PROCESS, 0, 0) == -1)
+ log_warn("could not set priority");
+
+ /* Init TLS and load cert before chroot() */
+ if (tls_init() == -1)
+ fatalx("tls_init");
+ if ((conf->ca = tls_load_file(CONSTRAINT_CA,
+ &conf->ca_len, NULL)) == NULL)
+ log_warnx("constraint certificate verification turned off");
+
+ /* Drop privileges */
+ if ((pw = getpwnam(NTPD_USER)) == NULL)
+ fatalx("unknown user %s", NTPD_USER);
+
+ if (chroot(pw->pw_dir) == -1)
+ fatal("chroot");
+ if (chdir("/") == -1)
+ fatal("chdir(\"/\")");
+
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ fatal("can't drop privileges");
+
+ /* Reset all signal handlers */
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sa.sa_handler = SIG_DFL;
+ for (i = 1; i < _NSIG; i++)
+ sigaction(i, &sa, NULL);
+
+ if (pledge("stdio inet", NULL) == -1)
+ fatal("pledge");
+
+ /* Get name and set process title */
+ if (getnameinfo((struct sockaddr *)&cstr->addr->ss,
+ SA_LEN((struct sockaddr *)&cstr->addr->ss),
+ hname, sizeof(hname), NULL, 0,
+ NI_NUMERICHOST) != 0)
+ fatalx("%s getnameinfo", __func__);
+ log_debug("constraint request to %s", hname);
+ setproctitle("constraint from %s", hname);
- return (0);
+ /* Set file descriptors */
+ if (dup2(pipes[1], CONSTRAINT_PASSFD) == -1)
+ fatal("%s dup2 CONSTRAINT_PASSFD", __func__);
+ if (pipes[0] != CONSTRAINT_PASSFD)
+ close(pipes[0]);
+ if (pipes[1] != CONSTRAINT_PASSFD)
+ close(pipes[1]);
+ (void)closefrom(CONSTRAINT_PASSFD + 1);
+
+ if (fcntl(CONSTRAINT_PASSFD, F_SETFD, FD_CLOEXEC) == -1)
+ fatal("%s fcntl F_SETFD", __func__);
+
+ cstr->fd = CONSTRAINT_PASSFD;
+ imsg_init(&cstr->ibuf, cstr->fd);
+
+ /* Get remaining data from imsg in the unpriv child */
+ if (am->namelen) {
+ if ((cstr->addr_head.name =
+ get_string(data, am->namelen)) == NULL)
+ fatalx("invalid IMSG_CONSTRAINT_QUERY name");
+ data += am->namelen;
+ }
+ if (am->pathlen) {
+ if ((cstr->addr_head.path =
+ get_string(data, am->pathlen)) == NULL)
+ fatalx("invalid IMSG_CONSTRAINT_QUERY path");
+ }
+
+ /* Run! */
+ if ((ctx = httpsdate_query(hname,
+ CONSTRAINT_PORT, cstr->addr_head.name, cstr->addr_head.path,
+ conf->ca, conf->ca_len, &rectv, &xmttv)) == NULL) {
+ /* Abort with failure but without warning */
+ exit(1);
+ }
+
+ iov[0].iov_base = &rectv;
+ iov[0].iov_len = sizeof(rectv);
+ iov[1].iov_base = &xmttv;
+ iov[1].iov_len = sizeof(xmttv);
+ imsg_composev(&cstr->ibuf,
+ IMSG_CONSTRAINT_RESULT, 0, 0, -1, iov, 2);
+ imsg_flush(&cstr->ibuf);
+
+ /* Tear down the TLS connection after sending the result */
+ httpsdate_free(ctx);
}
void
-constraint_check_child(void)
+priv_constraint_check_child(pid_t pid, int status)
{
struct constraint *cstr;
- int status;
int fail, sig;
- pid_t pid;
-
- do {
- pid = waitpid(WAIT_ANY, &status, WNOHANG);
- if (pid <= 0)
- continue;
- fail = sig = 0;
- if (WIFSIGNALED(status)) {
- sig = WTERMSIG(status);
- } else if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) != 0)
- fail = 1;
- } else
- fatalx("unexpected cause of SIGCHLD");
-
- if ((cstr = constraint_bypid(pid)) != NULL) {
- if (sig)
- fatalx("constraint %s, signal %d",
- log_sockaddr((struct sockaddr *)
- &cstr->addr->ss), sig);
- if (fail) {
- log_debug("no constraint reply from %s"
- " received in time, next query %ds",
- log_sockaddr((struct sockaddr *)
- &cstr->addr->ss), CONSTRAINT_SCAN_INTERVAL);
- }
-
- if (fail || cstr->state < STATE_QUERY_SENT) {
- cstr->senderrors++;
- constraint_close(cstr->fd);
- }
- }
- } while (pid > 0 || (pid == -1 && errno == EINTR));
+ fail = sig = 0;
+ if (WIFSIGNALED(status)) {
+ sig = WTERMSIG(status);
+ } else if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0)
+ fail = 1;
+ } else
+ fatalx("unexpected cause of SIGCHLD");
+
+ if ((cstr = constraint_bypid(pid)) != NULL) {
+ if (sig)
+ fatalx("constraint %s, signal %d",
+ log_sockaddr((struct sockaddr *)
+ &cstr->addr->ss), sig);
+
+ priv_constraint_close(cstr->fd, fail);
+ }
}
struct constraint *
}
int
-constraint_close(int fd)
+constraint_close(u_int32_t id)
{
struct constraint *cstr;
- if ((cstr = constraint_byfd(fd)) == NULL) {
- log_warn("%s: fd %d: not found", __func__, fd);
+ if ((cstr = constraint_byid(id)) == NULL) {
+ log_warn("%s: id %d: not found", __func__, id);
return (0);
}
- msgbuf_clear(&cstr->ibuf.w);
- close(cstr->fd);
- cstr->fd = -1;
cstr->last = getmonotime();
if (cstr->addr == NULL || (cstr->addr = cstr->addr->next) == NULL) {
return (constraint_init(cstr));
}
+void
+priv_constraint_close(int fd, int fail)
+{
+ struct constraint *cstr;
+ u_int32_t id;
+
+ if ((cstr = constraint_byfd(fd)) == NULL) {
+ log_warn("%s: fd %d: not found", __func__, fd);
+ return;
+ }
+
+ id = cstr->id;
+ constraint_remove(cstr);
+ constraint_cnt--;
+
+ imsg_compose(ibuf, IMSG_CONSTRAINT_CLOSE, id, 0, -1,
+ &fail, sizeof(fail));
+}
+
void
constraint_add(struct constraint *cstr)
{
constraint_remove(struct constraint *cstr)
{
TAILQ_REMOVE(&conf->constraints, cstr, entry);
+
+ msgbuf_clear(&cstr->ibuf.w);
+ if (cstr->fd != -1)
+ close(cstr->fd);
free(cstr->addr_head.name);
free(cstr->addr_head.path);
free(cstr);
}
+void
+constraint_purge(void)
+{
+ struct constraint *cstr, *ncstr;
+
+ TAILQ_FOREACH_SAFE(cstr, &conf->constraints, entry, ncstr)
+ constraint_remove(cstr);
+}
+
int
-constraint_dispatch_msg(struct pollfd *pfd)
+priv_constraint_dispatch(struct pollfd *pfd)
{
struct imsg imsg;
struct constraint *cstr;
ssize_t n;
struct timeval tv[2];
- double offset;
if ((cstr = constraint_byfd(pfd->fd)) == NULL)
return (0);
return (0);
if ((n = imsg_read(&cstr->ibuf)) == -1 || n == 0) {
- constraint_close(pfd->fd);
+ priv_constraint_close(pfd->fd, 1);
return (1);
}
for (;;) {
if ((n = imsg_get(&cstr->ibuf, &imsg)) == -1) {
- constraint_close(pfd->fd);
+ priv_constraint_close(pfd->fd, 1);
return (1);
}
if (n == 0)
break;
switch (imsg.hdr.type) {
- case IMSG_CONSTRAINT:
+ case IMSG_CONSTRAINT_RESULT:
if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(tv))
fatalx("invalid IMSG_CONSTRAINT received");
- memcpy(tv, imsg.data, sizeof(tv));
-
- offset = gettime_from_timeval(&tv[0]) -
- gettime_from_timeval(&tv[1]);
-
- log_info("constraint reply from %s: offset %f",
- log_sockaddr((struct sockaddr *)&cstr->addr->ss),
- offset);
-
- cstr->state = STATE_REPLY_RECEIVED;
- cstr->last = getmonotime();
- cstr->constraint = tv[0].tv_sec;
-
- constraint_update();
+ /* forward imsg to ntp child, don't parse it here */
+ imsg_compose(ibuf, imsg.hdr.type,
+ cstr->id, 0, -1, imsg.data, sizeof(tv));
break;
default:
break;
}
void
-constraint_dns(u_int32_t id, u_int8_t *data, size_t len)
+constraint_msg_result(u_int32_t id, u_int8_t *data, size_t len)
+{
+ struct constraint *cstr;
+ struct timeval tv[2];
+ double offset;
+
+ if ((cstr = constraint_byid(id)) == NULL) {
+ log_warnx("IMSG_CONSTRAINT_CLOSE with invalid constraint id");
+ return;
+ }
+
+ if (len != sizeof(tv)) {
+ log_warnx("invalid IMSG_CONSTRAINT received");
+ return;
+ }
+
+ memcpy(tv, data, len);
+
+ offset = gettime_from_timeval(&tv[0]) -
+ gettime_from_timeval(&tv[1]);
+
+ log_info("constraint reply from %s: offset %f",
+ log_sockaddr((struct sockaddr *)&cstr->addr->ss),
+ offset);
+
+ cstr->state = STATE_REPLY_RECEIVED;
+ cstr->last = getmonotime();
+ cstr->constraint = tv[0].tv_sec;
+
+ constraint_update();
+}
+
+void
+constraint_msg_close(u_int32_t id, u_int8_t *data, size_t len)
+{
+ struct constraint *cstr;
+ int fail;
+
+ if ((cstr = constraint_byid(id)) == NULL) {
+ log_warnx("IMSG_CONSTRAINT_CLOSE with invalid constraint id");
+ return;
+ }
+
+ if (len != sizeof(int)) {
+ log_warnx("invalid IMSG_CONSTRAINT_CLOSE received");
+ return;
+ }
+
+ memcpy(&fail, data, len);
+
+ if (fail) {
+ log_debug("no constraint reply from %s"
+ " received in time, next query %ds",
+ log_sockaddr((struct sockaddr *)
+ &cstr->addr->ss), CONSTRAINT_SCAN_INTERVAL);
+ }
+
+ if (fail || cstr->state < STATE_QUERY_SENT) {
+ cstr->senderrors++;
+ constraint_close(cstr->id);
+ }
+}
+
+void
+constraint_msg_dns(u_int32_t id, u_int8_t *data, size_t len)
{
struct constraint *cstr, *ncstr = NULL;
u_int8_t *p;
TAILQ_FOREACH(cstr, &conf->constraints, entry) {
if (cstr->state == STATE_QUERY_SENT)
continue;
- constraint_close(cstr->fd);
+ constraint_close(cstr->id);
}
conf->constraint_errors = 0;
}
{
struct httpsdate *httpsdate = NULL;
- if (tls_init() == -1)
- return (NULL);
-
if ((httpsdate = calloc(1, sizeof(*httpsdate))) == NULL)
goto fail;
fatal("gettimeofday");
return (buf);
}
+
+char *
+get_string(u_int8_t *ptr, size_t len)
+{
+ size_t i;
+ char *str;
+
+ for (i = 0; i < len; i++)
+ if (!(isprint(ptr[i]) || isspace(ptr[i])))
+ break;
+
+ if ((str = calloc(1, i + 1)) == NULL)
+ return (NULL);
+ memcpy(str, ptr, i);
+
+ return (str);
+}
-/* $OpenBSD: ntp.c,v 1.136 2015/10/09 03:54:53 deraadt Exp $ */
+/* $OpenBSD: ntp.c,v 1.137 2015/10/12 06:50:08 reyk Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
#include <time.h>
#include <unistd.h>
#include <err.h>
-#include <tls.h>
#include "ntpd.h"
volatile sig_atomic_t ntp_quit = 0;
volatile sig_atomic_t ntp_report = 0;
-volatile sig_atomic_t ntp_sigchld = 0;
struct imsgbuf *ibuf_main;
struct imsgbuf *ibuf_dns;
struct ntpd_conf *conf;
struct ctl_conns ctl_conns;
u_int peer_cnt;
u_int sensors_cnt;
-u_int constraint_cnt;
+extern u_int constraint_cnt;
time_t lastreport;
void ntp_sighdlr(int);
case SIGINFO:
ntp_report = 1;
break;
- case SIGCHLD:
- ntp_sigchld = 1;
- break;
}
}
return (pid);
}
- tls_init();
-
- /* Verification will be turned off if CA is not found */
- if ((conf->ca = tls_load_file(CONSTRAINT_CA,
- &conf->ca_len, NULL)) == NULL)
- log_warnx("constraint certificate verification turned off");
-
/* in this case the parent didn't init logging and didn't daemonize */
if (nconf->settime && !nconf->debug) {
log_init(nconf->debug);
endservent();
- /*
- * XXX
- * Unfortunately, the "contraint" processes are forked
- * below the "ntp engine". Hence the ntp engine needs
- * to be able to fork -> "proc", and the "constraint"
- * process will want to open sockets -> "inet".
- *
- * For many reasons, including fork/exec cost, it would
- * be better if constraints were forked from the master
- * process, which would then tell the ntp engine.
- */
- if (pledge("stdio inet proc", NULL) == -1)
+ /* The ntp process will want to open NTP client sockets -> "inet" */
+ if (pledge("stdio inet", NULL) == -1)
err(1, "pledge");
signal(SIGTERM, ntp_sighdlr);
signal(SIGINFO, ntp_sighdlr);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, SIG_IGN);
- signal(SIGCHLD, ntp_sighdlr);
+ signal(SIGCHLD, SIG_DFL);
if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
fatal(NULL);
}
new_cnt = PFD_MAX +
- peer_cnt + listener_cnt + ctl_cnt + constraint_cnt;
+ peer_cnt + listener_cnt + ctl_cnt;
if (new_cnt > pfd_elms) {
if ((newp = reallocarray(pfd, new_cnt,
sizeof(*pfd))) == NULL) {
TAILQ_FOREACH(cstr, &conf->constraints, entry) {
if (constraint_query(cstr) == -1)
continue;
- pfd[i].fd = cstr->fd;
- pfd[i].events = POLLIN;
- i++;
}
now = getmonotime();
nfds -= control_dispatch_msg(&pfd[j], &ctl_cnt);
}
- for (; nfds > 0 && j < i; j++) {
- nfds -= constraint_dispatch_msg(&pfd[j]);
- }
-
for (s = TAILQ_FIRST(&conf->ntp_sensors); s != NULL;
s = next_s) {
next_s = TAILQ_NEXT(s, entry);
}
report_peers(ntp_report);
ntp_report = 0;
-
- if (ntp_sigchld) {
- constraint_check_child();
- ntp_sigchld = 0;
- }
}
msgbuf_write(&ibuf_main->w);
conf->status.synced = 0;
}
break;
+ case IMSG_CONSTRAINT_RESULT:
+ constraint_msg_result(imsg.hdr.peerid,
+ imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
+ break;
+ case IMSG_CONSTRAINT_CLOSE:
+ constraint_msg_close(imsg.hdr.peerid,
+ imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
+ break;
default:
break;
}
client_addr_init(peer);
break;
case IMSG_CONSTRAINT_DNS:
- constraint_dns(imsg.hdr.peerid,
+ constraint_msg_dns(imsg.hdr.peerid,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
break;
default:
-/* $OpenBSD: ntpd.c,v 1.96 2015/10/09 01:37:09 deraadt Exp $ */
+/* $OpenBSD: ntpd.c,v 1.97 2015/10/12 06:50:08 reyk Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
struct imsgbuf *ibuf;
int timeout = INFTIM;
+extern u_int constraint_cnt;
+
const char *showopt;
static const char *ctl_showopt_list[] = {
#define POLL_MAX 8
#define PFD_PIPE 0
+#define PFD_MAX 1
int
main(int argc, char *argv[])
{
struct ntpd_conf lconf;
- struct pollfd pfd[POLL_MAX];
+ struct pollfd *pfd = NULL;
pid_t chld_pid = 0, pid;
const char *conffile;
- int fd_ctl, ch, nfds;
+ int fd_ctl, ch, nfds, i, j;
int pipe_chld[2];
struct passwd *pw;
extern char *__progname;
+ u_int pfd_elms = 0, new_cnt;
+ struct constraint *cstr;
+ void *newp;
if (strcmp(__progname, "ntpctl") == 0) {
ctl_main(argc, argv);
signal(SIGHUP, sighdlr);
close(pipe_chld[1]);
+ constraint_purge();
if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
fatal(NULL);
imsg_init(ibuf, pipe_chld[0]);
+ constraint_cnt = 0;
+
while (quit == 0) {
+ new_cnt = PFD_MAX + constraint_cnt;
+ if (new_cnt > pfd_elms) {
+ if ((newp = reallocarray(pfd, new_cnt,
+ sizeof(*pfd))) == NULL) {
+ /* panic for now */
+ log_warn("could not resize pfd from %u -> "
+ "%u entries", pfd_elms, new_cnt);
+ fatalx("exiting");
+ }
+ pfd = newp;
+ pfd_elms = new_cnt;
+ }
+
+ memset(pfd, 0, sizeof(*pfd) * pfd_elms);
pfd[PFD_PIPE].fd = ibuf->fd;
pfd[PFD_PIPE].events = POLLIN;
if (ibuf->w.queued)
pfd[PFD_PIPE].events |= POLLOUT;
- if ((nfds = poll(pfd, 1, timeout)) == -1)
+ i = PFD_MAX;
+ TAILQ_FOREACH(cstr, &conf->constraints, entry) {
+ pfd[i].fd = cstr->fd;
+ pfd[i].events = POLLIN;
+ i++;
+ }
+
+ if ((nfds = poll(pfd, i, timeout)) == -1)
if (errno != EINTR) {
log_warn("poll error");
quit = 1;
quit = 1;
}
+ for (j = PFD_MAX; nfds > 0 && j < i; j++) {
+ nfds -= priv_constraint_dispatch(&pfd[j]);
+ }
+
if (sigchld) {
if (check_child(chld_pid, "child")) {
quit = 1;
}
int
-check_child(pid_t pid, const char *pname)
+check_child(pid_t chld_pid, const char *pname)
{
int status, sig;
char *signame;
+ pid_t pid;
- if (waitpid(pid, &status, WNOHANG) > 0) {
- if (WIFEXITED(status)) {
- log_warnx("Lost child: %s exited", pname);
- return (1);
- }
- if (WIFSIGNALED(status)) {
- sig = WTERMSIG(status);
- signame = strsignal(sig) ? strsignal(sig) : "unknown";
- log_warnx("Lost child: %s terminated; signal %d (%s)",
- pname, sig, signame);
- return (1);
+ do {
+ pid = waitpid(WAIT_ANY, &status, WNOHANG);
+ if (pid <= 0) {
+ continue;
+ } else if (pid == chld_pid) {
+ if (WIFEXITED(status)) {
+ log_warnx("Lost child: %s exited", pname);
+ return (1);
+ }
+ if (WIFSIGNALED(status)) {
+ sig = WTERMSIG(status);
+ signame = strsignal(sig) ?
+ strsignal(sig) : "unknown";
+ log_warnx("Lost child: %s terminated; "
+ "signal %d (%s)", pname, sig, signame);
+ return (1);
+ }
+ } else {
+ priv_constraint_check_child(pid, status);
}
- }
+ } while (pid > 0 || (pid == -1 && errno == EINTR));
return (0);
}
lconf->settime = 0;
timeout = INFTIM;
break;
+ case IMSG_CONSTRAINT_QUERY:
+ priv_constraint_msg(imsg.hdr.peerid,
+ imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
+ break;
default:
break;
}