[w3m-dev 04130] [w3m-dev 04131] [w3m-dev 04132] Multiple challeges in *-Authenticate header
* file.c (skip_auth_token): added (extract_auth_val): ',' is end of token (extract_auth_param): use skip_auth_token (AuthDigestCred): parse qop and calc cnonce correctly (findAuthentication): use skip_auth_token From: Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
2005-01-05 Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
|
||||
|
||||
* [w3m-dev 04130] [w3m-dev 04131] [w3m-dev 04132] Multiple challeges in *-Authenticate header
|
||||
* file.c (skip_auth_token): added
|
||||
(extract_auth_val): ',' is end of token
|
||||
(extract_auth_param): use skip_auth_token
|
||||
(AuthDigestCred): parse qop and calc cnonce correctly
|
||||
(findAuthentication): use skip_auth_token
|
||||
|
||||
2004-11-09 Fumitoshi UKAI <ukai@debian.or.jp>
|
||||
|
||||
* w3mimg/fb/fb_gdkpixbuf.c (fb_image_load):
|
||||
@@ -8612,4 +8621,4 @@ a * [w3m-dev 03276] compile error on EWS4800
|
||||
* release-0-2-1
|
||||
* import w3m-0.2.1
|
||||
|
||||
$Id: ChangeLog,v 1.942 2004/11/08 17:14:06 ukai Exp $
|
||||
$Id: ChangeLog,v 1.943 2005/01/04 15:51:03 ukai Exp $
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: file.c,v 1.236 2004/11/04 17:25:45 ukai Exp $ */
|
||||
/* $Id: file.c,v 1.237 2005/01/04 15:51:04 ukai Exp $ */
|
||||
#include "fm.h"
|
||||
#include <sys/types.h>
|
||||
#include "myctype.h"
|
||||
@@ -972,7 +972,59 @@ struct http_auth {
|
||||
HRequest *hr, FormList *request);
|
||||
};
|
||||
|
||||
#define TOKEN_PAT "[^][()<>@,;:\\\"/?={} \t\001-\037\177]*"
|
||||
enum {
|
||||
AUTHCHR_NUL,
|
||||
AUTHCHR_SEP,
|
||||
AUTHCHR_TOKEN,
|
||||
};
|
||||
|
||||
static int
|
||||
skip_auth_token(char **pp)
|
||||
{
|
||||
char *p;
|
||||
int first = AUTHCHR_NUL, typ;
|
||||
|
||||
for (p = *pp ;; ++p) {
|
||||
switch (*p) {
|
||||
case '\0':
|
||||
goto endoftoken;
|
||||
default:
|
||||
if ((unsigned char)*p > 037) {
|
||||
typ = AUTHCHR_TOKEN;
|
||||
break;
|
||||
}
|
||||
/* thru */
|
||||
case '\177':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '<':
|
||||
case '>':
|
||||
case '@':
|
||||
case ';':
|
||||
case ':':
|
||||
case '\\':
|
||||
case '"':
|
||||
case '/':
|
||||
case '?':
|
||||
case '=':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case ',':
|
||||
typ = AUTHCHR_SEP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
first = typ;
|
||||
else if (first != typ)
|
||||
break;
|
||||
}
|
||||
endoftoken:
|
||||
*pp = p;
|
||||
return first;
|
||||
}
|
||||
|
||||
static Str
|
||||
extract_auth_val(char **q)
|
||||
@@ -993,12 +1045,13 @@ extract_auth_val(char **q)
|
||||
}
|
||||
if (!quoted) {
|
||||
switch (*qq) {
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '<':
|
||||
case '>':
|
||||
case '@':
|
||||
case ',':
|
||||
case ';':
|
||||
case ':':
|
||||
case '\\':
|
||||
@@ -1009,6 +1062,7 @@ extract_auth_val(char **q)
|
||||
case ' ':
|
||||
case '\t':
|
||||
qq++;
|
||||
case ',':
|
||||
goto end_token;
|
||||
default:
|
||||
if (*qq <= 037 || *qq == 0177) {
|
||||
@@ -1022,11 +1076,6 @@ extract_auth_val(char **q)
|
||||
Strcat_char(val, *qq++);
|
||||
}
|
||||
end_token:
|
||||
if (*qq != '\0') {
|
||||
SKIP_BLANKS(qq);
|
||||
if (*qq == ',')
|
||||
qq++;
|
||||
}
|
||||
*q = (char *)qq;
|
||||
return val;
|
||||
}
|
||||
@@ -1058,10 +1107,7 @@ static char *
|
||||
extract_auth_param(char *q, struct auth_param *auth)
|
||||
{
|
||||
struct auth_param *ap;
|
||||
char *q0;
|
||||
Regex re_token;
|
||||
|
||||
newRegex(TOKEN_PAT, FALSE, &re_token, NULL);
|
||||
char *p;
|
||||
|
||||
for (ap = auth; ap->name != NULL; ap++) {
|
||||
ap->val = NULL;
|
||||
@@ -1070,26 +1116,41 @@ extract_auth_param(char *q, struct auth_param *auth)
|
||||
while (*q != '\0') {
|
||||
SKIP_BLANKS(q);
|
||||
for (ap = auth; ap->name != NULL; ap++) {
|
||||
if (strncasecmp(q, ap->name, strlen(ap->name)) == 0) {
|
||||
q += strlen(ap->name);
|
||||
SKIP_BLANKS(q);
|
||||
if (*q != '=')
|
||||
size_t len;
|
||||
|
||||
len = strlen(ap->name);
|
||||
if (strncasecmp(q, ap->name, len) == 0 &&
|
||||
(IS_SPACE(q[len]) || q[len] == '=')) {
|
||||
p = q + len;
|
||||
SKIP_BLANKS(p);
|
||||
if (*p != '=')
|
||||
return q;
|
||||
q++;
|
||||
q = p + 1;
|
||||
ap->val = extract_auth_val(&q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ap->name == NULL) {
|
||||
/* skip unknown param */
|
||||
if (RegexMatch(&re_token, q, -1, TRUE) == 0)
|
||||
return q;
|
||||
MatchedPosition(&re_token, &q0, &q);
|
||||
int token_type;
|
||||
p = q;
|
||||
if ((token_type = skip_auth_token(&q)) == AUTHCHR_TOKEN &&
|
||||
(IS_SPACE(*q) || *q == '=')) {
|
||||
SKIP_BLANKS(q);
|
||||
if (*q != '=')
|
||||
return p;
|
||||
q++;
|
||||
extract_auth_val(&q);
|
||||
}
|
||||
else
|
||||
return p;
|
||||
}
|
||||
if (*q != '\0') {
|
||||
SKIP_BLANKS(q);
|
||||
if (*q != '=')
|
||||
return q;
|
||||
q++;
|
||||
extract_auth_val(&q);
|
||||
if (*q == ',')
|
||||
q++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
return q;
|
||||
@@ -1157,6 +1218,12 @@ digest_hex(char *p)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
enum {
|
||||
QOP_NONE,
|
||||
QOP_AUTH,
|
||||
QOP_AUTH_INT,
|
||||
};
|
||||
|
||||
static Str
|
||||
AuthDigestCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu,
|
||||
HRequest *hr, FormList *request)
|
||||
@@ -1168,11 +1235,50 @@ AuthDigestCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu,
|
||||
|
||||
Str algorithm = qstr_unquote(get_auth_param(ha->param, "algorithm"));
|
||||
Str nonce = qstr_unquote(get_auth_param(ha->param, "nonce"));
|
||||
Str cnonce = qstr_unquote(get_auth_param(ha->param, "cnonce"));
|
||||
Str cnonce /* = qstr_unquote(get_auth_param(ha->param, "cnonce")) */;
|
||||
/* cnonce is what client should generate. */
|
||||
Str qop = qstr_unquote(get_auth_param(ha->param, "qop"));
|
||||
|
||||
if (cnonce == NULL)
|
||||
cnonce = Strnew_charp("cnonce"); /* XXX */
|
||||
static union {
|
||||
int r[4];
|
||||
char s[sizeof(int) * 4];
|
||||
} cnonce_seed;
|
||||
int qop_i = QOP_NONE;
|
||||
|
||||
cnonce_seed.r[0] = rand();
|
||||
cnonce_seed.r[1] = rand();
|
||||
cnonce_seed.r[2] = rand();
|
||||
MD5(cnonce_seed.s, sizeof(cnonce_seed.s), md5);
|
||||
cnonce = digest_hex(md5);
|
||||
cnonce_seed.r[3]++;
|
||||
|
||||
if (qop) {
|
||||
char *p;
|
||||
size_t i;
|
||||
|
||||
p = qop->ptr;
|
||||
SKIP_BLANKS(p);
|
||||
|
||||
for (;;) {
|
||||
if ((i = strcspn(p, " \t,")) > 0) {
|
||||
if (i == sizeof("auth-int") - sizeof("") && !strncasecmp(p, "auth-int", i)) {
|
||||
if (qop_i < QOP_AUTH_INT)
|
||||
qop_i = QOP_AUTH_INT;
|
||||
}
|
||||
else if (i == sizeof("auth") - sizeof("") && !strncasecmp(p, "auth", i)) {
|
||||
if (qop_i < QOP_AUTH)
|
||||
qop_i = QOP_AUTH;
|
||||
}
|
||||
}
|
||||
|
||||
if (p[i]) {
|
||||
p += i + 1;
|
||||
SKIP_BLANKS(p);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* A1 = unq(username-value) ":" unq(realm-value) ":" passwd */
|
||||
tmp = Strnew_m_charp(uname->ptr, ":",
|
||||
@@ -1204,28 +1310,34 @@ AuthDigestCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu,
|
||||
|
||||
/* A2 = Method ":" digest-uri-value */
|
||||
tmp = Strnew_m_charp(HTTPrequestMethod(hr)->ptr, ":", uri->ptr, NULL);
|
||||
if (qop && (strcasecmp(qop->ptr, "auth-int") == 0)) {
|
||||
if (qop_i == QOP_AUTH_INT) {
|
||||
/* A2 = Method ":" digest-uri-value ":" H(entity-body) */
|
||||
Str ebody = Strnew();
|
||||
if (request && request->body) {
|
||||
FILE *fp = fopen(request->body, "r");
|
||||
if (fp != NULL) {
|
||||
int c;
|
||||
while ((c = fgetc(fp)) != EOF)
|
||||
Strcat_char(ebody, c);
|
||||
fclose(fp);
|
||||
if (request->method == FORM_METHOD_POST && request->enctype == FORM_ENCTYPE_MULTIPART) {
|
||||
FILE *fp = fopen(request->body, "r");
|
||||
if (fp != NULL) {
|
||||
Str ebody;
|
||||
ebody = Strfgetall(fp);
|
||||
MD5(ebody->ptr, strlen(ebody->ptr), md5);
|
||||
}
|
||||
else {
|
||||
MD5("", 0, md5);
|
||||
}
|
||||
}
|
||||
else {
|
||||
MD5(request->body, request->length, md5);
|
||||
}
|
||||
}
|
||||
MD5(ebody->ptr, strlen(ebody->ptr), md5);
|
||||
ebody = digest_hex(md5);
|
||||
Strcat_m_charp(tmp, ":", ebody->ptr, NULL);
|
||||
else {
|
||||
MD5("", 0, md5);
|
||||
}
|
||||
Strcat_char(tmp, ':');
|
||||
Strcat(tmp, digest_hex(md5));
|
||||
}
|
||||
MD5(tmp->ptr, strlen(tmp->ptr), md5);
|
||||
a2buf = digest_hex(md5);
|
||||
|
||||
if (qop &&
|
||||
(strcasecmp(qop->ptr, "auth") == 0
|
||||
|| strcasecmp(qop->ptr, "auth-int") == 0)) {
|
||||
if (qop_i >= QOP_AUTH) {
|
||||
/* request-digest = <"> < KD ( H(A1), unq(nonce-value)
|
||||
* ":" nc-value
|
||||
* ":" unq(cnonce-value)
|
||||
@@ -1238,7 +1350,7 @@ AuthDigestCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu,
|
||||
tmp = Strnew_m_charp(a1buf->ptr, ":", qstr_unquote(nonce)->ptr,
|
||||
":", nc,
|
||||
":", qstr_unquote(cnonce)->ptr,
|
||||
":", qstr_unquote(qop)->ptr,
|
||||
":", qop_i == QOP_AUTH ? "auth" : "auth-int",
|
||||
":", a2buf->ptr, NULL);
|
||||
MD5(tmp->ptr, strlen(tmp->ptr), md5);
|
||||
rd = digest_hex(md5);
|
||||
@@ -1279,10 +1391,13 @@ AuthDigestCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu,
|
||||
if ((s = get_auth_param(ha->param, "opaque")) != NULL)
|
||||
Strcat_m_charp(tmp, ", opaque=", s->ptr, NULL);
|
||||
|
||||
if (qop) {
|
||||
if (qop_i >= QOP_AUTH) {
|
||||
Strcat_m_charp(tmp, ", qop=",
|
||||
get_auth_param(ha->param, "qop")->ptr, NULL);
|
||||
qop_i == QOP_AUTH ? "auth" : "auth-int",
|
||||
NULL);
|
||||
/* XXX how to count? */
|
||||
/* Since nonce is unique up to each *-Authenticate and w3m does not re-use *-Authenticate: headers,
|
||||
nonce-count should be always "00000001". */
|
||||
Strcat_m_charp(tmp, ", nc=", nc, NULL);
|
||||
}
|
||||
|
||||
@@ -1344,12 +1459,9 @@ static struct http_auth *
|
||||
findAuthentication(struct http_auth *hauth, Buffer *buf, char *auth_field)
|
||||
{
|
||||
struct http_auth *ha;
|
||||
int len = strlen(auth_field);
|
||||
int len = strlen(auth_field), slen;
|
||||
TextListItem *i;
|
||||
char *p0, *p;
|
||||
Regex re_token;
|
||||
|
||||
newRegex(TOKEN_PAT, FALSE, &re_token, NULL);
|
||||
|
||||
bzero(hauth, sizeof(struct http_auth));
|
||||
for (i = buf->document_header->first; i != NULL; i = i->next) {
|
||||
@@ -1358,29 +1470,30 @@ findAuthentication(struct http_auth *hauth, Buffer *buf, char *auth_field)
|
||||
SKIP_BLANKS(p);
|
||||
p0 = p;
|
||||
for (ha = &www_auth[0]; ha->scheme != NULL; ha++) {
|
||||
if (strncasecmp(p, ha->scheme, strlen(ha->scheme)) == 0) {
|
||||
slen = strlen(ha->scheme);
|
||||
if (strncasecmp(p, ha->scheme, slen) == 0) {
|
||||
p += slen;
|
||||
SKIP_BLANKS(p);
|
||||
if (hauth->pri < ha->pri) {
|
||||
*hauth = *ha;
|
||||
p += strlen(ha->scheme);
|
||||
SKIP_BLANKS(p);
|
||||
p = extract_auth_param(p, hauth->param);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
/* weak auth */
|
||||
p += strlen(ha->scheme);
|
||||
SKIP_BLANKS(p);
|
||||
p = extract_auth_param(p, none_auth_param);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p0 == p) {
|
||||
/* all unknown auth failed */
|
||||
if (RegexMatch(&re_token, p0, -1, TRUE) == 0)
|
||||
return NULL;
|
||||
MatchedPosition(&re_token, &p0, &p);
|
||||
SKIP_BLANKS(p);
|
||||
p = extract_auth_param(p, none_auth_param);
|
||||
int token_type;
|
||||
if ((token_type = skip_auth_token(&p)) == AUTHCHR_TOKEN && IS_SPACE(*p)) {
|
||||
SKIP_BLANKS(p);
|
||||
p = extract_auth_param(p, none_auth_param);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1893,6 +2006,27 @@ loadGeneralFile(char *path, ParsedURL *volatile current, char *referer,
|
||||
status = HTST_NORMAL;
|
||||
goto load_doc;
|
||||
}
|
||||
#ifdef AUTH_DEBUG
|
||||
if ((p = checkHeader(t_buf, "WWW-Authenticate:")) != NULL) {
|
||||
/* Authentication needed */
|
||||
struct http_auth hauth;
|
||||
if (findAuthentication(&hauth, t_buf, "WWW-Authenticate:") != NULL
|
||||
&& (realm = get_auth_param(hauth.param, "realm")) != NULL) {
|
||||
auth_pu = &pu;
|
||||
getAuthCookie(&hauth, "Authorization:", extra_header,
|
||||
auth_pu, &hr, request, &uname, &pwd);
|
||||
if (uname == NULL) {
|
||||
/* abort */
|
||||
TRAP_OFF;
|
||||
goto page_loaded;
|
||||
}
|
||||
UFclose(&f);
|
||||
add_auth_cookie_flag = 1;
|
||||
status = HTST_NORMAL;
|
||||
goto load_doc;
|
||||
}
|
||||
}
|
||||
#endif /* defined(AUTH_DEBUG) */
|
||||
t = checkContentType(t_buf);
|
||||
if (t == NULL)
|
||||
t = "text/plain";
|
||||
|
||||
Reference in New Issue
Block a user