From 0044443a020d15c262e9f6c724b29365a8148437 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 28 Nov 2019 15:27:58 +0100 Subject: parsedate: offer a getdate_capped() alternative ... and use internally. This function will return TIME_T_MAX instead of failure if the parsed data is found to be larger than what can be represented. TIME_T_MAX being the largest value curl can represent. Reviewed-by: Daniel Gustafsson Reported-by: JanB on github Fixes #4152 Closes #4651 --- lib/altsvc.c | 2 +- lib/cookie.c | 3 ++- lib/ftp.c | 4 +--- lib/http.c | 6 ++---- lib/parsedate.c | 24 ++++++++++++++++++++++++ lib/parsedate.h | 6 ++++++ 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/altsvc.c b/lib/altsvc.c index c3dbb708a..28c9276b1 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -161,7 +161,7 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line) date, &persist, &prio); if(9 == rc) { struct altsvc *as; - time_t expires = curl_getdate(date, NULL); + time_t expires = Curl_getdate_capped(date); as = altsvc_create(srchost, dsthost, srcalpn, dstalpn, srcport, dstport); if(as) { as->expires = expires; diff --git a/lib/cookie.c b/lib/cookie.c index 7e68b0785..c9e420ad4 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -96,6 +96,7 @@ Example set of cookies: #include "curl_get_line.h" #include "curl_memrchr.h" #include "inet_pton.h" +#include "parsedate.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -715,7 +716,7 @@ Curl_cookie_add(struct Curl_easy *data, else if(co->expirestr) { /* Note that if the date couldn't get parsed for whatever reason, the cookie will be treated as a session cookie */ - co->expires = curl_getdate(co->expirestr, NULL); + co->expires = Curl_getdate_capped(co->expirestr); /* Session cookies have expires set to 0 so if we get that back from the date parser let's add a second to make it a diff --git a/lib/ftp.c b/lib/ftp.c index 8072a33d5..469096f0f 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -2039,13 +2039,11 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, &year, &month, &day, &hour, &minute, &second)) { /* we have a time, reformat it */ char timebuf[24]; - time_t secs = time(NULL); - msnprintf(timebuf, sizeof(timebuf), "%04d%02d%02d %02d:%02d:%02d GMT", year, month, day, hour, minute, second); /* now, convert this into a time() value: */ - data->info.filetime = curl_getdate(timebuf, &secs); + data->info.filetime = Curl_getdate_capped(timebuf); } #ifdef CURL_FTP_HTTPSTYLE_HEAD diff --git a/lib/http.c b/lib/http.c index e344663d0..885704560 100644 --- a/lib/http.c +++ b/lib/http.c @@ -3974,7 +3974,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, else if(checkprefix("Retry-After:", k->p)) { /* Retry-After = HTTP-date / delay-seconds */ curl_off_t retry_after = 0; /* zero for unknown or "now" */ - time_t date = curl_getdate(&k->p[12], NULL); + time_t date = Curl_getdate_capped(&k->p[12]); if(-1 == date) { /* not a date, try it as a decimal number */ (void)curlx_strtoofft(&k->p[12], NULL, 10, &retry_after); @@ -4032,9 +4032,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #endif else if(!k->http_bodyless && checkprefix("Last-Modified:", k->p) && (data->set.timecondition || data->set.get_filetime) ) { - time_t secs = time(NULL); - k->timeofdoc = curl_getdate(k->p + strlen("Last-Modified:"), - &secs); + k->timeofdoc = Curl_getdate_capped(k->p + strlen("Last-Modified:")); if(data->set.get_filetime) data->info.filetime = k->timeofdoc; } diff --git a/lib/parsedate.c b/lib/parsedate.c index f4b18d091..585d7ea40 100644 --- a/lib/parsedate.c +++ b/lib/parsedate.c @@ -587,6 +587,30 @@ time_t curl_getdate(const char *p, const time_t *now) return -1; } +/* Curl_getdate_capped() differs from curl_getdate() in that this will return + TIME_T_MAX in case the parsed time value was too big, instead of an + error. */ + +time_t Curl_getdate_capped(const char *p) +{ + time_t parsed = -1; + int rc = parsedate(p, &parsed); + + switch(rc) { + case PARSEDATE_OK: + if(parsed == -1) + /* avoid returning -1 for a working scenario */ + parsed++; + return parsed; + case PARSEDATE_LATER: + /* this returns the maximum time value */ + return parsed; + default: + return -1; /* everything else is fail */ + } + /* UNREACHABLE */ +} + /* * Curl_gmtime() is a gmtime() replacement for portability. Do not use the * gmtime_r() or gmtime() functions anywhere else but here. diff --git a/lib/parsedate.h b/lib/parsedate.h index 83d4c1f24..8c7ae94e4 100644 --- a/lib/parsedate.h +++ b/lib/parsedate.h @@ -27,4 +27,10 @@ extern const char * const Curl_month[12]; CURLcode Curl_gmtime(time_t intime, struct tm *store); +/* Curl_getdate_capped() differs from curl_getdate() in that this will return + TIME_T_MAX in case the parsed time value was too big, instead of an + error. */ + +time_t Curl_getdate_capped(const char *p); + #endif /* HEADER_CURL_PARSEDATE_H */ -- cgit v1.2.3