diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-04-17 19:26:11 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-04-17 19:26:11 +0000 |
commit | 157b6d8e95b98c322d0167bbbf7213f7b641e4d9 (patch) | |
tree | 874e309ef9024211a94664f26846722d2a6421e2 /usr.sbin | |
parent | 80973d7181c8efebe9f402c244e838138f1bf77c (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.c | 36 | ||||
-rw-r--r-- | usr.sbin/dhcpd/dhcpd.h | 5 | ||||
-rw-r--r-- | usr.sbin/dhcpd/parse.c | 187 |
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); } |