it is just capable of answering (s)ntp4 requests with the local time for now. imsg/buffer and logging framework from bgpd, ntp protocol hackery with Alexander GuyOPENBSD_3_6
@ -0,0 +1,15 @@ | |||||
# $OpenBSD: Makefile,v 1.1 2004/05/31 13:46:16 henning Exp $ | |||||
.PATH: ${.CURDIR}/.. | |||||
PROG= ntpd | |||||
SRCS= ntpd.c buffer.c log.c imsg.c ntp.c | |||||
CFLAGS+= -Wall -I${.CURDIR} | |||||
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes | |||||
CFLAGS+= -Wmissing-declarations | |||||
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual | |||||
CFLAGS+= -Wsign-compare | |||||
YFLAGS= | |||||
NOMAN= | |||||
.include <bsd.prog.mk> |
@ -0,0 +1,182 @@ | |||||
/* $OpenBSD: buffer.c,v 1.1 2004/05/31 13:46:16 henning Exp $ */ | |||||
/* | |||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||||
* | |||||
* Permission to use, copy, modify, and distribute this software for any | |||||
* purpose with or without fee is hereby granted, provided that the above | |||||
* copyright notice and this permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include <sys/types.h> | |||||
#include <sys/uio.h> | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <err.h> | |||||
#include <errno.h> | |||||
#include <limits.h> | |||||
#include <string.h> | |||||
#include <unistd.h> | |||||
#include "ntpd.h" | |||||
int buf_write(int, struct buf *); | |||||
void buf_enqueue(struct msgbuf *, struct buf *); | |||||
void buf_dequeue(struct msgbuf *, struct buf *); | |||||
struct buf * | |||||
buf_open(ssize_t len) | |||||
{ | |||||
struct buf *buf; | |||||
if ((buf = calloc(1, sizeof(struct buf))) == NULL) | |||||
return (NULL); | |||||
if ((buf->buf = malloc(len)) == NULL) { | |||||
free(buf); | |||||
return (NULL); | |||||
} | |||||
buf->size = len; | |||||
return (buf); | |||||
} | |||||
int | |||||
buf_add(struct buf *buf, void *data, ssize_t len) | |||||
{ | |||||
if (buf->wpos + len > buf->size) | |||||
return (-1); | |||||
memcpy(buf->buf + buf->wpos, data, len); | |||||
buf->wpos += len; | |||||
return (0); | |||||
} | |||||
int | |||||
buf_close(struct msgbuf *msgbuf, struct buf *buf) | |||||
{ | |||||
buf_enqueue(msgbuf, buf); | |||||
return (1); | |||||
} | |||||
int | |||||
buf_write(int sock, struct buf *buf) | |||||
{ | |||||
ssize_t n; | |||||
if ((n = write(sock, buf->buf + buf->rpos, | |||||
buf->size - buf->rpos)) == -1) { | |||||
if (errno == EAGAIN) /* cannot write immediately */ | |||||
return (0); | |||||
else | |||||
return (-1); | |||||
} | |||||
if (n == 0) { /* connection closed */ | |||||
errno = 0; | |||||
return (-2); | |||||
} | |||||
if (n < buf->size - buf->rpos) { /* not all data written yet */ | |||||
buf->rpos += n; | |||||
return (0); | |||||
} else | |||||
return (1); | |||||
} | |||||
void | |||||
buf_free(struct buf *buf) | |||||
{ | |||||
free(buf->buf); | |||||
free(buf); | |||||
} | |||||
void | |||||
msgbuf_init(struct msgbuf *msgbuf) | |||||
{ | |||||
msgbuf->queued = 0; | |||||
msgbuf->fd = -1; | |||||
TAILQ_INIT(&msgbuf->bufs); | |||||
} | |||||
void | |||||
msgbuf_clear(struct msgbuf *msgbuf) | |||||
{ | |||||
struct buf *buf; | |||||
while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) | |||||
buf_dequeue(msgbuf, buf); | |||||
} | |||||
int | |||||
msgbuf_write(struct msgbuf *msgbuf) | |||||
{ | |||||
/* | |||||
* possible race here | |||||
* when we cannot write out data completely from a buffer, | |||||
* we MUST return and NOT try to write out stuff from later buffers - | |||||
* the socket might have become writeable again | |||||
*/ | |||||
struct iovec iov[IOV_MAX]; | |||||
struct buf *buf, *next; | |||||
int i = 0; | |||||
ssize_t n; | |||||
bzero(&iov, sizeof(iov)); | |||||
TAILQ_FOREACH(buf, &msgbuf->bufs, entries) { | |||||
if (i >= IOV_MAX) | |||||
break; | |||||
iov[i].iov_base = buf->buf + buf->rpos; | |||||
iov[i].iov_len = buf->size - buf->rpos; | |||||
i++; | |||||
} | |||||
if ((n = writev(msgbuf->fd, iov, i)) == -1) { | |||||
if (errno == EAGAIN) /* cannot write immediately */ | |||||
return (0); | |||||
else | |||||
return (-1); | |||||
} | |||||
if (n == 0) { /* connection closed */ | |||||
errno = 0; | |||||
return (-2); | |||||
} | |||||
for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; | |||||
buf = next) { | |||||
next = TAILQ_NEXT(buf, entries); | |||||
if (n >= buf->size - buf->rpos) { | |||||
n -= buf->size - buf->rpos; | |||||
buf_dequeue(msgbuf, buf); | |||||
} else { | |||||
buf->rpos += n; | |||||
n = 0; | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
void | |||||
buf_enqueue(struct msgbuf *msgbuf, struct buf *buf) | |||||
{ | |||||
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entries); | |||||
msgbuf->queued++; | |||||
} | |||||
void | |||||
buf_dequeue(struct msgbuf *msgbuf, struct buf *buf) | |||||
{ | |||||
TAILQ_REMOVE(&msgbuf->bufs, buf, entries); | |||||
msgbuf->queued--; | |||||
buf_free(buf); | |||||
} |
@ -0,0 +1,215 @@ | |||||
/* $OpenBSD: imsg.c,v 1.1 2004/05/31 13:46:16 henning Exp $ */ | |||||
/* | |||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||||
* | |||||
* Permission to use, copy, modify, and distribute this software for any | |||||
* purpose with or without fee is hereby granted, provided that the above | |||||
* copyright notice and this permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include <sys/types.h> | |||||
#include <errno.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <unistd.h> | |||||
#include "ntpd.h" | |||||
int imsg_compose_core(struct imsgbuf *, int, u_int32_t, void *, | |||||
u_int16_t, pid_t); | |||||
struct buf *imsg_create_core(struct imsgbuf *, int, u_int32_t, u_int16_t, | |||||
pid_t); | |||||
void | |||||
imsg_init(struct imsgbuf *ibuf, int fd) | |||||
{ | |||||
msgbuf_init(&ibuf->w); | |||||
bzero(&ibuf->r, sizeof(ibuf->r)); | |||||
ibuf->fd = fd; | |||||
ibuf->w.fd = fd; | |||||
ibuf->pid = getpid(); | |||||
} | |||||
int | |||||
imsg_read(struct imsgbuf *ibuf) | |||||
{ | |||||
ssize_t n; | |||||
if ((n = read(ibuf->fd, ibuf->r.buf + ibuf->r.wpos, | |||||
sizeof(ibuf->r.buf) - ibuf->r.wpos)) == -1) { | |||||
if (errno != EINTR && errno != EAGAIN) { | |||||
log_warn("imsg_read: pipe read error"); | |||||
return (-1); | |||||
} | |||||
return (0); | |||||
} | |||||
ibuf->r.wpos += n; | |||||
return (n); | |||||
} | |||||
int | |||||
imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) | |||||
{ | |||||
ssize_t datalen = 0; | |||||
size_t av, left; | |||||
av = ibuf->r.wpos; | |||||
if (IMSG_HEADER_SIZE > av) | |||||
return (0); | |||||
memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); | |||||
if (imsg->hdr.len < IMSG_HEADER_SIZE || | |||||
imsg->hdr.len > MAX_IMSGSIZE) { | |||||
log_warnx("imsg_get: imsg hdr len out of bounds"); | |||||
return (-1); | |||||
} | |||||
if (imsg->hdr.len > av) | |||||
return (0); | |||||
datalen = imsg->hdr.len - IMSG_HEADER_SIZE; | |||||
ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; | |||||
if ((imsg->data = malloc(datalen)) == NULL) { | |||||
log_warn("imsg_get"); | |||||
return (-1); | |||||
} | |||||
memcpy(imsg->data, ibuf->r.rptr, datalen); | |||||
if (imsg->hdr.len < av) { | |||||
left = av - imsg->hdr.len; | |||||
memcpy(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); | |||||
ibuf->r.wpos = left; | |||||
} else | |||||
ibuf->r.wpos = 0; | |||||
return (datalen + IMSG_HEADER_SIZE); | |||||
} | |||||
int | |||||
imsg_compose(struct imsgbuf *ibuf, int type, u_int32_t peerid, void *data, | |||||
u_int16_t dlen) | |||||
{ | |||||
return (imsg_compose_core(ibuf, type, peerid, data, dlen, ibuf->pid)); | |||||
} | |||||
int | |||||
imsg_compose_pid(struct imsgbuf *ibuf, int type, pid_t pid, void *data, | |||||
u_int16_t datalen) | |||||
{ | |||||
return (imsg_compose_core(ibuf, type, 0, data, datalen, pid)); | |||||
} | |||||
int | |||||
imsg_compose_core(struct imsgbuf *ibuf, int type, u_int32_t peerid, void *data, | |||||
u_int16_t datalen, pid_t pid) | |||||
{ | |||||
struct buf *wbuf; | |||||
struct imsg_hdr hdr; | |||||
int n; | |||||
hdr.len = datalen + IMSG_HEADER_SIZE; | |||||
hdr.type = type; | |||||
hdr.peerid = peerid; | |||||
hdr.pid = pid; | |||||
wbuf = buf_open(hdr.len); | |||||
if (wbuf == NULL) { | |||||
log_warn("imsg_compose: buf_open"); | |||||
return (-1); | |||||
} | |||||
if (buf_add(wbuf, &hdr, sizeof(hdr)) == -1) { | |||||
log_warnx("imsg_compose: buf_add error"); | |||||
buf_free(wbuf); | |||||
return (-1); | |||||
} | |||||
if (datalen) | |||||
if (buf_add(wbuf, data, datalen) == -1) { | |||||
log_warnx("imsg_compose: buf_add error"); | |||||
buf_free(wbuf); | |||||
return (-1); | |||||
} | |||||
if ((n = buf_close(&ibuf->w, wbuf)) < 0) { | |||||
log_warnx("imsg_compose: buf_add error"); | |||||
buf_free(wbuf); | |||||
return (-1); | |||||
} | |||||
return (n); | |||||
} | |||||
struct buf * | |||||
imsg_create(struct imsgbuf *ibuf, int type, u_int32_t peerid, u_int16_t dlen) | |||||
{ | |||||
return (imsg_create_core(ibuf, type, peerid, dlen, ibuf->pid)); | |||||
} | |||||
struct buf * | |||||
imsg_create_pid(struct imsgbuf *ibuf, int type, pid_t pid, u_int16_t datalen) | |||||
{ | |||||
return (imsg_create_core(ibuf, type, 0, datalen, pid)); | |||||
} | |||||
struct buf * | |||||
imsg_create_core(struct imsgbuf *ibuf, int type, u_int32_t peerid, | |||||
u_int16_t datalen, pid_t pid) | |||||
{ | |||||
struct buf *wbuf; | |||||
struct imsg_hdr hdr; | |||||
hdr.len = datalen + IMSG_HEADER_SIZE; | |||||
hdr.type = type; | |||||
hdr.peerid = peerid; | |||||
hdr.pid = pid; | |||||
wbuf = buf_open(hdr.len); | |||||
if (wbuf == NULL) { | |||||
log_warn("imsg_create: buf_open"); | |||||
return (NULL); | |||||
} | |||||
if (buf_add(wbuf, &hdr, sizeof(hdr)) == -1) { | |||||
log_warnx("imsg_create: buf_add error"); | |||||
buf_free(wbuf); | |||||
return (NULL); | |||||
} | |||||
return (wbuf); | |||||
} | |||||
int | |||||
imsg_add(struct buf *msg, void *data, u_int16_t datalen) | |||||
{ | |||||
if (datalen) | |||||
if (buf_add(msg, data, datalen) == -1) { | |||||
log_warnx("imsg_add: buf_add error"); | |||||
buf_free(msg); | |||||
return (-1); | |||||
} | |||||
return (datalen); | |||||
} | |||||
int | |||||
imsg_close(struct imsgbuf *ibuf, struct buf *msg) | |||||
{ | |||||
int n; | |||||
if ((n = buf_close(&ibuf->w, msg)) < 0) { | |||||
log_warnx("imsg_close: buf_add error"); | |||||
buf_free(msg); | |||||
return (-1); | |||||
} | |||||
return (n); | |||||
} | |||||
void | |||||
imsg_free(struct imsg *imsg) | |||||
{ | |||||
free(imsg->data); | |||||
} |
@ -0,0 +1,154 @@ | |||||
/* $OpenBSD: log.c,v 1.1 2004/05/31 13:46:16 henning Exp $ */ | |||||
/* | |||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||||
* | |||||
* Permission to use, copy, modify, and distribute this software for any | |||||
* purpose with or without fee is hereby granted, provided that the above | |||||
* copyright notice and this permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include <sys/types.h> | |||||
#include <sys/socket.h> | |||||
#include <netinet/in.h> | |||||
#include <arpa/inet.h> | |||||
#include <err.h> | |||||
#include <errno.h> | |||||
#include <stdarg.h> | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <syslog.h> | |||||
#include <unistd.h> | |||||
#include "ntpd.h" | |||||
int debug; | |||||
void logit(int, const char *, ...); | |||||
void | |||||
log_init(int n_debug) | |||||
{ | |||||
extern char *__progname; | |||||
debug = n_debug; | |||||
if (!debug) | |||||
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); | |||||
} | |||||
void | |||||
logit(int pri, const char *fmt, ...) | |||||
{ | |||||
va_list ap; | |||||
va_start(ap, fmt); | |||||
vlog(pri, fmt, ap); | |||||
va_end(ap); | |||||
} | |||||
void | |||||
vlog(int pri, const char *fmt, va_list ap) | |||||
{ | |||||
char *nfmt; | |||||
if (debug) { | |||||
/* best effort in out of mem situations */ | |||||
if (asprintf(&nfmt, "%s\n", fmt) == -1) { | |||||
vfprintf(stderr, fmt, ap); | |||||
fprintf(stderr, "\n"); | |||||
} else { | |||||
vfprintf(stderr, nfmt, ap); | |||||
free(nfmt); | |||||
} | |||||
fflush(stderr); | |||||
} else | |||||
vsyslog(pri, fmt, ap); | |||||
} | |||||
void | |||||
log_warn(const char *emsg, ...) | |||||
{ | |||||
char *nfmt; | |||||
va_list ap; | |||||
/* best effort to even work in out of memory situations */ | |||||
if (emsg == NULL) | |||||
logit(LOG_CRIT, "%s", strerror(errno)); | |||||
else { | |||||
va_start(ap, emsg); | |||||
if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) { | |||||
/* we tried it... */ | |||||
vlog(LOG_CRIT, emsg, ap); | |||||
logit(LOG_CRIT, "%s", strerror(errno)); | |||||
} else { | |||||
vlog(LOG_CRIT, nfmt, ap); | |||||
free(nfmt); | |||||
} | |||||
va_end(ap); | |||||
} | |||||
} | |||||
void | |||||
log_warnx(const char *emsg, ...) | |||||
{ | |||||
va_list ap; | |||||
va_start(ap, emsg); | |||||
vlog(LOG_CRIT, emsg, ap); | |||||
va_end(ap); | |||||
} | |||||
void | |||||
log_info(const char *emsg, ...) | |||||
{ | |||||
va_list ap; | |||||
va_start(ap, emsg); | |||||
vlog(LOG_INFO, emsg, ap); | |||||
va_end(ap); | |||||
} | |||||
void | |||||
log_debug(const char *emsg, ...) | |||||
{ | |||||
va_list ap; | |||||
va_start(ap, emsg); | |||||
vlog(LOG_DEBUG, emsg, ap); | |||||
va_end(ap); | |||||
} | |||||
void | |||||
fatal(const char *emsg) | |||||
{ | |||||
if (emsg == NULL) | |||||
logit(LOG_CRIT, "fatal: %s", strerror(errno)); | |||||
else | |||||
if (errno) | |||||
logit(LOG_CRIT, "fatal: %s: %s", | |||||
emsg, strerror(errno)); | |||||
else | |||||
logit(LOG_CRIT, "fatal: %s", emsg); | |||||
exit(1); | |||||
} | |||||
void | |||||
fatalx(const char *emsg) | |||||
{ | |||||
errno = 0; | |||||
fatal(emsg); | |||||
} |
@ -0,0 +1,385 @@ | |||||
/* $OpenBSD: ntp.c,v 1.1 2004/05/31 13:46:16 henning Exp $ */ | |||||
/* | |||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||||
* Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org> | |||||
* | |||||
* Permission to use, copy, modify, and distribute this software for any | |||||
* purpose with or without fee is hereby granted, provided that the above | |||||
* copyright notice and this permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include <sys/param.h> | |||||
#include <errno.h> | |||||
#include <netdb.h> | |||||
#include <poll.h> | |||||
#include <pwd.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <unistd.h> | |||||
#include "ntpd.h" | |||||
#include "ntp.h" | |||||
#define PFD_LISTEN 0 | |||||
#define PFD_PIPE_MAIN 1 | |||||
#define PFD_MAX 2 | |||||
volatile sig_atomic_t ntp_quit = 0; | |||||
struct imsgbuf ibuf_main; | |||||
struct l_fixedpt ref_ts; | |||||
void ntp_sighdlr(int); | |||||
int setup_listener(struct servent *); | |||||
int ntp_dispatch_imsg(void); | |||||
int ntp_dispatch(int fd); | |||||
int parse_ntp_msg(char *, ssize_t, struct ntp_msg *); | |||||
int ntp_reply(int, struct sockaddr *, struct ntp_msg *, int); | |||||
int ntp_send(int, struct sockaddr *, struct ntp_msg *, ssize_t, int); | |||||
void get_ts(struct l_fixedpt *); | |||||
void | |||||
ntp_sighdlr(int sig) | |||||
{ | |||||
switch (sig) { | |||||
case SIGINT: | |||||
case SIGTERM: | |||||
ntp_quit = 1; | |||||
break; | |||||
} | |||||
} | |||||
pid_t | |||||
ntp_main(int pipe_prnt[2]) | |||||
{ | |||||
int nfds; | |||||
int sock = -1; | |||||
pid_t pid; | |||||
struct pollfd pfd[PFD_MAX]; | |||||
struct passwd *pw; | |||||
struct servent *se; | |||||
switch (pid = fork()) { | |||||
case -1: | |||||
fatal("cannot fork"); | |||||
case 0: | |||||
break; | |||||
default: | |||||
return (pid); | |||||
} | |||||
if ((se = getservbyname("ntp", "udp")) == NULL) | |||||
fatal("getservbyname"); | |||||
if ((pw = getpwnam(NTPD_USER)) == NULL) | |||||
fatal(NULL); | |||||
if (chroot(pw->pw_dir) == -1) | |||||
fatal("chroot"); | |||||
if (chdir("/") == -1) | |||||
fatal("chdir(\"/\")"); | |||||
setproctitle("ntp engine"); | |||||
sock = setup_listener(se); | |||||
if (setgroups(1, &pw->pw_gid) || | |||||
setegid(pw->pw_gid) || setgid(pw->pw_gid) || | |||||
seteuid(pw->pw_uid) || setuid(pw->pw_uid)) | |||||
fatal("can't drop privileges"); | |||||
endpwent(); | |||||
endservent(); | |||||
signal(SIGTERM, ntp_sighdlr); | |||||
signal(SIGINT, ntp_sighdlr); | |||||
signal(SIGPIPE, SIG_IGN); | |||||
close(pipe_prnt[0]); | |||||
imsg_init(&ibuf_main, pipe_prnt[1]); | |||||
log_info("ntp engine ready"); | |||||
while (ntp_quit == 0) { | |||||
get_ts(&ref_ts); /* XXX */ | |||||
bzero(&pfd, sizeof(pfd)); | |||||
pfd[PFD_LISTEN].fd = sock; | |||||
pfd[PFD_LISTEN].events = POLLIN; | |||||
pfd[PFD_PIPE_MAIN].fd = ibuf_main.fd; | |||||
pfd[PFD_PIPE_MAIN].events = POLLIN; | |||||
if (ibuf_main.w.queued > 0) | |||||
pfd[PFD_PIPE_MAIN].events |= POLLOUT; | |||||
if ((nfds = poll(pfd, 2, INFTIM)) == -1) | |||||
if (errno != EINTR) { | |||||
log_warn("poll error"); | |||||
ntp_quit = 1; | |||||
} | |||||
if (nfds > 0 && (pfd[PFD_PIPE_MAIN].revents & POLLOUT)) | |||||
if (msgbuf_write(&ibuf_main.w) < 0) { | |||||
log_warn("pipe write error (to parent)"); | |||||
ntp_quit = 1; | |||||
} | |||||
if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & POLLIN) { | |||||
nfds--; | |||||
if (ntp_dispatch_imsg() == -1) | |||||
ntp_quit = 1; | |||||
} | |||||
if (nfds > 0 && pfd[PFD_LISTEN].revents & POLLIN) { | |||||
nfds--; | |||||
if (ntp_dispatch(sock) == -1) | |||||
ntp_quit = 1; | |||||
} | |||||
} | |||||
msgbuf_write(&ibuf_main.w); | |||||
msgbuf_clear(&ibuf_main.w); | |||||
log_info("ntp engine exiting"); | |||||
_exit(0); | |||||
} | |||||
int | |||||
setup_listener(struct servent *se) | |||||
{ | |||||
struct sockaddr_in sa_in; | |||||
int fd; | |||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) | |||||
fatal("socket"); | |||||
bzero(&sa_in, sizeof(sa_in)); | |||||
sa_in.sin_family = AF_INET; | |||||
sa_in.sin_addr.s_addr = htonl(INADDR_ANY); | |||||
sa_in.sin_port = se->s_port; | |||||
if (bind(fd, (struct sockaddr *)&sa_in, sizeof(sa_in)) == -1) | |||||
fatal("bind"); | |||||
return (fd); | |||||
} | |||||
int | |||||
ntp_dispatch_imsg(void) | |||||
{ | |||||
struct imsg imsg; | |||||
int n; | |||||
if ((n = imsg_read(&ibuf_main)) == -1) | |||||
return (-1); | |||||
if (n == 0) { /* connection closed */ | |||||
log_warnx("ntp_dispatch_imsg in ntp engine: pipe closed"); | |||||
return (-1); | |||||
} | |||||
for (;;) { | |||||
if ((n = imsg_get(&ibuf_main, &imsg)) == -1) | |||||
return (-1); | |||||
if (n == 0) | |||||
break; | |||||
switch (imsg.hdr.type) { | |||||
default: | |||||
break; | |||||
} | |||||
imsg_free(&imsg); | |||||
} | |||||
return (0); | |||||
} | |||||
int | |||||
ntp_dispatch(int fd) | |||||
{ | |||||
struct sockaddr fsa; | |||||
socklen_t fsa_len; | |||||
char buf[NTP_MSGSIZE]; | |||||
ssize_t size; | |||||
struct ntp_msg msg; | |||||
fsa_len = sizeof(fsa); | |||||
if ((size = recvfrom(fd, &buf, sizeof(buf), 0, &fsa, &fsa_len)) == -1) | |||||
fatal("recvfrom"); | |||||
parse_ntp_msg(buf, size, &msg); | |||||
ntp_reply(fd, &fsa, &msg, 0); | |||||
return (0); | |||||
} | |||||
int | |||||
parse_ntp_msg(char *p, ssize_t len, struct ntp_msg *msg) | |||||
{ | |||||
int auth, i; | |||||
if (len == NTP_MSGSIZE) | |||||
auth = 1; | |||||
else if (len == NTP_MSGSIZE_NOAUTH) | |||||
auth = 0; | |||||
else { | |||||
log_warnx("malformed packet received"); | |||||
return (-1); | |||||
} | |||||
memcpy(&msg->status, p, sizeof(msg->status)); | |||||
p += sizeof(msg->status); | |||||
memcpy(&msg->stratum, p, sizeof(msg->stratum)); | |||||
p += sizeof(msg->stratum); | |||||
memcpy(&msg->ppoll, p, sizeof(msg->ppoll)); | |||||
p += sizeof(msg->ppoll); | |||||
memcpy(&msg->precision, p, sizeof(msg->precision)); | |||||
p += sizeof(msg->precision); | |||||
memcpy(&msg->distance.int_part, p, sizeof(msg->distance.int_part)); | |||||
p += sizeof(msg->distance.int_part); | |||||
memcpy(&msg->distance.fraction, p, sizeof(msg->distance.fraction)); | |||||
p += sizeof(msg->distance.fraction); | |||||
memcpy(&msg->dispersion.int_part, p, sizeof(msg->dispersion.int_part)); | |||||
p += sizeof(msg->dispersion.int_part); | |||||
memcpy(&msg->dispersion.fraction, p, sizeof(msg->dispersion.fraction)); | |||||
p += sizeof(msg->dispersion.fraction); | |||||
memcpy(&msg->refid, p, sizeof(msg->refid)); | |||||
p += sizeof(msg->refid); | |||||
memcpy(&msg->reftime.int_part, p, sizeof(msg->reftime.int_part)); | |||||
p += sizeof(msg->reftime.int_part); | |||||
memcpy(&msg->reftime.fraction, p, sizeof(msg->reftime.fraction)); | |||||
p += sizeof(msg->reftime.fraction); | |||||
memcpy(&msg->orgtime.int_part, p, sizeof(msg->orgtime.int_part)); | |||||
p += sizeof(msg->orgtime.int_part); | |||||
memcpy(&msg->orgtime.fraction, p, sizeof(msg->orgtime.fraction)); | |||||
p += sizeof(msg->orgtime.fraction); | |||||
memcpy(&msg->rectime.int_part, p, sizeof(msg->rectime.int_part)); | |||||
p += sizeof(msg->rectime.int_part); | |||||
memcpy(&msg->rectime.fraction, p, sizeof(msg->rectime.fraction)); | |||||
p += sizeof(msg->rectime.fraction); | |||||
memcpy(&msg->xmttime.int_part, p, sizeof(msg->xmttime.int_part)); | |||||
p += sizeof(msg->xmttime.int_part); | |||||
memcpy(&msg->xmttime.fraction, p, sizeof(msg->xmttime.fraction)); | |||||
p += sizeof(msg->xmttime.fraction); | |||||
if (auth) { | |||||
memcpy(&msg->keyid, p, sizeof(msg->keyid)); | |||||
p += sizeof(msg->refid); | |||||
for (i = 0; i < NTP_DIGESTSIZE; i++) { | |||||
memcpy(&msg->digest[i], p, sizeof(msg->digest[i])); | |||||
p += sizeof(msg->digest[i]); | |||||
} | |||||
/* XXX check auth */ | |||||
} | |||||
return (0); | |||||
} | |||||
int | |||||
ntp_reply(int fd, struct sockaddr *sa, struct ntp_msg *query, int auth) | |||||
{ | |||||
ssize_t len; | |||||
struct l_fixedpt t; | |||||
struct ntp_msg reply; | |||||
if (auth) | |||||
len = NTP_MSGSIZE; | |||||
else | |||||
len = NTP_MSGSIZE_NOAUTH; | |||||
bzero(&reply, sizeof(reply)); | |||||
reply.status = 0 | (query->status & VERSIONMASK); | |||||
if ((query->status & MODEMASK) == MODE_CLIENT) | |||||
reply.status |= MODE_SERVER; | |||||
else | |||||
reply.status |= MODE_SYM_PAS; | |||||
reply.stratum = 2; | |||||
reply.ppoll = query->ppoll; | |||||
reply.precision = 0; /* XXX */ | |||||
reply.refid = htonl(t.fraction); /* XXX */ | |||||
reply.reftime.int_part = htonl(ref_ts.int_part); | |||||
reply.reftime.fraction = htonl(ref_ts.fraction); | |||||
get_ts(&t); | |||||
reply.rectime.int_part = htonl(t.int_part); | |||||
reply.rectime.fraction = htonl(t.fraction); | |||||
reply.xmttime.int_part = htonl(t.int_part); | |||||
reply.xmttime.fraction = htonl(t.fraction); | |||||
reply.orgtime.int_part = query->xmttime.int_part; | |||||
reply.orgtime.fraction = query->xmttime.fraction; | |||||
return (ntp_send(fd, sa, &reply, len, auth)); | |||||
} | |||||
int | |||||
ntp_send(int fd, struct sockaddr *sa, struct ntp_msg *reply, ssize_t len, | |||||
int auth) | |||||
{ | |||||
char buf[NTP_MSGSIZE]; | |||||
char *p; | |||||
p = buf; | |||||
memcpy(p, &reply->status, sizeof(reply->status)); | |||||
p += sizeof(reply->status); | |||||
memcpy(p, &reply->stratum, sizeof(reply->stratum)); | |||||
p += sizeof(reply->stratum); | |||||
memcpy(p, &reply->ppoll, sizeof(reply->ppoll)); | |||||
p += sizeof(reply->ppoll); | |||||
memcpy(p, &reply->precision, sizeof(reply->precision)); | |||||
p += sizeof(reply->precision); | |||||
memcpy(p, &reply->distance.int_part, sizeof(reply->distance.int_part)); | |||||
p += sizeof(reply->distance.int_part); | |||||
memcpy(p, &reply->distance.fraction, sizeof(reply->distance.fraction)); | |||||
p += sizeof(reply->distance.fraction); | |||||
memcpy(p, &reply->dispersion.int_part, | |||||
sizeof(reply->dispersion.int_part)); | |||||
p += sizeof(reply->dispersion.int_part); | |||||
memcpy(p, &reply->dispersion.fraction, | |||||
sizeof(reply->dispersion.fraction)); | |||||
p += sizeof(reply->dispersion.fraction); | |||||
memcpy(p, &reply->refid, sizeof(reply->refid)); | |||||
p += sizeof(reply->refid); | |||||
memcpy(p, &reply->reftime.int_part, sizeof(reply->reftime.int_part)); | |||||
p += sizeof(reply->reftime.int_part); | |||||
memcpy(p, &reply->reftime.fraction, sizeof(reply->reftime.fraction)); | |||||
p += sizeof(reply->reftime.fraction); | |||||
memcpy(p, &reply->orgtime.int_part, sizeof(reply->orgtime.int_part)); | |||||
p += sizeof(reply->orgtime.int_part); | |||||
memcpy(p, &reply->orgtime.fraction, sizeof(reply->orgtime.fraction)); | |||||
p += sizeof(reply->orgtime.fraction); | |||||
memcpy(p, &reply->rectime.int_part, sizeof(reply->rectime.int_part)); | |||||
p += sizeof(reply->rectime.int_part); | |||||
memcpy(p, &reply->rectime.fraction, sizeof(reply->rectime.fraction)); | |||||
p += sizeof(reply->rectime.fraction); | |||||
memcpy(p, &reply->xmttime.int_part, sizeof(reply->xmttime.int_part)); | |||||
p += sizeof(reply->xmttime.int_part); | |||||
memcpy(p, &reply->xmttime.fraction, sizeof(reply->xmttime.fraction)); | |||||
p += sizeof(reply->xmttime.fraction); | |||||
if (auth) { | |||||
/* XXX */ | |||||
} | |||||
if (sendto(fd, &buf, len, 0, sa, sa->sa_len) != len) | |||||
fatal("sendto"); | |||||
return (0); | |||||
} | |||||
void | |||||
get_ts(struct l_fixedpt *t) | |||||
{ | |||||
struct timeval tv; | |||||
gettimeofday(&tv, NULL); | |||||
t->int_part = tv.tv_sec + JAN_1970; | |||||
t->fraction = ((float)tv.tv_usec)/1000000 * UINT_MAX; | |||||
} |
@ -0,0 +1,134 @@ | |||||
/* | |||||
* Copyright (c) 2004 Henning Brauer <henning@openbsd.org> | |||||
* Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org> | |||||
* | |||||
* Permission to use, copy, modify, and distribute this software for any | |||||
* purpose with or without fee is hereby granted, provided that the above | |||||
* copyright notice and this permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/* Style borrowed from NTP ref/tcpdump and updated for SNTPv4 (RFC2030). */ | |||||
/* | |||||
* RFC Section 3 | |||||
* | |||||
* 0 1 2 3 | |||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | Integer Part | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | Fraction Part | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | |||||
* 0 1 2 3 | |||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | Integer Part | Fraction Part | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
*/ | |||||
struct l_fixedpt { | |||||
u_int32_t int_part; | |||||
u_int32_t fraction; | |||||
}; | |||||
struct s_fixedpt { | |||||
u_int16_t int_part; | |||||
u_int16_t fraction; | |||||
}; | |||||
/* RFC Section 4 | |||||
* | |||||
* 0 1 2 3 | |||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* |LI | VN | Mode| Stratum | Poll | Precision | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | Synchronizing Distance | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | Synchronizing Dispersion | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | Reference Clock Identifier | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | | | |||||
* | Reference Timestamp (64 bits) | | |||||
* | | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | | | |||||
* | Originate Timestamp (64 bits) | | |||||
* | | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | | | |||||
* | Receive Timestamp (64 bits) | | |||||
* | | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | | | |||||
* | Transmit Timestamp (64 bits) | | |||||
* | | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | Key Identifier (optional) (32) | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | | | |||||
* | | | |||||
* | Message Digest (optional) (128) | | |||||
* | | | |||||
* | | | |||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |||||
* | |||||
*/ | |||||
#define NTP_DIGESTSIZE 16 | |||||
#define NTP_MSGSIZE_NOAUTH 48 | |||||
#define NTP_MSGSIZE (NTP_MSGSIZE_NOAUTH + 4 + NTP_DIGESTSIZE) | |||||
struct ntp_msg { | |||||
u_int8_t status; /* status of local clock and leap info */ | |||||
u_int8_t stratum; /* Stratum level */ | |||||
u_int8_t ppoll; /* poll value */ | |||||
int8_t precision; | |||||
struct s_fixedpt distance; | |||||
struct s_fixedpt dispersion; | |||||
u_int32_t refid; | |||||
struct l_fixedpt reftime; | |||||
struct l_fixedpt orgtime; | |||||
struct l_fixedpt rectime; | |||||
struct l_fixedpt xmttime; | |||||
u_int32_t keyid; | |||||
u_int8_t digest[NTP_DIGESTSIZE]; | |||||
}; | |||||
/* | |||||
* Leap Second Codes (high order two bits) | |||||
*/ | |||||
#define LI_NOWARNING (0 << 6) /* no warning */ | |||||
#define LI_PLUSSEC (1 << 6) /* add a second (61 seconds) */ | |||||
#define LI_MINUSSEC (2 << 6) /* minus a second (59 seconds) */ | |||||
#define LI_ALARM (3 << 6) /* alarm condition */ | |||||
/* | |||||
* Status Masks | |||||
*/ | |||||
#define MODEMASK (7 << 0) | |||||
#define VERSIONMASK (7 << 3) | |||||
#define LIMASK (2 << 6) | |||||
/* | |||||
* Mode values | |||||
*/ | |||||
#define MODE_RES0 0 /* reserved */ | |||||
#define MODE_SYM_ACT 1 /* symmetric active */ | |||||
#define MODE_SYM_PAS 2 /* symmetric passive */ | |||||
#define MODE_CLIENT 3 /* client */ | |||||
#define MODE_SERVER 4 /* server */ | |||||
#define MODE_BROADCAST 5 /* broadcast */ | |||||
#define MODE_RES1 6 /* reserved for NTP control message */ | |||||
#define MODE_RES2 7 /* reserved for private use */ | |||||
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ |
@ -0,0 +1,245 @@ | |||||
/* $OpenBSD: ntpd.c,v 1.1 2004/05/31 13:46:16 henning Exp $ */ | |||||
/* | |||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||||
* | |||||
* Permission to use, copy, modify, and distribute this software for any | |||||
* purpose with or without fee is hereby granted, provided that the above | |||||
* copyright notice and this permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include <sys/types.h> | |||||
#include <sys/socket.h> | |||||
#include <sys/wait.h> | |||||
#include <netinet/in.h> | |||||
#include <arpa/inet.h> | |||||
#include <err.h> | |||||
#include <errno.h> | |||||
#include <fcntl.h> | |||||
#include <poll.h> | |||||
#include <pwd.h> | |||||
#include <signal.h> | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <unistd.h> | |||||
#include "ntpd.h" | |||||
void sighdlr(int); | |||||
void usage(void); | |||||
int main(int, char *[]); | |||||
int check_child(pid_t, const char *); | |||||
int reconfigure(char *); | |||||
int dispatch_imsg(void); | |||||
int rfd = -1; | |||||
volatile sig_atomic_t quit = 0; | |||||
volatile sig_atomic_t reconfig = 0; | |||||
volatile sig_atomic_t sigchld = 0; | |||||
struct imsgbuf ibuf; | |||||
void | |||||
sighdlr(int sig) | |||||
{ | |||||
switch (sig) { | |||||
case SIGTERM: | |||||
case SIGINT: | |||||
quit = 1; | |||||
break; | |||||
case SIGCHLD: | |||||
sigchld = 1; | |||||
break; | |||||
case SIGHUP: | |||||
reconfig = 1; | |||||
break; | |||||
} | |||||
} | |||||
void | |||||
usage(void) | |||||
{ | |||||
extern char *__progname; | |||||
fprintf(stderr, "usage: %s [-d] [-f file]", __progname); | |||||
exit(1); | |||||
} | |||||
#define POLL_MAX 8 | |||||
#define PFD_PIPE 0 | |||||
int | |||||
main(int argc, char *argv[]) | |||||
{ | |||||
struct pollfd pfd[POLL_MAX]; | |||||
pid_t chld_pid = 0, pid; | |||||
char *conffile; | |||||
int debug = 0; | |||||
int ch, nfds; | |||||
int pipe_chld[2]; | |||||
conffile = CONFFILE; | |||||
log_init(1); /* log to stderr until daemonized */ | |||||
while ((ch = getopt(argc, argv, "df:")) != -1) { | |||||
switch (ch) { | |||||
case 'd': | |||||
debug = 1; | |||||
break; | |||||
case 'f': | |||||
conffile = optarg; | |||||
break; | |||||
default: | |||||
usage(); | |||||
/* NOTREACHED */ | |||||
} | |||||
} | |||||
if (geteuid()) | |||||
errx(1, "need root privileges"); | |||||
if (getpwnam(NTPD_USER) == NULL) | |||||
errx(1, "unknown user %s", NTPD_USER); | |||||
endpwent(); | |||||
log_init(debug); | |||||
if (!debug) | |||||
daemon(1, 0); | |||||
log_info("startup"); | |||||
if (pipe(pipe_chld) == -1) | |||||
fatal("pipe"); | |||||
/* fork children */ | |||||
chld_pid = ntp_main(pipe_chld); | |||||
setproctitle("[priv]"); | |||||
signal(SIGTERM, sighdlr); | |||||
signal(SIGINT, sighdlr); | |||||
signal(SIGCHLD, sighdlr); | |||||
signal(SIGHUP, sighdlr); | |||||
close(pipe_chld[1]); | |||||
imsg_init(&ibuf, pipe_chld[0]); | |||||
while (quit == 0) { | |||||
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, INFTIM)) == -1) | |||||
if (errno != EINTR) { | |||||
log_warn("poll error"); | |||||
quit = 1; | |||||
} | |||||
if (nfds > 0 && (pfd[PFD_PIPE].revents & POLLOUT)) | |||||
if (msgbuf_write(&ibuf.w) < 0) { | |||||
log_warn("pipe write error (to child"); | |||||
quit = 1; | |||||
} | |||||
if (nfds > 0 && pfd[PFD_PIPE].revents & POLLIN) { | |||||
nfds--; | |||||
if (dispatch_imsg() == -1) | |||||
quit = 1; | |||||
} | |||||
if (reconfig) { | |||||
log_info("rereading config"); | |||||
reconfigure(conffile); | |||||
reconfig = 0; | |||||
} | |||||
if (sigchld) { | |||||
if (check_child(chld_pid, "child")) | |||||
quit = 1; | |||||
sigchld = 0; | |||||
} | |||||
} | |||||
signal(SIGCHLD, SIG_IGN); | |||||
if (chld_pid) | |||||
kill(chld_pid, SIGTERM); | |||||
do { | |||||
if ((pid = wait(NULL)) == -1 && | |||||
errno != EINTR && errno != ECHILD) | |||||
fatal("wait"); | |||||
} while (pid != -1 || (pid == -1 && errno == EINTR)); | |||||
log_info("Terminating"); | |||||
return (0); | |||||
} | |||||
int | |||||
check_child(pid_t pid, const char *pname) | |||||
{ | |||||
int status; | |||||
if (waitpid(pid, &status, WNOHANG) > 0) { | |||||
if (WIFEXITED(status)) { | |||||
log_warnx("Lost child: %s exited", pname); | |||||
return (1); | |||||
} | |||||
if (WIFSIGNALED(status)) { | |||||
log_warnx("Lost child: %s terminated; signal %d", | |||||
pname, WTERMSIG(status)); | |||||
return (1); | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
int | |||||
reconfigure(char *conffile) | |||||
{ | |||||
return (-1); | |||||
} | |||||
int | |||||
dispatch_imsg(void) | |||||
{ | |||||
struct imsg imsg; | |||||
int n; | |||||
if ((n = imsg_read(&ibuf)) == -1) | |||||
return (-1); | |||||
if (n == 0) { /* connection closed */ | |||||
log_warnx("dispatch_imsg in main: pipe closed"); | |||||
return (-1); | |||||
} | |||||
for (;;) { | |||||
if ((n = imsg_get(&ibuf, &imsg)) == -1) | |||||
return (-1); | |||||
if (n == 0) | |||||
break; | |||||
switch (imsg.hdr.type) { | |||||
default: | |||||
break; | |||||
} | |||||
imsg_free(&imsg); | |||||
} | |||||
return (0); | |||||
} |
@ -0,0 +1,112 @@ | |||||
/* $OpenBSD: ntpd.h,v 1.1 2004/05/31 13:46:16 henning Exp $ */ | |||||
/* | |||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||||
* | |||||
* Permission to use, copy, modify, and distribute this software for any | |||||
* purpose with or without fee is hereby granted, provided that the above | |||||
* copyright notice and this permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include <sys/types.h> | |||||
#include <sys/socket.h> | |||||
#include <sys/queue.h> | |||||
#include <netinet/in.h> | |||||
#include <arpa/inet.h> | |||||
#include <stdarg.h> | |||||
#define NTPD_USER "_ntp" | |||||
#define CONFFILE "/etc/ntpd.conf" | |||||
#define READ_BUF_SIZE 65535 | |||||
struct buf { | |||||
TAILQ_ENTRY(buf) entries; | |||||
u_char *buf; | |||||
ssize_t size; | |||||
ssize_t wpos; | |||||
ssize_t rpos; | |||||
}; | |||||
struct msgbuf { | |||||
u_int32_t queued; | |||||
int fd; | |||||
TAILQ_HEAD(bufs, buf) bufs; | |||||
}; | |||||
struct buf_read { | |||||
u_char buf[READ_BUF_SIZE]; | |||||
u_char *rptr; | |||||
ssize_t wpos; | |||||
}; | |||||
/* ipc messages */ | |||||
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) | |||||
#define MAX_IMSGSIZE 8192 | |||||
struct imsgbuf { | |||||
int fd; | |||||
pid_t pid; | |||||
struct buf_read r; | |||||
struct msgbuf w; | |||||
}; | |||||
enum imsg_type { | |||||
IMSG_NONE | |||||
}; | |||||
struct imsg_hdr { | |||||
enum imsg_type type; | |||||
u_int16_t len; | |||||
u_int32_t peerid; | |||||
pid_t pid; | |||||
}; | |||||
struct imsg { | |||||
struct imsg_hdr hdr; | |||||
void *data; | |||||
}; | |||||
/* prototypes */ | |||||
/* log.c */ | |||||
void log_init(int); | |||||
void vlog(int, const char *, va_list); | |||||
void log_warn(const char *, ...); | |||||
void log_warnx(const char *, ...); | |||||
void log_info(const char *, ...); | |||||
void log_debug(const char *, ...); | |||||
void fatal(const char *); | |||||
void fatalx(const char *); | |||||
/* buffer.c */ | |||||
struct buf *buf_open(ssize_t); | |||||
int buf_add(struct buf *, void *, ssize_t); | |||||
int buf_close(struct msgbuf *, struct buf *); | |||||
void buf_free(struct buf *); | |||||
void msgbuf_init(struct msgbuf *); | |||||
void msgbuf_clear(struct msgbuf *); | |||||
int msgbuf_write(struct msgbuf *); | |||||
/* imsg.c */ | |||||
void imsg_init(struct imsgbuf *, int); | |||||
int imsg_read(struct imsgbuf *); | |||||
int imsg_get(struct imsgbuf *, struct imsg *); | |||||
int imsg_compose(struct imsgbuf *, int, u_int32_t, void *, u_int16_t); | |||||
int imsg_compose_pid(struct imsgbuf *, int, pid_t, void *, u_int16_t); | |||||
struct buf *imsg_create(struct imsgbuf *, int, u_int32_t, u_int16_t); | |||||
struct buf *imsg_create_pid(struct imsgbuf *, int, pid_t, u_int16_t); | |||||
int imsg_add(struct buf *, void *, u_int16_t); | |||||
int imsg_close(struct imsgbuf *, struct buf *); | |||||
void imsg_free(struct imsg *); | |||||
/* ntp.c */ | |||||
pid_t ntp_main(int[2]); |