mirror of
https://github.com/curl/curl.git
synced 2026-08-25 14:43:33 +03:00
hsts: make the HSTS read callback handle name dupes
Now the logic for handling name duplicates and picking the longest expiry and strictest subdomain is the same for the callback as for when reading from file. Also strip trailing dots from the hostname added by the callback. A minor side-effect is that the hostname provided by the callback can now enable subdomains by starting the name with a dot, but we discourage using such hostnames in documentation. Amended test 1915 to verify. Closes #21201
This commit is contained in:
parent
dc20c91e04
commit
e65ba1bd34
4 changed files with 99 additions and 82 deletions
132
lib/hsts.c
132
lib/hsts.c
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
#define MAX_HSTS_LINE 4095
|
||||
#define MAX_HSTS_HOSTLEN 2048
|
||||
#define MAX_HSTS_DATELEN 256
|
||||
#define MAX_HSTS_DATELEN 17
|
||||
#define UNLIMITED "unlimited"
|
||||
|
||||
#if defined(DEBUGBUILD) || defined(UNITTESTS)
|
||||
|
|
@ -399,6 +399,61 @@ skipsave:
|
|||
return result;
|
||||
}
|
||||
|
||||
/* only returns SERIOUS errors */
|
||||
static CURLcode hsts_add_host_expire(struct hsts *h,
|
||||
const char *host, size_t hostlen,
|
||||
const char *expire, size_t explen,
|
||||
bool subdomain) /* default */
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct stsentry *e;
|
||||
char dbuf[MAX_HSTS_DATELEN + 1];
|
||||
time_t expires = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
/* The date parser works on a null-terminated string. */
|
||||
if(explen > MAX_HSTS_DATELEN)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
memcpy(dbuf, expire, explen);
|
||||
dbuf[explen] = 0;
|
||||
|
||||
if(!strcmp(dbuf, UNLIMITED))
|
||||
expires = TIME_T_MAX;
|
||||
else
|
||||
Curl_getdate_capped(dbuf, &expires);
|
||||
|
||||
if(expires <= now)
|
||||
/* this entry already expired */
|
||||
return CURLE_OK;
|
||||
|
||||
if(host[0] == '.') {
|
||||
host++;
|
||||
hostlen--;
|
||||
subdomain = TRUE;
|
||||
}
|
||||
if(hostlen && (host[hostlen - 1] == '.'))
|
||||
/* strip off any trailing dot */
|
||||
hostlen--;
|
||||
|
||||
if(hostlen) {
|
||||
/* only add it if not already present */
|
||||
e = Curl_hsts(h, host, hostlen, subdomain);
|
||||
if(!e)
|
||||
result = hsts_create(h, host, hostlen, subdomain, expires);
|
||||
/* 'host' is not necessarily null terminated */
|
||||
else if((hostlen == strlen(e->host) &&
|
||||
curl_strnequal(host, e->host, hostlen))) {
|
||||
/* the same hostname, use the largest expire time and keep the strictest
|
||||
subdomain policy */
|
||||
if(expires > e->expires)
|
||||
e->expires = expires;
|
||||
if(subdomain)
|
||||
e->includeSubDomains = TRUE;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* only returns SERIOUS errors */
|
||||
static CURLcode hsts_add(struct hsts *h, const char *line)
|
||||
{
|
||||
|
|
@ -415,54 +470,9 @@ static CURLcode hsts_add(struct hsts *h, const char *line)
|
|||
curlx_str_newline(&line))
|
||||
;
|
||||
else {
|
||||
CURLcode result = CURLE_OK;
|
||||
bool subdomain = FALSE;
|
||||
struct stsentry *e;
|
||||
char dbuf[MAX_HSTS_DATELEN + 1];
|
||||
time_t expires = 0;
|
||||
const char *hp = curlx_str(&host);
|
||||
size_t hlen;
|
||||
time_t now = time(NULL);
|
||||
|
||||
/* The date parser works on a null-terminated string. The maximum length
|
||||
is upheld by curlx_str_quotedword(). */
|
||||
memcpy(dbuf, curlx_str(&date), curlx_strlen(&date));
|
||||
dbuf[curlx_strlen(&date)] = 0;
|
||||
|
||||
if(!strcmp(dbuf, UNLIMITED))
|
||||
expires = TIME_T_MAX;
|
||||
else
|
||||
Curl_getdate_capped(dbuf, &expires);
|
||||
|
||||
if(expires <= now)
|
||||
/* this entry already expired */
|
||||
return CURLE_OK;
|
||||
|
||||
if(hp[0] == '.') {
|
||||
curlx_str_nudge(&host, 1);
|
||||
hp = curlx_str(&host);
|
||||
subdomain = TRUE;
|
||||
}
|
||||
hlen = curlx_strlen(&host);
|
||||
if(hlen && (hp[hlen - 1] == '.'))
|
||||
/* strip off any trailing dot */
|
||||
curlx_str_trim(&host, 1);
|
||||
|
||||
/* only add it if not already present */
|
||||
e = Curl_hsts(h, curlx_str(&host), curlx_strlen(&host), subdomain);
|
||||
if(!e)
|
||||
result = hsts_create(h, curlx_str(&host), curlx_strlen(&host),
|
||||
subdomain, expires);
|
||||
else if(curlx_str_casecompare(&host, e->host)) {
|
||||
/* the same hostname, use the largest expire time and keep the
|
||||
strictest subdomain policy */
|
||||
if(expires > e->expires)
|
||||
e->expires = expires;
|
||||
if(subdomain)
|
||||
e->includeSubDomains = TRUE;
|
||||
}
|
||||
if(result)
|
||||
return result;
|
||||
return hsts_add_host_expire(h, curlx_str(&host), curlx_strlen(&host),
|
||||
curlx_str(&date), curlx_strlen(&date),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
|
|
@ -485,23 +495,23 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
|
|||
e.namelen = sizeof(buffer) - 1;
|
||||
e.includeSubDomains = FALSE; /* default */
|
||||
e.expire[0] = 0;
|
||||
e.expire[MAX_HSTS_DATELEN] = 0;
|
||||
e.name[0] = 0; /* to make it clean */
|
||||
e.name[MAX_HSTS_HOSTLEN] = 0;
|
||||
sc = data->set.hsts_read(data, &e, data->set.hsts_read_userp);
|
||||
if(sc == CURLSTS_OK) {
|
||||
time_t expires = 0;
|
||||
CURLcode result;
|
||||
DEBUGASSERT(e.name[0]);
|
||||
if(!e.name[0])
|
||||
/* bail out if no name was stored */
|
||||
const char *date = e.expire;
|
||||
if(!e.name[0] || e.expire[MAX_HSTS_DATELEN] ||
|
||||
e.name[MAX_HSTS_HOSTLEN])
|
||||
/* bail out if no name was stored or if a null terminator is gone */
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
if(e.expire[0])
|
||||
Curl_getdate_capped(e.expire, &expires);
|
||||
else
|
||||
expires = TIME_T_MAX; /* the end of time */
|
||||
result = hsts_create(h, e.name, strlen(e.name),
|
||||
/* bitfield to bool conversion: */
|
||||
e.includeSubDomains ? TRUE : FALSE,
|
||||
expires);
|
||||
if(!date[0])
|
||||
date = UNLIMITED;
|
||||
result = hsts_add_host_expire(h, e.name, strlen(e.name),
|
||||
date, strlen(date),
|
||||
/* bitfield to bool conversion: */
|
||||
e.includeSubDomains ? TRUE : FALSE);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue