diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/curl_get_line.c | 2 | ||||
-rw-r--r-- | lib/easy.c | 4 | ||||
-rw-r--r-- | lib/easyoptions.c | 6 | ||||
-rw-r--r-- | lib/hsts.c | 109 | ||||
-rw-r--r-- | lib/hsts.h | 7 | ||||
-rw-r--r-- | lib/setopt.c | 14 | ||||
-rw-r--r-- | lib/transfer.c | 2 | ||||
-rw-r--r-- | lib/url.c | 1 | ||||
-rw-r--r-- | lib/urldata.h | 7 |
9 files changed, 139 insertions, 13 deletions
diff --git a/lib/curl_get_line.c b/lib/curl_get_line.c index aa524d8fe..135217c57 100644 --- a/lib/curl_get_line.c +++ b/lib/curl_get_line.c @@ -22,7 +22,7 @@ #include "curl_setup.h" -#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC)) || \ +#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \ defined(USE_HSTS) #include "curl_get_line.h" diff --git a/lib/easy.c b/lib/easy.c index ca1117a46..4dc094603 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -888,7 +888,9 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) if(!outcurl->hsts) goto fail; if(outcurl->set.str[STRING_HSTS]) - (void)Curl_hsts_load(outcurl->hsts, outcurl->set.str[STRING_HSTS]); + (void)Curl_hsts_loadfile(outcurl, + outcurl->hsts, outcurl->set.str[STRING_HSTS]); + (void)Curl_hsts_loadcb(outcurl, outcurl->hsts); } #endif /* Clone the resolver handle, if present, for the new handle */ diff --git a/lib/easyoptions.c b/lib/easyoptions.c index e5b9ffb70..8a4aaee26 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c @@ -116,6 +116,10 @@ struct curl_easyoption Curl_easyopts[] = { {"HEADERFUNCTION", CURLOPT_HEADERFUNCTION, CURLOT_FUNCTION, 0}, {"HEADEROPT", CURLOPT_HEADEROPT, CURLOT_VALUES, 0}, {"HSTS", CURLOPT_HSTS, CURLOT_STRING, 0}, + {"HSTSREADDATA", CURLOPT_HSTSREADDATA, CURLOT_CBPTR, 0}, + {"HSTSREADFUNCTION", CURLOPT_HSTSREADFUNCTION, CURLOT_FUNCTION, 0}, + {"HSTSWRITEDATA", CURLOPT_HSTSWRITEDATA, CURLOT_CBPTR, 0}, + {"HSTSWRITEFUNCTION", CURLOPT_HSTSWRITEFUNCTION, CURLOT_FUNCTION, 0}, {"HSTS_CTRL", CURLOPT_HSTS_CTRL, CURLOT_LONG, 0}, {"HTTP09_ALLOWED", CURLOPT_HTTP09_ALLOWED, CURLOT_LONG, 0}, {"HTTP200ALIASES", CURLOPT_HTTP200ALIASES, CURLOT_SLIST, 0}, @@ -344,6 +348,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return (CURLOPT_LASTENTRY != (300 + 1)); + return (CURLOPT_LASTENTRY != (304 + 1)); } #endif diff --git a/lib/hsts.c b/lib/hsts.c index 7eb3cda03..53b6d202b 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -262,6 +262,37 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname, } /* + * Send this HSTS entry to the write callback. + */ +static CURLcode hsts_push(struct Curl_easy *data, + struct curl_index *i, + struct stsentry *sts, + bool *stop) +{ + struct curl_hstsentry e; + CURLSTScode sc; + struct tm stamp; + CURLcode result; + + e.name = (char *)sts->host; + e.namelen = strlen(sts->host); + e.includeSubDomains = sts->includeSubDomains; + + result = Curl_gmtime(sts->expires, &stamp); + if(result) + return result; + + msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d", + stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, + stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + + sc = data->set.hsts_write(data, &e, i, + data->set.hsts_write_userp); + *stop = (sc != CURLSTS_OK); + return sc == CURLSTS_FAIL ? CURLE_BAD_FUNCTION_ARGUMENT : CURLE_OK; +} + +/* * Write this single hsts entry to a single output line */ static CURLcode hsts_out(struct stsentry *sts, FILE *fp) @@ -280,7 +311,7 @@ static CURLcode hsts_out(struct stsentry *sts, FILE *fp) /* - * Curl_https_save() writes the HSTS cache to a file. + * Curl_https_save() writes the HSTS cache to file and callback. */ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, const char *file) @@ -302,7 +333,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, if((h->flags & CURLHSTS_READONLYFILE) || !file || !file[0]) /* marked as read-only, no file or zero length file name */ - return CURLE_OK; + goto skipsave; if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) return CURLE_FAILED_INIT; @@ -333,6 +364,22 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, unlink(tempstore); } free(tempstore); + skipsave: + if(data->set.hsts_write) { + /* if there's a write callback */ + struct curl_index i; /* count */ + i.total = h->list.size; + i.index = 0; + for(e = h->list.head; e; e = n) { + struct stsentry *sts = e->ptr; + bool stop; + n = e->next; + result = hsts_push(data, &i, sts, &stop); + if(result || stop) + break; + i.index++; + } + } return result; } @@ -368,6 +415,46 @@ static CURLcode hsts_add(struct hsts *h, char *line) } /* + * Load HSTS data from callback. + * + */ +static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h) +{ + /* if the HSTS read callback is set, use it */ + if(data->set.hsts_read) { + CURLSTScode sc; + DEBUGASSERT(h); + do { + char buffer[257]; + struct curl_hstsentry e; + e.name = buffer; + e.namelen = sizeof(buffer)-1; + e.includeSubDomains = FALSE; /* default */ + e.expire[0] = 0; + e.name[0] = 0; /* just to make it clean */ + sc = data->set.hsts_read(data, &e, data->set.hsts_read_userp); + if(sc == CURLSTS_OK) { + time_t expires; + CURLcode result; + if(!e.name[0]) + /* bail out if no name was stored */ + return CURLE_BAD_FUNCTION_ARGUMENT; + if(e.expire[0]) + expires = Curl_getdate_capped(e.expire); + else + expires = TIME_T_MAX; /* the end of time */ + result = hsts_create(h, e.name, e.includeSubDomains, expires); + if(result) + return result; + } + else if(sc == CURLSTS_FAIL) + return CURLE_BAD_FUNCTION_ARGUMENT; + } while(sc == CURLSTS_OK); + } + return CURLE_OK; +} + +/* * Load the HSTS cache from the given file. The text based line-oriented file * format is documented here: * https://github.com/curl/curl/wiki/HSTS @@ -417,14 +504,22 @@ static CURLcode hsts_load(struct hsts *h, const char *file) } /* - * Curl_hsts_load() loads HSTS from file. + * Curl_hsts_loadfile() loads HSTS from file */ -CURLcode Curl_hsts_load(struct hsts *h, const char *file) +CURLcode Curl_hsts_loadfile(struct Curl_easy *data, + struct hsts *h, const char *file) { - CURLcode result; DEBUGASSERT(h); - result = hsts_load(h, file); - return result; + (void)data; + return hsts_load(h, file); +} + +/* + * Curl_hsts_loadcb() loads HSTS from callback + */ +CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h) +{ + return hsts_pull(data, h); } #endif /* CURL_DISABLE_HTTP || USE_HSTS */ diff --git a/lib/hsts.h b/lib/hsts.h index 60b3c2df7..0028d8ee4 100644 --- a/lib/hsts.h +++ b/lib/hsts.h @@ -53,8 +53,13 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname, bool subdomain); CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, const char *file); -CURLcode Curl_hsts_load(struct hsts *h, const char *file); +CURLcode Curl_hsts_loadfile(struct Curl_easy *data, + struct hsts *h, const char *file); +CURLcode Curl_hsts_loadcb(struct Curl_easy *data, + struct hsts *h); #else #define Curl_hsts_cleanup(x) +#define Curl_hsts_loadcb(x,y) +#define Curl_hsts_save(x,y,z) #endif /* CURL_DISABLE_HTTP || USE_HSTS */ #endif /* HEADER_CURL_HSTS_H */ diff --git a/lib/setopt.c b/lib/setopt.c index 4aa31bb39..7627557f5 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2841,6 +2841,18 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) #endif break; #ifdef USE_HSTS + case CURLOPT_HSTSREADFUNCTION: + data->set.hsts_read = va_arg(param, curl_hstsread_callback); + break; + case CURLOPT_HSTSREADDATA: + data->set.hsts_read_userp = va_arg(param, void *); + break; + case CURLOPT_HSTSWRITEFUNCTION: + data->set.hsts_write = va_arg(param, curl_hstswrite_callback); + break; + case CURLOPT_HSTSWRITEDATA: + data->set.hsts_write_userp = va_arg(param, void *); + break; case CURLOPT_HSTS: if(!data->hsts) { data->hsts = Curl_hsts_init(); @@ -2852,7 +2864,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) if(result) return result; if(argptr) - (void)Curl_hsts_load(data->hsts, argptr); + (void)Curl_hsts_loadfile(data, data->hsts, argptr); break; case CURLOPT_HSTS_CTRL: arg = va_arg(param, long); diff --git a/lib/transfer.c b/lib/transfer.c index 05a9e8ff6..267058d45 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -78,6 +78,7 @@ #include "mime.h" #include "strcase.h" #include "urlapi-int.h" +#include "hsts.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -1528,6 +1529,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) } #endif Curl_http2_init_state(&data->state); + Curl_hsts_loadcb(data, data->hsts); } return result; @@ -412,6 +412,7 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_flush_cookies(data, TRUE); Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); Curl_altsvc_cleanup(&data->asi); + Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]); Curl_hsts_cleanup(&data->hsts); #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) Curl_http_auth_cleanup_digest(data); diff --git a/lib/urldata.h b/lib/urldata.h index ea7060ec5..a0238c5aa 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1639,7 +1639,12 @@ struct UserDefined { curl_conv_callback convtonetwork; /* function to convert from UTF-8 encoding: */ curl_conv_callback convfromutf8; - +#ifdef USE_HSTS + curl_hstsread_callback hsts_read; + void *hsts_read_userp; + curl_hstswrite_callback hsts_write; + void *hsts_write_userp; +#endif void *progress_client; /* pointer to pass to the progress callback */ void *ioctl_client; /* pointer to pass to the ioctl callback */ long timeout; /* in milliseconds, 0 means no timeout */ |