about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChristian Neukirchen <chneukirchen@gmail.com>2015-01-09 17:50:39 +0100
committerChristian Neukirchen <chneukirchen@gmail.com>2015-01-09 17:50:39 +0100
commiteeed21e84c1702e4b6c6c8ccbef5b245dd9daa25 (patch)
tree0b8348d97b1f6bb625214480054059def8d98afc
parent0d9ab362ff16978b87a0ff8a2a67e0e7ccb86d64 (diff)
downloadoutils-eeed21e84c1702e4b6c6c8ccbef5b245dd9daa25.tar.gz
outils-eeed21e84c1702e4b6c6c8ccbef5b245dd9daa25.tar.xz
outils-eeed21e84c1702e4b6c6c8ccbef5b245dd9daa25.zip
add rdate (which speaks SNTP really)
-rw-r--r--src/usr.sbin/rdate/Makefile11
-rw-r--r--src/usr.sbin/rdate/ntp.c488
-rw-r--r--src/usr.sbin/rdate/ntpleaps.c196
-rw-r--r--src/usr.sbin/rdate/ntpleaps.h73
-rw-r--r--src/usr.sbin/rdate/rdate.8110
-rw-r--r--src/usr.sbin/rdate/rdate.c173
-rw-r--r--src/usr.sbin/rdate/rfc868time.c122
7 files changed, 1173 insertions, 0 deletions
diff --git a/src/usr.sbin/rdate/Makefile b/src/usr.sbin/rdate/Makefile
new file mode 100644
index 0000000..44361d1
--- /dev/null
+++ b/src/usr.sbin/rdate/Makefile
@@ -0,0 +1,11 @@
+#	$OpenBSD: Makefile,v 1.7 2003/11/20 23:23:09 avsm Exp $
+
+PROG=	rdate
+SRCS=	rdate.c rfc868time.c ntp.c ntpleaps.c
+CFLAGS+=-Wall
+DPADD+= ${LIBUTIL}
+LDADD+= -lutil
+
+MAN=	rdate.8
+
+.include <bsd.prog.mk>
diff --git a/src/usr.sbin/rdate/ntp.c b/src/usr.sbin/rdate/ntp.c
new file mode 100644
index 0000000..e06f236
--- /dev/null
+++ b/src/usr.sbin/rdate/ntp.c
@@ -0,0 +1,488 @@
+/*	$OpenBSD: ntp.c,v 1.32 2014/10/29 04:00:44 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 1996, 1997 by N.M. Maclaren. All rights reserved.
+ * Copyright (c) 1996, 1997 by University of Cambridge. All rights reserved.
+ * Copyright (c) 2002 by Thorsten "mirabile" Glaser.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the university may be used to
+ *    endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "ntpleaps.h"
+
+/*
+ * NTP definitions.  Note that these assume 8-bit bytes - sigh.  There
+ * is little point in parameterising everything, as it is neither
+ * feasible nor useful.  It would be very useful if more fields could
+ * be defined as unspecified.  The NTP packet-handling routines
+ * contain a lot of extra assumptions.
+ */
+
+#define JAN_1970   2208988800.0		/* 1970 - 1900 in seconds */
+#define NTP_SCALE  4294967296.0		/* 2^32, of course! */
+
+#define NTP_MODE_CLIENT       3		/* NTP client mode */
+#define NTP_MODE_SERVER       4		/* NTP server mode */
+#define NTP_VERSION           4		/* The current version */
+#define NTP_VERSION_MIN       1		/* The minimum valid version */
+#define NTP_VERSION_MAX       4		/* The maximum valid version */
+#define NTP_STRATUM_MAX      14		/* The maximum valid stratum */
+#define NTP_INSANITY     3600.0		/* Errors beyond this are hopeless */
+
+#define NTP_PACKET_MIN       48		/* Without authentication */
+#define NTP_PACKET_MAX       68		/* With authentication (ignored) */
+
+#define NTP_DISP_FIELD        8		/* Offset of dispersion field */
+#define NTP_REFERENCE        16		/* Offset of reference timestamp */
+#define NTP_ORIGINATE        24		/* Offset of originate timestamp */
+#define NTP_RECEIVE          32		/* Offset of receive timestamp */
+#define NTP_TRANSMIT         40		/* Offset of transmit timestamp */
+
+#define STATUS_NOWARNING      0		/* No Leap Indicator */
+#define STATUS_LEAPHIGH       1		/* Last Minute Has 61 Seconds */
+#define STATUS_LEAPLOW        2		/* Last Minute Has 59 Seconds */
+#define STATUS_ALARM          3		/* Server Clock Not Synchronized */
+
+#define MAX_QUERIES         25
+#define MAX_DELAY           15
+
+#define MILLION_L    1000000l		/* For conversion to/from timeval */
+#define MILLION_D       1.0e6		/* Must be equal to MILLION_L */
+
+struct ntp_data {
+	u_char		status;
+	u_char		version;
+	u_char		mode;
+	u_char		stratum;
+	double		receive;
+	double		transmit;
+	double		current;
+	u_int64_t	recvck;
+
+	/* Local State */
+	double		originate;
+	u_int64_t	xmitck;
+};
+
+void	ntp_client(const char *, int, struct timeval *, struct timeval *, int);
+int	sync_ntp(int, const struct sockaddr *, double *, double *);
+int	write_packet(int, struct ntp_data *);
+int	read_packet(int, struct ntp_data *, double *, double *);
+void	unpack_ntp(struct ntp_data *, u_char *);
+double	current_time(double);
+void	create_timeval(double, struct timeval *, struct timeval *);
+
+#ifdef DEBUG
+void	print_packet(const struct ntp_data *);
+#endif
+
+int	corrleaps;
+
+void
+ntp_client(const char *hostname, int family, struct timeval *new,
+    struct timeval *adjust, int leapflag)
+{
+	struct addrinfo hints, *res0, *res;
+	double offset, error;
+	int accept = 0, ret, s, ierror;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = family;
+	hints.ai_socktype = SOCK_DGRAM;
+	ierror = getaddrinfo(hostname, "ntp", &hints, &res0);
+	if (ierror) {
+		errx(1, "%s: %s", hostname, gai_strerror(ierror));
+		/*NOTREACHED*/
+	}
+
+	corrleaps = leapflag;
+	if (corrleaps)
+		ntpleaps_init();
+
+	s = -1;
+	for (res = res0; res; res = res->ai_next) {
+		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+		if (s < 0)
+			continue;
+
+		ret = sync_ntp(s, res->ai_addr, &offset, &error);
+		if (ret < 0) {
+#ifdef DEBUG
+			fprintf(stderr, "try the next address\n");
+#endif
+			close(s);
+			s = -1;
+			continue;
+		}
+
+		accept++;
+		break;
+	}
+	freeaddrinfo(res0);
+
+#ifdef DEBUG
+	fprintf(stderr, "Correction: %.6f +/- %.6f\n", offset, error);
+#endif
+
+	if (accept < 1)
+		errx(1, "Unable to get a reasonable time estimate");
+
+	create_timeval(offset, new, adjust);
+}
+
+int
+sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
+{
+	int attempts = 0, accepts = 0, rejects = 0;
+	int delay = MAX_DELAY, ret;
+	double deadline;
+	double a, b, x, y;
+	double minerr = 0.1;		/* Maximum ignorable variation */
+	struct ntp_data data;
+
+	deadline = current_time(JAN_1970) + delay;
+	*offset = 0.0;
+	*error = NTP_INSANITY;
+
+	if (connect(fd, peer, SA_LEN(peer)) < 0) {
+		warn("Failed to connect to server");
+		return (-1);
+	}
+
+	while (accepts < MAX_QUERIES && attempts < 2 * MAX_QUERIES) {
+		memset(&data, 0, sizeof(data));
+
+		if (current_time(JAN_1970) > deadline) {
+			warnx("Not enough valid responses received in time");
+			return (-1);
+		}
+
+		if (write_packet(fd, &data) < 0)
+			return (-1);
+
+		ret = read_packet(fd, &data, &x, &y);
+
+		if (ret < 0)
+			return (-1);
+		else if (ret > 0) {
+#ifdef DEBUG
+			print_packet(&data);
+#endif
+
+			if (++rejects > MAX_QUERIES) {
+				warnx("Too many bad or lost packets");
+				return (-1);
+			} else
+				continue;
+		} else
+			++accepts;
+
+#ifdef DEBUG
+		fprintf(stderr, "Offset: %.6f +/- %.6f\n", x, y);
+#endif
+
+		if ((a = x - *offset) < 0.0)
+			a = -a;
+		if (accepts <= 1)
+			a = 0.0;
+		b = *error + y;
+		if (y < *error) {
+			*offset = x;
+			*error = y;
+		}
+
+#ifdef DEBUG
+		fprintf(stderr, "Best: %.6f +/- %.6f\n", *offset, *error);
+#endif
+
+		if (a > b) {
+			warnx("Inconsistent times received from NTP server");
+			return (-1);
+		}
+
+		if ((data.status & STATUS_ALARM) == STATUS_ALARM) {
+			warnx("Ignoring NTP server with alarm flag set");
+			return (-1);
+		}
+
+		if (*error <= minerr)
+			break;
+	}
+
+	return (accepts);
+}
+
+/* Send out NTP packet. */
+int
+write_packet(int fd, struct ntp_data *data)
+{
+	u_char	packet[NTP_PACKET_MIN];
+	ssize_t	length;
+
+	memset(packet, 0, sizeof(packet));
+
+	packet[0] = (NTP_VERSION << 3) | (NTP_MODE_CLIENT);
+
+	arc4random_buf(&data->xmitck, sizeof(data->xmitck));
+
+	/*
+	 * Send out a random 64-bit number as our transmit time.  The NTP
+	 * server will copy said number into the originate field on the
+	 * response that it sends us.  This is totally legal per the SNTP spec.
+	 *
+	 * The impact of this is two fold: we no longer send out the current
+	 * system time for the world to see (which may aid an attacker), and
+	 * it gives us a (not very secure) way of knowing that we're not
+	 * getting spoofed by an attacker that can't capture our traffic
+	 * but can spoof packets from the NTP server we're communicating with.
+	 *
+	 * No endian concerns here.  Since we're running as a strict
+	 * unicast client, we don't have to worry about anyone else finding
+	 * the transmit field intelligible.
+	 */
+
+	bcopy(&data->xmitck, (packet + NTP_TRANSMIT), sizeof(data->xmitck));
+
+	data->originate = current_time(JAN_1970);
+
+	length = write(fd, packet, sizeof(packet));
+
+	if (length != sizeof(packet)) {
+		warn("Unable to send NTP packet to server");
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * Check the packet and work out the offset and optionally the error.
+ * Note that this contains more checking than xntp does. Return 0 for
+ * success, 1 for failure. Note that it must not change its arguments
+ * if it fails.
+ */
+int
+read_packet(int fd, struct ntp_data *data, double *off, double *error)
+{
+	u_char	receive[NTP_PACKET_MAX];
+	struct	pollfd pfd[1];
+	double	x, y;
+	int	length, r;
+
+	pfd[0].fd = fd;
+	pfd[0].events = POLLIN;
+
+retry:
+	r = poll(pfd, 1, 1000 * MAX_DELAY / MAX_QUERIES);
+	if (r < 0) {
+		if (errno == EINTR)
+			goto retry;
+		warn("select");
+		return (r);
+	}
+
+	if (r != 1)
+		return (1);
+	if ((pfd[0].revents & POLLIN) == 0)
+		return (1);
+
+	length = read(fd, receive, NTP_PACKET_MAX);
+	if (length < 0) {
+		warn("Unable to receive NTP packet from server");
+		return (-1);
+	}
+
+	if (length < NTP_PACKET_MIN || length > NTP_PACKET_MAX) {
+		warnx("Invalid NTP packet size, packet rejected");
+		return (1);
+	}
+
+	unpack_ntp(data, receive);
+
+	if (data->recvck != data->xmitck) {
+		warnx("Invalid cookie received, packet rejected");
+		return (1);
+	}
+
+	if (data->version < NTP_VERSION_MIN ||
+	    data->version > NTP_VERSION_MAX) {
+		warnx("Received NTP version %u, need %u or lower",
+		    data->version, NTP_VERSION);
+		return (1);
+	}
+
+	if (data->mode != NTP_MODE_SERVER) {
+		warnx("Invalid NTP server mode, packet rejected");
+		return (1);
+	}
+
+	if (data->stratum > NTP_STRATUM_MAX) {
+		warnx("Invalid stratum received, packet rejected");
+		return (1);
+	}
+
+	if (data->transmit == 0.0) {
+		warnx("Server clock invalid, packet rejected");
+		return (1);
+	}
+
+	x = data->receive - data->originate;
+	y = data->transmit - data->current;
+
+	*off = (x + y) / 2;
+	*error = x - y;
+
+	x = (data->current - data->originate) / 2;
+
+	if (x > *error)
+		*error = x;
+
+	return (0);
+}
+
+/*
+ * Unpack the essential data from an NTP packet, bypassing struct
+ * layout and endian problems.  Note that it ignores fields irrelevant
+ * to SNTP.
+ */
+void
+unpack_ntp(struct ntp_data *data, u_char *packet)
+{
+	int i;
+	double d;
+
+	data->current = current_time(JAN_1970);
+
+	data->status = (packet[0] >> 6);
+	data->version = (packet[0] >> 3) & 0x07;
+	data->mode = packet[0] & 0x07;
+	data->stratum = packet[1];
+
+	for (i = 0, d = 0.0; i < 8; ++i)
+	    d = 256.0*d+packet[NTP_RECEIVE+i];
+
+	data->receive = d / NTP_SCALE;
+
+	for (i = 0, d = 0.0; i < 8; ++i)
+	    d = 256.0*d+packet[NTP_TRANSMIT+i];
+
+	data->transmit = d / NTP_SCALE;
+
+	/* See write_packet for why this isn't an endian problem. */
+	bcopy((packet + NTP_ORIGINATE), &data->recvck, sizeof(data->recvck));
+}
+
+/*
+ * Get the current UTC time in seconds since the Epoch plus an offset
+ * (usually the time from the beginning of the century to the Epoch)
+ */
+double
+current_time(double offset)
+{
+	struct timeval current;
+	u_int64_t t;
+
+	if (gettimeofday(&current, NULL))
+		err(1, "Could not get local time of day");
+
+	/*
+	 * At this point, current has the current TAI time.
+	 * Now subtract leap seconds to set the posix tick.
+	 */
+
+	t = SEC_TO_TAI64(current.tv_sec);
+	if (corrleaps)
+		ntpleaps_sub(&t);
+
+	return (offset + TAI64_TO_SEC(t) + 1.0e-6 * current.tv_usec);
+}
+
+/*
+ * Change offset into current UTC time. This is portable, even if
+ * struct timeval uses an unsigned long for tv_sec.
+ */
+void
+create_timeval(double difference, struct timeval *new, struct timeval *adjust)
+{
+	struct timeval old;
+	long n;
+
+	/* Start by converting to timeval format. Note that we have to
+	 * cater for negative, unsigned values. */
+	if ((n = (long) difference) > difference)
+		--n;
+	adjust->tv_sec = n;
+	adjust->tv_usec = (long) (MILLION_D * (difference-n));
+	errno = 0;
+	if (gettimeofday(&old, NULL))
+		err(1, "Could not get local time of day");
+	new->tv_sec = old.tv_sec + adjust->tv_sec;
+	new->tv_usec = (n = (long) old.tv_usec + (long) adjust->tv_usec);
+
+	if (n < 0) {
+		new->tv_usec += MILLION_L;
+		--new->tv_sec;
+	} else if (n >= MILLION_L) {
+		new->tv_usec -= MILLION_L;
+		++new->tv_sec;
+	}
+}
+
+#ifdef DEBUG
+void
+print_packet(const struct ntp_data *data)
+{
+	printf("status:      %u\n", data->status);
+	printf("version:     %u\n", data->version);
+	printf("mode:        %u\n", data->mode);
+	printf("stratum:     %u\n", data->stratum);
+	printf("originate:   %f\n", data->originate);
+	printf("receive:     %f\n", data->receive);
+	printf("transmit:    %f\n", data->transmit);
+	printf("current:     %f\n", data->current);
+	printf("xmitck:      0x%0llX\n", data->xmitck);
+	printf("recvck:      0x%0llX\n", data->recvck);
+};
+#endif
diff --git a/src/usr.sbin/rdate/ntpleaps.c b/src/usr.sbin/rdate/ntpleaps.c
new file mode 100644
index 0000000..8c9323e
--- /dev/null
+++ b/src/usr.sbin/rdate/ntpleaps.c
@@ -0,0 +1,196 @@
+/*	$OpenBSD: ntpleaps.c,v 1.13 2014/10/08 04:48:22 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 2002 Thorsten Glaser. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    - Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    - Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Leap second support for NTP clients (generic) */
+
+/*
+ * I could include tzfile.h, but this would make the code unportable
+ * at no real benefit. Read tzfile.h for why.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ntpleaps.h"
+
+static u_int64_t *leapsecs;
+static unsigned int leapsecs_num;
+
+u_int32_t	read_be_dword(u_int8_t *ptr);
+
+
+int
+ntpleaps_init(void)
+{
+	static int doneinit;
+	static int donewarn;
+
+	if (doneinit)
+		return (0);
+
+	if (ntpleaps_read() == 0) {
+		doneinit = 1;
+		return (0);
+	}
+
+	/* This does not really hurt, but users will complain about
+	 * off-by-22-seconds (at time of coding) errors if we don't warn.
+	 */
+	if (!donewarn) {
+		fputs("Warning: error reading tzfile. You will NOT be\n"
+		    "able to get legal time or posix compliance!\n", stderr);
+		donewarn = 1;	/* put it only once */
+	}
+
+	return (-1);
+}
+
+int
+ntpleaps_sub(u_int64_t *t)
+{
+	unsigned int i = 0;
+	u_int64_t u;
+	int r = 1;
+
+	if (ntpleaps_init() == -1)
+		return (-1);
+
+	u = *t;
+
+	while (i < leapsecs_num) {
+		if (u < leapsecs[i]) {
+			r--;
+			break;
+		}
+		if (u == leapsecs[i++])
+			break;
+	}
+
+	*t = u - i;
+	return (r);
+}
+
+u_int32_t
+read_be_dword(u_int8_t *ptr)
+{
+	u_int32_t res;
+
+	memcpy(&res, ptr, 4);
+	return (ntohl(res));
+}
+
+
+int
+ntpleaps_read(void)
+{
+	int fd;
+	unsigned int r;
+	u_int8_t buf[32];
+	u_int32_t m1, m2, m3;
+	u_int64_t s;
+	u_int64_t *l;
+
+	fd = open("/usr/share/zoneinfo/right/UTC", O_RDONLY | O_NDELAY);
+	if (fd == -1)
+		return (-1);
+
+	/* Check signature */
+	read(fd, buf, 4);
+	buf[4] = 0;
+	if (strcmp((const char *)buf, "TZif")) {
+		close(fd);
+		return (-1);
+	}
+
+	/* Pre-initialize buf[24..27] so we need not check read(2) result */
+	buf[24] = 0;
+	buf[25] = 0;
+	buf[26] = 0;
+	buf[27] = 0;
+
+	/* Skip uninteresting parts of header */
+	read(fd, buf, 28);
+
+	/* Read number of leap second entries */
+	r = read_be_dword(&buf[24]);
+	/* Check for plausibility - arbitrary values */
+	if ((r < 20) || (r > 60000)) {
+		close(fd);
+		return (-1);
+	}
+	if ((l = reallocarray(NULL, r, sizeof(u_int64_t))) == NULL) {
+		close(fd);
+		return (-1);
+	}
+
+	/* Skip further uninteresting stuff */
+	read(fd, buf, 12);
+	m1 = read_be_dword(buf);
+	m2 = read_be_dword(&buf[4]);
+	m3 = read_be_dword(&buf[8]);
+	m3 += (m1 << 2)+m1+(m2 << 2)+(m2 << 1);
+	lseek(fd, (off_t)m3, SEEK_CUR);
+
+	/* Now go parse the tzfile leap second info */
+	for (m1 = 0; m1 < r; m1++) {
+		if (read(fd, buf, 8) != 8) {
+			free(l);
+			close(fd);
+			return (-1);
+		}
+		s = SEC_TO_TAI64(read_be_dword(buf));
+		/*
+		 * Assume just _one_ leap second on each entry, and compensate
+		 * the lacking error checking by validating the first entry
+		 * against the known value
+		 */
+		if (!m1 && s != 0x4000000004B2580AULL) {
+			free(l);
+			close(fd);
+			return (-1);
+		}
+		l[m1] = s;
+	}
+
+	/* Clean up and activate the table */
+	close(fd);
+	if (leapsecs != NULL)
+		free(leapsecs);
+	leapsecs = l;
+	leapsecs_num = r;
+	return (0);
+}
diff --git a/src/usr.sbin/rdate/ntpleaps.h b/src/usr.sbin/rdate/ntpleaps.h
new file mode 100644
index 0000000..30dda83
--- /dev/null
+++ b/src/usr.sbin/rdate/ntpleaps.h
@@ -0,0 +1,73 @@
+/*	$OpenBSD: ntpleaps.h,v 1.4 2007/11/25 16:40:04 jmc Exp $	*/
+
+/*
+ * Copyright (c) 2002 Thorsten Glaser. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    - Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    - Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Leap second support for SNTP clients
+ * This header file and its corresponding C file provide generic
+ * ability for NTP or SNTP clients to correctly handle leap seconds
+ * by reading them from an always existing file and subtracting the
+ * leap seconds from the NTP return value before setting the posix
+ * clock. This is fairly portable between operating systems and may
+ * be used for patching other ntp clients, too. The tzfile used is:
+ * /usr/share/zoneinfo/right/UTC which is available on any unix-like
+ * platform with the Olson tz library, which is necessary to get real
+ * leap second zoneinfo files and userland support anyways.
+ */
+
+#ifndef _NTPLEAPS_H
+#define _NTPLEAPS_H
+
+/* Offset between struct timeval.tv_sec and a tai64_t */
+#define	NTPLEAPS_OFFSET	(4611686018427387914ULL)
+
+/* Hide this ugly value from programmes */
+#define	SEC_TO_TAI64(s)	(NTPLEAPS_OFFSET + (u_int64_t)(s))
+#define	TAI64_TO_SEC(t)	((t) - NTPLEAPS_OFFSET)
+
+/* Initializes the leap second table. Does not need to be called
+ * before usage of the subtract function, but calls ntpleaps_read.
+ * returns 0 on success, -1 on error (displays a warning on stderr)
+ */
+int ntpleaps_init(void);
+
+/* Re-reads the leap second table, thus consuming quite much time.
+ * Ought to be called from within daemons at least once a month to
+ * ensure the in-memory table is always up-to-date.
+ * returns 0 on success, -1 on error (leap seconds will not be available)
+ */
+int ntpleaps_read(void);
+
+/* Subtracts leap seconds from the given value (converts NTP time
+ * to posix clock tick time.
+ * returns 0 on success, -1 on error (time is unchanged), 1 on leap second
+ */
+int ntpleaps_sub(u_int64_t *);
+
+#endif
diff --git a/src/usr.sbin/rdate/rdate.8 b/src/usr.sbin/rdate/rdate.8
new file mode 100644
index 0000000..bf990d9
--- /dev/null
+++ b/src/usr.sbin/rdate/rdate.8
@@ -0,0 +1,110 @@
+.\"	$OpenBSD: rdate.8,v 1.36 2013/04/19 19:14:46 millert Exp $
+.\"	$NetBSD: rdate.8,v 1.4 1996/04/08 20:55:17 jtc Exp $
+.\"
+.\" Copyright (c) 1994 Christos Zoulas
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by Christos Zoulas.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\"    derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd $Mdocdate: April 19 2013 $
+.Dt RDATE 8
+.Os
+.Sh NAME
+.Nm rdate
+.Nd set the system's date from a remote host
+.Sh SYNOPSIS
+.Nm rdate
+.Op Fl 46acnopsv
+.Ar host
+.Sh DESCRIPTION
+.Nm
+displays and sets the local date and time from the
+host name or address given as the argument.
+The time source may be an RFC 5905 protocol SNTP/NTP server
+or an RFC 868 TCP protocol server,
+which is usually implemented as a built-in service of
+.Xr inetd 8 .
+By default,
+.Nm
+uses the RFC 5905 SNTP/NTP protocol.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl a
+Use the
+.Xr adjtime 2
+call to gradually skew the local time to the
+remote time rather than just hopping.
+.It Fl c
+Correct leap seconds.
+This should be used only when synchronizing to a server
+which does not correctly account for leap seconds.
+.It Fl n
+Use SNTP (RFC 5905) instead of the RFC 868 time protocol.
+This is the default.
+.It Fl o
+Use an RFC 868 TCP protocol server instead of SNTP.
+This protocol is obsolete as it is not capable of representing
+dates past January 19, 2038 03:14:07 GMT.
+.It Fl p
+Do not set, just print the remote time.
+.It Fl s
+Do not print the time.
+.It Fl v
+Verbose output.
+Always show the adjustment.
+.El
+.Sh FILES
+.Bl -tag -width /var/log/wtmp -compact
+.It Pa /var/log/wtmp
+record of date resets and time changes
+.El
+.Sh EXAMPLES
+To get the legal time in Germany, set the
+.Pa /etc/localtime
+symlink to
+.Pa /usr/share/zoneinfo/right/Europe/Berlin
+and issue the following command:
+.Pp
+.D1 Li "# rdate -v ptbtime1.ptb.de"
+.Pp
+The command of course assumes you have a working internet connection
+and DNS set up to connect to the server at
+.Sy Physikalisch-Technische Bundesanstalt
+in Braunschweig, Germany.
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr adjtime 2 ,
+.Xr inetd 8 ,
+.Xr ntpd 8
diff --git a/src/usr.sbin/rdate/rdate.c b/src/usr.sbin/rdate/rdate.c
new file mode 100644
index 0000000..1c503dc
--- /dev/null
+++ b/src/usr.sbin/rdate/rdate.c
@@ -0,0 +1,173 @@
+/*	$OpenBSD: rdate.c,v 1.30 2013/11/12 22:27:13 deraadt Exp $	*/
+/*	$NetBSD: rdate.c,v 1.4 1996/03/16 12:37:45 pk Exp $	*/
+
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * rdate.c: Set the date from the specified host
+ *
+ *	Time is returned as the number of seconds since
+ *	midnight January 1st 1900.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <err.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+/* there are systems without libutil; for portability */
+#ifndef NO_UTIL
+#include <util.h>
+#else
+#define logwtmp(a,b,c)
+#endif
+
+void rfc868time_client(const char *, int, struct timeval *, struct timeval *, int);
+void ntp_client(const char *, int, struct timeval *, struct timeval *, int);
+
+extern char    *__progname;
+__dead void	usage(void);
+
+__dead void
+usage(void)
+{
+	(void) fprintf(stderr, "usage: %s [-46acnopsv] host\n", __progname);
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	int             pr = 0, silent = 0, ntp = 1, verbose = 0;
+	int		slidetime = 0, corrleaps = 0;
+	char           *hname;
+	extern int      optind;
+	int             c;
+	int		family = PF_UNSPEC;
+
+	struct timeval new, adjust;
+
+	while ((c = getopt(argc, argv, "46psanocv")) != -1) {
+		switch (c) {
+		case '4':
+			family = PF_INET;
+			break;
+
+		case '6':
+			family = PF_INET6;
+			break;
+
+		case 'p':
+			pr++;
+			break;
+
+		case 's':
+			silent++;
+			break;
+
+		case 'a':
+			slidetime++;
+			break;
+
+		case 'n':
+			ntp++;
+			break;
+
+		case 'o':
+			ntp = 0;
+			break;
+
+		case 'c':
+			corrleaps = 1;
+			break;
+
+		case 'v':
+			verbose++;
+			break;
+
+		default:
+			usage();
+		}
+	}
+	if (argc - 1 != optind)
+		usage();
+	hname = argv[optind];
+
+	if (ntp)
+		ntp_client(hname, family, &new, &adjust, corrleaps);
+	else
+		rfc868time_client(hname, family, &new, &adjust, corrleaps);
+
+	if (!pr) {
+		if (!slidetime) {
+			logwtmp("|", "date", "");
+			if (settimeofday(&new, NULL) == -1)
+				err(1, "Could not set time of day");
+			logwtmp("{", "date", "");
+		} else {
+			if (adjtime(&adjust, NULL) == -1)
+				err(1, "Could not adjust time of day");
+		}
+	}
+
+	if (!silent) {
+		struct tm      *ltm;
+		char		buf[80];
+		time_t		tim = new.tv_sec;
+		double		adjsec;
+
+		ltm = localtime(&tim);
+		(void) strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y\n", ltm);
+		(void) fputs(buf, stdout);
+
+		adjsec  = adjust.tv_sec + adjust.tv_usec / 1.0e6;
+
+		if (slidetime || verbose) {
+			if (ntp)
+				(void) fprintf(stdout,
+				   "%s: adjust local clock by %.6f seconds\n",
+				   __progname, adjsec);
+			else
+				(void) fprintf(stdout,
+				   "%s: adjust local clock by %lld seconds\n",
+				   __progname, (long long)adjust.tv_sec);
+		}
+	}
+
+	return 0;
+}
diff --git a/src/usr.sbin/rdate/rfc868time.c b/src/usr.sbin/rdate/rfc868time.c
new file mode 100644
index 0000000..7f1b23b
--- /dev/null
+++ b/src/usr.sbin/rdate/rfc868time.c
@@ -0,0 +1,122 @@
+/*	$OpenBSD: rfc868time.c,v 1.9 2013/11/12 22:27:13 deraadt Exp $	*/
+/*	$NetBSD: rdate.c,v 1.4 1996/03/16 12:37:45 pk Exp $	*/
+
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * rdate.c: Set the date from the specified host
+ *
+ *	Uses the rfc868 time protocol at socket 37 (tcp).
+ *	Time is returned as the number of seconds since
+ *	midnight January 1st 1900.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <err.h>
+#include <string.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <time.h>
+
+/* Obviously it is not just for SNTP clients... */
+#include "ntpleaps.h"
+
+/* seconds from midnight Jan 1900 - 1970 */
+#define DIFFERENCE 2208988800UL
+
+void
+rfc868time_client(const char *hostname, int family, struct timeval *new,
+    struct timeval *adjust, int leapflag);
+
+
+void
+rfc868time_client(const char *hostname, int family, struct timeval *new,
+    struct timeval *adjust, int leapflag)
+{
+	struct addrinfo hints, *res0, *res;
+	struct timeval old;
+	u_int32_t tim;	/* RFC 868 states clearly this is an uint32 */
+	int s;
+	int error;
+	u_int64_t td;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = family;
+	hints.ai_socktype = SOCK_STREAM;
+	error = getaddrinfo(hostname, "time", &hints, &res0);
+	if (error) {
+		errx(1, "%s: %s", hostname, gai_strerror(error));
+		/*NOTREACHED*/
+	}
+
+	s = -1;
+	for (res = res0; res; res = res->ai_next) {
+		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+		if (s < 0)
+			continue;
+
+		if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+			close(s);
+			s = -1;
+			continue;
+		}
+
+		break;
+	}
+	if (s < 0)
+		err(1, "Could not connect socket");
+	freeaddrinfo(res0);
+
+	if (read(s, &tim, sizeof(tim)) != sizeof(tim))
+		err(1, "Could not read data");
+
+	(void) close(s);
+	tim = ntohl(tim) - DIFFERENCE;
+
+	if (gettimeofday(&old, NULL) == -1)
+		err(1, "Could not get local time of day");
+
+	td = SEC_TO_TAI64(old.tv_sec);
+	if (leapflag)
+		ntpleaps_sub(&td);
+
+	adjust->tv_sec = tim - TAI64_TO_SEC(td);
+	adjust->tv_usec = 0;
+
+	new->tv_sec = old.tv_sec + adjust->tv_sec;
+	new->tv_usec = 0;
+}