From c210cac00f2584f031b56b4cdd2e801dbb9e1348 Mon Sep 17 00:00:00 2001 From: Alex Bahm Date: Mon, 10 Jul 2023 10:56:05 -0500 Subject: [PATCH] dhclient: fix time parsing for leases expiring after 2038 Convert lease parsing to timegm to calculate timestamp. For reference, when writing the lease, we use gmtime to convert the timestamp to struct tm. Reviewed By: markj, vangyzen MFC after: 2 weeks Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D40760 --- sbin/dhclient/parse.c | 28 +------------- sbin/dhclient/tests/Makefile | 3 +- sbin/dhclient/tests/fake.c | 15 ++++++++ sbin/dhclient/tests/option-domain-search.c | 45 ++++++++++++++++++++++ 4 files changed, 64 insertions(+), 27 deletions(-) diff --git a/sbin/dhclient/parse.c b/sbin/dhclient/parse.c index 4018f70f3a5d..70e2013d0813 100644 --- a/sbin/dhclient/parse.c +++ b/sbin/dhclient/parse.c @@ -444,9 +444,7 @@ convert_num(unsigned char *buf, char *str, unsigned base, int size) time_t parse_date(FILE *cfile) { - static int months[11] = { 31, 59, 90, 120, 151, 181, - 212, 243, 273, 304, 334 }; - int guess, token; + int token; struct tm tm; char *val; @@ -570,27 +568,5 @@ parse_date(FILE *cfile) 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); + return (timegm(&tm)); } diff --git a/sbin/dhclient/tests/Makefile b/sbin/dhclient/tests/Makefile index ce4c7acb822e..790d3dbcccce 100644 --- a/sbin/dhclient/tests/Makefile +++ b/sbin/dhclient/tests/Makefile @@ -6,7 +6,8 @@ ATF_TESTS_SH= pcp PLAIN_TESTS_C= option-domain-search_test SRCS.option-domain-search_test= alloc.c convert.c hash.c options.c \ - tables.c fake.c option-domain-search.c + tables.c parse.c conflex.c tree.c fake.c \ + option-domain-search.c CFLAGS.option-domain-search_test+= -I${.CURDIR:H} LIBADD.option-domain-search_test= util diff --git a/sbin/dhclient/tests/fake.c b/sbin/dhclient/tests/fake.c index 6a170953beb0..17b721527f04 100644 --- a/sbin/dhclient/tests/fake.c +++ b/sbin/dhclient/tests/fake.c @@ -7,6 +7,7 @@ #include "dhcpd.h" extern jmp_buf env; +int warnings_occurred; void error(const char *fmt, ...) @@ -52,6 +53,20 @@ note(const char *fmt, ...) return ret; } +int +parse_warn(const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + + return ret; +} + void bootp(struct packet *packet) { diff --git a/sbin/dhclient/tests/option-domain-search.c b/sbin/dhclient/tests/option-domain-search.c index b79f9a560137..a3517c9c1dc1 100644 --- a/sbin/dhclient/tests/option-domain-search.c +++ b/sbin/dhclient/tests/option-domain-search.c @@ -303,6 +303,49 @@ multiple_domains_valid() free(option->data); } +static +void +parse_date_helper(const char *string, time_t timestamp) +{ + int ret = 0; + FILE *file = NULL; + time_t ts; + + file = fopen("/tmp/dhclient.test", "w"); + if (!file) + abort(); + + ret = fwrite(string, strlen(string), 1, file); + if (ret <= 0) + abort(); + + fclose(file); + + file = fopen("/tmp/dhclient.test", "r"); + if (!file) + abort(); + + new_parse("test"); + ts = parse_date(file); + if (ts != timestamp) + abort(); + + fclose(file); +} + +void +parse_date_valid(void) +{ + int ret; + + ret = setjmp(env); + if (ret != 0) + abort(); + + parse_date_helper(" 2 2024/7/2 20:25:50;\n", 1719951950); + parse_date_helper(" 1 2091/7/2 20:25:50;\n", 3834246350); +} + int main(int argc, char *argv[]) { @@ -324,5 +367,7 @@ main(int argc, char *argv[]) multiple_domains_valid(); + parse_date_valid(); + return (0); }