|
|
|
@ -1171,7 +1171,7 @@ mod_auth_digest_misconfigured (request_st * const r, const struct http_auth_back
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
mod_auth_digest_parse_authorization (http_auth_digest_params_t * const dp, const buffer * const vb) |
|
|
|
|
mod_auth_digest_parse_authorization (http_auth_digest_params_t * const dp, const char *c) |
|
|
|
|
{ |
|
|
|
|
struct digest_kv { |
|
|
|
|
const char *key; |
|
|
|
@ -1180,53 +1180,57 @@ mod_auth_digest_parse_authorization (http_auth_digest_params_t * const dp, const
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const struct digest_kv dkv[] = { |
|
|
|
|
{ CONST_STR_LEN("username="), e_username }, |
|
|
|
|
{ CONST_STR_LEN("realm="), e_realm }, |
|
|
|
|
{ CONST_STR_LEN("nonce="), e_nonce }, |
|
|
|
|
{ CONST_STR_LEN("uri="), e_uri }, |
|
|
|
|
{ CONST_STR_LEN("algorithm="), e_algorithm }, |
|
|
|
|
{ CONST_STR_LEN("qop="), e_qop }, |
|
|
|
|
{ CONST_STR_LEN("cnonce="), e_cnonce }, |
|
|
|
|
{ CONST_STR_LEN("nc="), e_nc }, |
|
|
|
|
{ CONST_STR_LEN("response="), e_response }, |
|
|
|
|
{ CONST_STR_LEN("username"), e_username }, |
|
|
|
|
{ CONST_STR_LEN("realm"), e_realm }, |
|
|
|
|
{ CONST_STR_LEN("nonce"), e_nonce }, |
|
|
|
|
{ CONST_STR_LEN("uri"), e_uri }, |
|
|
|
|
{ CONST_STR_LEN("algorithm"), e_algorithm }, |
|
|
|
|
{ CONST_STR_LEN("qop"), e_qop }, |
|
|
|
|
{ CONST_STR_LEN("cnonce"), e_cnonce }, |
|
|
|
|
{ CONST_STR_LEN("nc"), e_nc }, |
|
|
|
|
{ CONST_STR_LEN("response"), e_response }, |
|
|
|
|
|
|
|
|
|
{ NULL, 0, http_auth_digest_params_sz } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/* parse credentials from client */ |
|
|
|
|
/* note: parsing does not recognize and handle BWS (bad whitespace) */ |
|
|
|
|
/* XXX: might find end of token and strncmp() only when len matches */ |
|
|
|
|
/* (caller already checked that vb->ptr begins with "Digest ") */ |
|
|
|
|
/* coverity[overflow_sink : FALSE] */ |
|
|
|
|
for (const char *c = vb->ptr+sizeof("Digest ")-1, *e; *c; c++) { |
|
|
|
|
/* (caller must pass c pointing to string after "Digest ") */ |
|
|
|
|
for (const char *e; *c; c++) { |
|
|
|
|
/* skip whitespaces */ |
|
|
|
|
while (*c == ' ' || *c == '\t') c++; |
|
|
|
|
while (*c == ' ' || *c == '\t' || *c == ',') ++c; |
|
|
|
|
if (!*c) break; |
|
|
|
|
for (e = c; *e!='=' && *e!=' ' && *e!='\t' && *e!='\0'; ++e) ; |
|
|
|
|
const uint32_t tlen = (uint32_t)(e - c); |
|
|
|
|
|
|
|
|
|
for (int i = 0; dkv[i].key; ++i) { |
|
|
|
|
if (0 != strncmp(c, dkv[i].key, dkv[i].klen)) |
|
|
|
|
if (tlen != dkv[i].klen || 0 != memcmp(c, dkv[i].key, tlen)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
if ((c[dkv[i].klen] == '"') && |
|
|
|
|
(NULL != (e = strchr(c + dkv[i].klen + 1, '"')))) { |
|
|
|
|
/* value with "..." */ |
|
|
|
|
c += dkv[i].klen + 1; |
|
|
|
|
dp->ptr[dkv[i].id] = c; |
|
|
|
|
dp->len[dkv[i].id] = (uint16_t)(e - c); |
|
|
|
|
c = e; |
|
|
|
|
c += tlen; |
|
|
|
|
/* detect and step over '='; ignore BWS (bad whitespace) */ |
|
|
|
|
if (__builtin_expect( (*c != '='), 0)) { |
|
|
|
|
while (*c == ' ' || *c == '\t') ++c; |
|
|
|
|
if (*c != '=') return; /*(including '\0')*/ |
|
|
|
|
} |
|
|
|
|
else if (NULL != (e = strchr(c + dkv[i].klen, ','))) { |
|
|
|
|
/* value without "...", terminated by ',' */ |
|
|
|
|
c += dkv[i].klen; |
|
|
|
|
dp->ptr[dkv[i].id] = c; |
|
|
|
|
dp->len[dkv[i].id] = (uint16_t)(e - c); |
|
|
|
|
c = e; |
|
|
|
|
do { ++c; } while (*c == ' ' || *c == '\t'); |
|
|
|
|
|
|
|
|
|
if (*c == '"') { |
|
|
|
|
for (e = ++c; *e != '"' && *e != '\0'; ++e) { |
|
|
|
|
if (*e == '\\' && *++e == '\0') return; |
|
|
|
|
} |
|
|
|
|
if (*e != '"') return; |
|
|
|
|
/* value with "..." *//*(XXX: quoted value not unescaped)*/ |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
/* value without "...", terminated by EOL */ |
|
|
|
|
c += dkv[i].klen; |
|
|
|
|
dp->ptr[dkv[i].id] = c; |
|
|
|
|
c += (dp->len[dkv[i].id] = (uint16_t)strlen(c)) - 1; |
|
|
|
|
for (e = c; *e!=',' && *e!=' ' && *e!='\t' && *e!='\0'; ++e) ; |
|
|
|
|
/* value without "..." */ |
|
|
|
|
} |
|
|
|
|
dp->ptr[dkv[i].id] = c; |
|
|
|
|
dp->len[dkv[i].id] = (uint16_t)(e - c); |
|
|
|
|
c = e; |
|
|
|
|
if (*c != ',') { |
|
|
|
|
/*(could more strictly check for linear whitespace)*/ |
|
|
|
|
c = strchr(c, ','); |
|
|
|
|
if (!c) return; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
@ -1396,7 +1400,7 @@ mod_auth_check_digest (request_st * const r, void *p_d, const struct http_auth_r
|
|
|
|
|
|
|
|
|
|
memset(&dp, 0, sizeof(dp) - sizeof(dp.rdigest)); |
|
|
|
|
|
|
|
|
|
mod_auth_digest_parse_authorization(&dp, vb); |
|
|
|
|
mod_auth_digest_parse_authorization(&dp, vb->ptr + sizeof("Digest ")-1); |
|
|
|
|
|
|
|
|
|
rc = mod_auth_digest_validate_params(r, require, &dp, &ai); |
|
|
|
|
if (__builtin_expect( (HANDLER_GO_ON != rc), 0)) |
|
|
|
|