diff options
author | Christian Neukirchen <chneukirchen@gmail.com> | 2015-01-09 17:50:39 +0100 |
---|---|---|
committer | Christian Neukirchen <chneukirchen@gmail.com> | 2015-01-09 17:50:39 +0100 |
commit | eeed21e84c1702e4b6c6c8ccbef5b245dd9daa25 (patch) | |
tree | 0b8348d97b1f6bb625214480054059def8d98afc | |
parent | 0d9ab362ff16978b87a0ff8a2a67e0e7ccb86d64 (diff) | |
download | outils-eeed21e84c1702e4b6c6c8ccbef5b245dd9daa25.tar.gz outils-eeed21e84c1702e4b6c6c8ccbef5b245dd9daa25.tar.xz outils-eeed21e84c1702e4b6c6c8ccbef5b245dd9daa25.zip |
add rdate (which speaks SNTP really)
-rw-r--r-- | src/usr.sbin/rdate/Makefile | 11 | ||||
-rw-r--r-- | src/usr.sbin/rdate/ntp.c | 488 | ||||
-rw-r--r-- | src/usr.sbin/rdate/ntpleaps.c | 196 | ||||
-rw-r--r-- | src/usr.sbin/rdate/ntpleaps.h | 73 | ||||
-rw-r--r-- | src/usr.sbin/rdate/rdate.8 | 110 | ||||
-rw-r--r-- | src/usr.sbin/rdate/rdate.c | 173 | ||||
-rw-r--r-- | src/usr.sbin/rdate/rfc868time.c | 122 |
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(¤t, 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; +} |