summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2013-04-17 19:26:11 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2013-04-17 19:26:11 +0000
commit157b6d8e95b98c322d0167bbbf7213f7b641e4d9 (patch)
tree874e309ef9024211a94664f26846722d2a6421e2 /usr.sbin
parent80973d7181c8efebe9f402c244e838138f1bf77c (diff)
Replace hand-rolled date printing/parsing code with strftime()/strptime().
Use timegm() because all the dates are in UTC and the 'standard' routines can't handle the truth. Remove some 'time_t is 32bits' assumptions. Print 'UTC' at the end of dates in the leases file, rather than mentioning that all dates are UTC in a comment at the top of the file. Feedback and suggestions from guenther@, kettenis@, otto@, tedu@, deraadt@.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/dhcpd/db.c36
-rw-r--r--usr.sbin/dhcpd/dhcpd.h5
-rw-r--r--usr.sbin/dhcpd/parse.c187
3 files changed, 62 insertions, 166 deletions
diff --git a/usr.sbin/dhcpd/db.c b/usr.sbin/dhcpd/db.c
index 8e3887e7ace..3f0df99eea6 100644
--- a/usr.sbin/dhcpd/db.c
+++ b/usr.sbin/dhcpd/db.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: db.c,v 1.11 2013/04/13 16:40:36 krw Exp $ */
+/* $OpenBSD: db.c,v 1.12 2013/04/17 19:26:10 krw Exp $ */
/*
* Persistent database management routines for DHCPD.
@@ -56,8 +56,8 @@ time_t write_time;
int
write_lease(struct lease *lease)
{
- struct tm *t;
- char tbuf[64];
+ char tbuf[26]; /* "w yyyy/mm/dd hh:mm:ss UTC" */
+ size_t rsltsz;
int errors = 0;
int i;
@@ -66,21 +66,15 @@ write_lease(struct lease *lease)
if (fprintf(db_file, "lease %s {\n", piaddr(lease->ip_addr)) == -1)
++errors;
- t = gmtime(&lease->starts);
- snprintf(tbuf, sizeof(tbuf), "%d %d/%02d/%02d %02d:%02d:%02d;",
- t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
- t->tm_hour, t->tm_min, t->tm_sec);
+ rsltsz = strftime(tbuf, sizeof(tbuf), DB_TIMEFMT,
+ gmtime(&lease->starts));
+ if (rsltsz == 0 || fprintf(db_file, "\tstarts %s;\n", tbuf) == -1)
+ errors++;
- if (fprintf(db_file, "\tstarts %s\n", tbuf) == -1)
- ++errors;
-
- t = gmtime(&lease->ends);
- snprintf(tbuf, sizeof(tbuf), "%d %d/%02d/%02d %02d:%02d:%02d;",
- t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
- t->tm_hour, t->tm_min, t->tm_sec);
-
- if (fprintf(db_file, "\tends %s", tbuf) == -1)
- ++errors;
+ rsltsz = strftime(tbuf, sizeof(tbuf), DB_TIMEFMT,
+ gmtime(&lease->ends));
+ if (rsltsz == 0 || fprintf(db_file, "\tends %s;\n", tbuf) == -1)
+ errors++;
if (lease->hardware_addr.hlen) {
if (fprintf(db_file, "\n\thardware %s %s;",
@@ -206,14 +200,6 @@ new_lease_file(void)
fflush(db_file);
rewind(db_file);
- /*
- * Write an introduction so people don't complain about time being off.
- */
- fprintf(db_file, "# All times in this file are in UTC (GMT), "
- "not your local timezone.\n");
- fprintf(db_file, "# The format of this file is documented in "
- "the dhcpd.leases(5) manual page.\n\n");
-
/* Write out all the leases that we know of... */
counting = 0;
write_leases();
diff --git a/usr.sbin/dhcpd/dhcpd.h b/usr.sbin/dhcpd/dhcpd.h
index 125e71fbfb2..9c13aa803d8 100644
--- a/usr.sbin/dhcpd/dhcpd.h
+++ b/usr.sbin/dhcpd/dhcpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhcpd.h,v 1.46 2013/02/03 21:04:19 krw Exp $ */
+/* $OpenBSD: dhcpd.h,v 1.47 2013/04/17 19:26:10 krw Exp $ */
/*
* Copyright (c) 1995, 1996, 1997, 1998, 1999
@@ -74,6 +74,9 @@
#include "dhcp.h"
#include "tree.h"
+#define DB_TIMEFMT "%w %Y/%m/%d %T UTC"
+#define OLD_DB_TIMEFMT "%w %Y/%m/%d %T"
+
#define SERVER_PORT 67
#define CLIENT_PORT 68
diff --git a/usr.sbin/dhcpd/parse.c b/usr.sbin/dhcpd/parse.c
index b7c5159d37b..060927dbb54 100644
--- a/usr.sbin/dhcpd/parse.c
+++ b/usr.sbin/dhcpd/parse.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.c,v 1.13 2010/03/27 14:11:38 krw Exp $ */
+/* $OpenBSD: parse.c,v 1.14 2013/04/17 19:26:10 krw Exp $ */
/* Common parser code for dhcpd and dhclient. */
@@ -259,6 +259,7 @@ void
parse_lease_time(FILE *cfile, time_t *timep)
{
char *val;
+ uint32_t value;
int token;
token = next_token(&val, cfile);
@@ -267,9 +268,9 @@ parse_lease_time(FILE *cfile, time_t *timep)
skip_to_semi(cfile);
return;
}
- convert_num((unsigned char *)timep, val, 10, 32);
+ convert_num((unsigned char *)&value, val, 10, 32);
/* Unswap the number - convert_num returns stuff in NBO. */
- *timep = ntohl(*timep); /* XXX */
+ *timep = ntohl(value); /* XXX */
parse_semi(cfile);
}
@@ -465,160 +466,66 @@ convert_num(unsigned char *buf, char *str, int base, int size)
/*
* date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
- * NUMBER COLON NUMBER COLON NUMBER SEMI
+ * NUMBER COLON NUMBER COLON NUMBER UTC SEMI
*
- * Dates are always in GMT; first number is day of week; next is
+ * Dates are always in UTC; first number is day of week; next is
* year/month/day; next is hours:minutes:seconds on a 24-hour
* clock.
*/
time_t
parse_date(FILE *cfile)
{
- static int months[11] = { 31, 59, 90, 120, 151, 181,
- 212, 243, 273, 304, 334 };
- int guess, token;
struct tm tm;
- char *val;
-
- /* Day of week... */
- token = next_token(&val, cfile);
- if (token != TOK_NUMBER) {
- parse_warn("numeric day of week expected.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
- }
- tm.tm_wday = atoi(val);
-
- /* Year... */
- token = next_token(&val, cfile);
- if (token != TOK_NUMBER) {
- parse_warn("numeric year expected.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
- }
- tm.tm_year = atoi(val);
- if (tm.tm_year > 1900)
- tm.tm_year -= 1900;
-
- /* Slash separating year from month... */
- token = next_token(&val, cfile);
- if (token != '/') {
- parse_warn("expected slash separating year from month.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
- }
-
- /* Month... */
- token = next_token(&val, cfile);
- if (token != TOK_NUMBER) {
- parse_warn("numeric month expected.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
- }
- tm.tm_mon = atoi(val) - 1;
-
- /* Slash separating month from day... */
- token = next_token(&val, cfile);
- if (token != '/') {
- parse_warn("expected slash separating month from day.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
- }
-
- /* Day... */
- token = next_token(&val, cfile);
- if (token != TOK_NUMBER) {
- parse_warn("numeric day of month expected.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
- }
- tm.tm_mday = atoi(val);
-
- /* Hour... */
- token = next_token(&val, cfile);
- if (token != TOK_NUMBER) {
- parse_warn("numeric hour expected.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
- }
- tm.tm_hour = atoi(val);
+ char timestr[26]; /* "w yyyy/mm/dd hh:mm:ss UTC" */
+ char *val, *p;
+ size_t n;
+ time_t guess;
+ int token;
- /* Colon separating hour from minute... */
- token = next_token(&val, cfile);
- if (token != ':') {
- parse_warn("expected colon separating hour from minute.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
- }
+ memset(timestr, 0, sizeof(timestr));
- /* Minute... */
- token = next_token(&val, cfile);
- if (token != TOK_NUMBER) {
- parse_warn("numeric minute expected.");
- if (token != ';')
+ do {
+ token = peek_token(NULL, cfile);
+ switch (token) {
+ case TOK_NAME:
+ case TOK_NUMBER:
+ case '/':
+ case ':':
+ token = next_token(&val, cfile);
+ n = strlcat(timestr, val, sizeof(timestr));
+ if (n >= sizeof(timestr)) {
+ /* XXX Will break after year 9999! */
+ parse_warn("time string too long");
+ skip_to_semi(cfile);
+ return (0);
+ }
+ break;
+ case';':
+ break;
+ default:
+ parse_warn("invalid time string");
skip_to_semi(cfile);
- return (0);
- }
- tm.tm_min = atoi(val);
+ return (0);
+ }
+ } while (token != ';');
- /* Colon separating minute from second... */
- token = next_token(&val, cfile);
- if (token != ':') {
- parse_warn("expected colon separating minute from second.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
- }
+ parse_semi(cfile);
- /* Second... */
- token = next_token(&val, cfile);
- if (token != TOK_NUMBER) {
- parse_warn("numeric second expected.");
- if (token != ';')
- skip_to_semi(cfile);
- return (0);
+ memset(&tm, 0, sizeof(tm)); /* 'cuz strptime ignores tm_isdt. */
+ p = strptime(timestr, DB_TIMEFMT, &tm);
+ if (p == NULL || *p != '\0') {
+ p = strptime(timestr, OLD_DB_TIMEFMT, &tm);
+ if (p == NULL || *p != '\0') {
+ parse_warn("unparseable time string");
+ return (0);
+ }
}
- tm.tm_sec = atoi(val);
- tm.tm_isdst = 0;
-
- /* XXX: We assume that mktime does not use tm_yday. */
- tm.tm_yday = 0;
- /* Make sure the date ends in a semicolon... */
- token = next_token(&val, cfile);
- if (token != ';') {
- parse_warn("semicolon expected.");
- skip_to_semi(cfile);
+ guess = timegm(&tm);
+ if (guess == -1) {
+ parse_warn("time could not be represented");
return (0);
}
- /* Guess the time value... */
- guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */
- (tm.tm_year - 69) / 4 + /* Leap days since '70 */
- (tm.tm_mon /* Days in months this year */
- ? months[tm.tm_mon - 1] : 0) +
- (tm.tm_mon > 1 && /* Leap day this year */
- !((tm.tm_year - 72) & 3)) +
- tm.tm_mday - 1) * 24) + /* Day of month */
- tm.tm_hour) * 60) + tm.tm_min) * 60) + tm.tm_sec;
-
- /*
- * This guess could be wrong because of leap seconds or other
- * weirdness we don't know about that the system does. For
- * now, we're just going to accept the guess, but at some point
- * it might be nice to do a successive approximation here to get
- * an exact value. Even if the error is small, if the server
- * is restarted frequently (and thus the lease database is
- * reread), the error could accumulate into something
- * significant.
- */
return (guess);
}