Source code pulled from OpenBSD for OpenNTPD. The place to contribute to this code is via the OpenBSD CVS tree.
 
 
 
 
 
 

402 lines
11 KiB

/* $OpenBSD: ntp.c,v 1.4 2004/06/01 16:27:09 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_PIPE_MAIN 0
volatile sig_atomic_t ntp_quit = 0;
struct imsgbuf ibuf_main;
struct l_fixedpt ref_ts;
void ntp_sighdlr(int);
int setup_listeners(struct servent *, struct ntpd_conf *);
int ntp_dispatch_imsg(void);
int ntp_dispatch(int fd);
int ntp_getmsg(char *, ssize_t, struct ntp_msg *);
int ntp_reply(int, struct sockaddr *, struct ntp_msg *, int);
int ntp_sendmsg(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], struct ntpd_conf *conf)
{
int nfds, i, j;
pid_t pid;
struct pollfd pfd[OPEN_MAX];
struct passwd *pw;
struct servent *se;
struct listen_addr *la;
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");
setup_listeners(se, conf);
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_PIPE_MAIN].fd = ibuf_main.fd;
pfd[PFD_PIPE_MAIN].events = POLLIN;
if (ibuf_main.w.queued > 0)
pfd[PFD_PIPE_MAIN].events |= POLLOUT;
i = 1;
TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
pfd[i].fd = la->fd;
pfd[i].events = POLLIN;
i++;
}
if ((nfds = poll(pfd, i, 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;
}
for (j = 1; nfds > 0 && j < i; j++)
if (pfd[j].revents & POLLIN) {
nfds--;
if (ntp_dispatch(pfd[j].fd) == -1)
ntp_quit = 1;
}
}
msgbuf_write(&ibuf_main.w);
msgbuf_clear(&ibuf_main.w);
log_info("ntp engine exiting");
_exit(0);
}
int
setup_listeners(struct servent *se, struct ntpd_conf *conf)
{
struct listen_addr *la;
if (TAILQ_EMPTY(&conf->listen_addrs)) {
if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
fatal("setup_listeners calloc");
la->sa.ss_len = sizeof(struct sockaddr_in);
((struct sockaddr_in *)&la->sa)->sin_family = AF_INET;
((struct sockaddr_in *)&la->sa)->sin_addr.s_addr =
htonl(INADDR_ANY);
((struct sockaddr_in *)&la->sa)->sin_port = se->s_port;
TAILQ_INSERT_TAIL(&conf->listen_addrs, la, entry);
if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
fatal("setup_listeners calloc");
la->sa.ss_len = sizeof(struct sockaddr_in6);
((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6;
((struct sockaddr_in6 *)&la->sa)->sin6_port = se->s_port;
TAILQ_INSERT_TAIL(&conf->listen_addrs, la, entry);
}
TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1)
fatal("socket");
if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa.ss_len) ==
-1)
fatal("bind");
}
return (0);
}
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_storage 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,
(struct sockaddr *)&fsa, &fsa_len)) == -1)
fatal("recvfrom");
ntp_getmsg(buf, size, &msg);
ntp_reply(fd, (struct sockaddr *)&fsa, &msg, 0);
return (0);
}
int
ntp_getmsg(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_sendmsg(fd, sa, &reply, len, auth));
}
int
ntp_sendmsg(int fd, struct sockaddr *sa, struct ntp_msg *msg, ssize_t len,
int auth)
{
char buf[NTP_MSGSIZE];
char *p;
p = buf;
memcpy(p, &msg->status, sizeof(msg->status));
p += sizeof(msg->status);
memcpy(p, &msg->stratum, sizeof(msg->stratum));
p += sizeof(msg->stratum);
memcpy(p, &msg->ppoll, sizeof(msg->ppoll));
p += sizeof(msg->ppoll);
memcpy(p, &msg->precision, sizeof(msg->precision));
p += sizeof(msg->precision);
memcpy(p, &msg->distance.int_part, sizeof(msg->distance.int_part));
p += sizeof(msg->distance.int_part);
memcpy(p, &msg->distance.fraction, sizeof(msg->distance.fraction));
p += sizeof(msg->distance.fraction);
memcpy(p, &msg->dispersion.int_part, sizeof(msg->dispersion.int_part));
p += sizeof(msg->dispersion.int_part);
memcpy(p, &msg->dispersion.fraction, sizeof(msg->dispersion.fraction));
p += sizeof(msg->dispersion.fraction);
memcpy(p, &msg->refid, sizeof(msg->refid));
p += sizeof(msg->refid);
memcpy(p, &msg->reftime.int_part, sizeof(msg->reftime.int_part));
p += sizeof(msg->reftime.int_part);
memcpy(p, &msg->reftime.fraction, sizeof(msg->reftime.fraction));
p += sizeof(msg->reftime.fraction);
memcpy(p, &msg->orgtime.int_part, sizeof(msg->orgtime.int_part));
p += sizeof(msg->orgtime.int_part);
memcpy(p, &msg->orgtime.fraction, sizeof(msg->orgtime.fraction));
p += sizeof(msg->orgtime.fraction);
memcpy(p, &msg->rectime.int_part, sizeof(msg->rectime.int_part));
p += sizeof(msg->rectime.int_part);
memcpy(p, &msg->rectime.fraction, sizeof(msg->rectime.fraction));
p += sizeof(msg->rectime.fraction);
memcpy(p, &msg->xmttime.int_part, sizeof(msg->xmttime.int_part));
p += sizeof(msg->xmttime.int_part);
memcpy(p, &msg->xmttime.fraction, sizeof(msg->xmttime.fraction));
p += sizeof(msg->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;
}