Browse Source

initial cut at ntpd.

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 Guy
OPENBSD_3_6
henning 20 years ago
parent
commit
4ad0cde98b
8 changed files with 1442 additions and 0 deletions
  1. +15
    -0
      src/usr.sbin/ntpd/Makefile
  2. +182
    -0
      src/usr.sbin/ntpd/buffer.c
  3. +215
    -0
      src/usr.sbin/ntpd/imsg.c
  4. +154
    -0
      src/usr.sbin/ntpd/log.c
  5. +385
    -0
      src/usr.sbin/ntpd/ntp.c
  6. +134
    -0
      src/usr.sbin/ntpd/ntp.h
  7. +245
    -0
      src/usr.sbin/ntpd/ntpd.c
  8. +112
    -0
      src/usr.sbin/ntpd/ntpd.h

+ 15
- 0
src/usr.sbin/ntpd/Makefile View File

@ -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>

+ 182
- 0
src/usr.sbin/ntpd/buffer.c View File

@ -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);
}

+ 215
- 0
src/usr.sbin/ntpd/imsg.c View File

@ -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);
}

+ 154
- 0
src/usr.sbin/ntpd/log.c View File

@ -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);
}

+ 385
- 0
src/usr.sbin/ntpd/ntp.c View File

@ -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;
}

+ 134
- 0
src/usr.sbin/ntpd/ntp.h View File

@ -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 */

+ 245
- 0
src/usr.sbin/ntpd/ntpd.c View File

@ -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);
}

+ 112
- 0
src/usr.sbin/ntpd/ntpd.h View File

@ -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]);

Loading…
Cancel
Save