diff options
author | Justus Winter, corvid <devnull@localhost> | 2011-09-29 16:21:28 +0000 |
---|---|---|
committer | Justus Winter, corvid <devnull@localhost> | 2011-09-29 16:21:28 +0000 |
commit | 8dac04451d23627af7be3b50ca13a9d882ac4ad6 (patch) | |
tree | b2c946ec1101a8ca8da6cfd74de950b562c9c6e9 /src | |
parent | c4f7c7f2e6b9d028033040a83a39cfc3decdedd6 (diff) |
rest of digest authentication
Justus contributed the original patch in April 2009.
I read RFCs, fixed bugs, restructured, tested.
Diffstat (limited to 'src')
-rw-r--r-- | src/IO/http.c | 6 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/auth.c | 536 | ||||
-rw-r--r-- | src/auth.h | 23 |
4 files changed, 370 insertions, 199 deletions
diff --git a/src/IO/http.c b/src/IO/http.c index 44befe53..a9db1668 100644 --- a/src/IO/http.c +++ b/src/IO/http.c @@ -276,8 +276,7 @@ static Dstr *Http_make_content_type(const DilloUrl *url) Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester, bool_t use_proxy) { - const char *auth; - char *ptr, *cookies, *referer; + char *ptr, *cookies, *referer, *auth; Dstr *query = dStr_new(""), *request_uri = dStr_new(""), *proxy_auth = dStr_new(""); @@ -300,7 +299,7 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester, } cookies = a_Cookies_get_query(url, requester); - auth = a_Auth_get_auth_str(url); + auth = a_Auth_get_auth_str(url, request_uri->str); referer = Http_get_referer(url); if (URL_FLAGS(url) & URL_Post) { Dstr *content_type = Http_make_content_type(url); @@ -352,6 +351,7 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester, } dFree(referer); dFree(cookies); + dFree(auth); dStr_free(request_uri, TRUE); dStr_free(proxy_auth, TRUE); diff --git a/src/Makefile.am b/src/Makefile.am index 9de7eed5..5e887d2c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -35,6 +35,10 @@ dillo_SOURCES = \ cookies.h \ auth.c \ auth.h \ + md5.c \ + md5.h \ + digest.c \ + digest.h \ colors.c \ colors.h \ binaryconst.h \ @@ -2,6 +2,7 @@ * File: auth.c * * Copyright 2008 Jeremy Henty <onepoint@starurchin.org> + * Copyright 2009 Justus Winter <4winter@informatik.uni-hamburg.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,28 +21,29 @@ #include "msg.h" #include "misc.h" #include "dialog.hh" +#include "digest.h" #include "../dlib/dlib.h" - typedef struct { int ok; + enum AuthParseHTTPAuthType_t type; const char *realm; + const char *nonce; + const char *opaque; + int stale; + enum AuthParseDigestAlgorithm_t algorithm; + const char *domain; + enum AuthParseDigestQOP_t qop; } AuthParse_t; typedef struct { - char *name; - Dlist *paths; /* stripped of any trailing '/', so the root path is "" */ - char *authorization; /* the authorization request header */ -} AuthRealm_t; - -typedef struct { char *scheme; char *authority; Dlist *realms; } AuthHost_t; typedef struct { - const char *realm_name; + const AuthParse_t *auth_parse; const DilloUrl *url; } AuthDialogData_t; @@ -62,7 +64,14 @@ static AuthParse_t *Auth_parse_new() { AuthParse_t *auth_parse = dNew(AuthParse_t, 1); auth_parse->ok = 0; + auth_parse->type = TYPENOTSET; auth_parse->realm = NULL; + auth_parse->nonce = NULL; + auth_parse->opaque = NULL; + auth_parse->stale = 0; + auth_parse->algorithm = ALGORITHMNOTSET; + auth_parse->domain = NULL; + auth_parse->qop = QOPNOTSET; return auth_parse; } @@ -70,6 +79,9 @@ static void Auth_parse_free(AuthParse_t *auth_parse) { if (auth_parse) { dFree((void *)auth_parse->realm); + dFree((void *)auth_parse->nonce); + dFree((void *)auth_parse->opaque); + dFree((void *)auth_parse->domain); dFree(auth_parse); } } @@ -96,187 +108,246 @@ static int Auth_is_token_char(char c) } /* - * Unquote the content of a quoted string. + * Unquote the content of a (potentially) quoted string. * Return: newly allocated unquoted content. * * Arguments: - * quoted: pointer to the first char *after* the initial double quote. - * size: the number of chars in the result, *not* including a final '\0'. + * valuep: pointer to a pointer to the first char. * * Preconditions: - * quoted points to a correctly quoted and escaped string. - * size is the number of characters in the quoted string, *after* - * removing escape characters. + * *valuep points to a correctly quoted and escaped string. + * + * Postconditions: + * *valuep points to the first not processed char. * */ -static const char *Auth_unquote_value(const char *quoted, int size) +static Dstr *Auth_unquote_value(char **valuep) { - char c, *value, *value_ptr; - value_ptr = value = dNew(char, size + 1); - while ((c = *quoted++) != '"') - *value_ptr++ = (c == '\\') ? *quoted++ : c; - *value_ptr = '\0'; - return value; + char c, quoted; + char *value = *valuep; + Dstr *result; + + while (*value == ' ' || *value == '\t') + value++; + + if ((quoted = *value == '"')) + value++; + + result = dStr_new(NULL); + while ((c = *value) && + (( quoted && c != '"') || + (!quoted && Auth_is_token_char(c)))) { + dStr_append_c(result, (c == '\\' && value[1]) ? *++value : c); + value++; + } + + if (quoted && *value == '\"') + value++; + *valuep = value; + return result; } +typedef int (Auth_parse_token_value_callback_t)(AuthParse_t *auth_parse, + char *token, + const char *value); + + /* - * Parse a quoted string. Save the result as the auth realm if required. + * Parse authentication challenge into token-value pairs + * and feed them into the callback function. + * + * The parsing is aborted should the callback function return 0. + * * Return: 1 if the parse succeeds, 0 otherwise. */ -static int Auth_parse_quoted_string(AuthParse_t *auth_parse, int set_realm, - char **auth) +static int Auth_parse_token_value(AuthParse_t *auth_parse, char **auth, + Auth_parse_token_value_callback_t *callback) { - char *value; - int size; - - /* parse the '"' */ - switch (*(*auth)++) { - case '"': - break; - case '\0': - case ',': - MSG("auth.c: missing Basic auth token value after '='\n"); - return 0; - break; - default: - MSG("auth.c: garbage in Basic auth after '='\n"); - return 0; - break; - } + char keep_going, expect_quoted; + char *token, *beyond_token; + Dstr *value; + size_t *token_size; - /* parse the rest */ - value = *auth; - size = 0; - while (1) { + while (**auth) { + _MSG("Auth_parse_token_value: remaining: %s\n", *auth); + + /* parse a token */ + token = *auth; + + token_size = 0; + while (Auth_is_token_char(**auth)) { + (*auth)++; + token_size++; + } + if (token_size == 0) { + MSG("Auth_parse_token_value: missing auth token\n"); + return 0; + } + beyond_token = *auth; + /* skip linear whitespace characters */ + while (**auth == ' ' || **auth == '\t') + (*auth)++; + + /* parse the '=' */ switch (*(*auth)++) { - case '"': - if (set_realm) { - dFree((void *)auth_parse->realm); - auth_parse->realm = Auth_unquote_value(value, size); - auth_parse->ok = 1; - } - return 1; + case '=': + *beyond_token = '\0'; break; case '\0': - MSG("auth.c: auth string ended inside quoted string value\n"); + case ',': + MSG("Auth_parse_token_value: missing auth token value\n"); return 0; break; - case '\\': - /* end of string? */ - if (!*(*auth)++) { - MSG("auth.c: " - "auth string ended inside quoted string value " - "immediately after \\\n"); - return 0; - } - /* fall through to the next case */ default: - size++; + MSG("Auth_parse_token_value: garbage after auth token\n"); + return 0; break; } - } -} -/* - * Parse a token-value pair. - * Return: 1 if the parse succeeds, 0 otherwise. - */ -static int Auth_parse_token_value(AuthParse_t *auth_parse, char **auth) -{ - char *token; - int token_size, set_realm; - static const char realm_token[] = "realm"; - - /* parse a token */ - token = *auth; - token_size = 0; - while (Auth_is_token_char(**auth)) { - (*auth)++; - token_size++; - } - if (token_size == 0) { - MSG("auth.c: Auth_parse_token_value: " - "missing Basic auth token\n"); - return 0; - } + value = Auth_unquote_value(auth); + expect_quoted = !(strcmp(token, "stale") == 0 || + strcmp(token, "algorithm") == 0); - /* skip space characters */ - while (**auth == ' ') - (*auth)++; - - /* parse the '=' */ - switch (*(*auth)++) { - case '=': - break; - case '\0': - case ',': - MSG("auth.c: Auth_parse_token_value: " - "missing Basic auth token value\n"); - return 0; - break; - default: - MSG("auth.c: Auth_parse_token_value: " - "garbage after Basic auth token\n"); - return 0; - break; - } + if (((*auth)[-1] == '"') != expect_quoted) + MSG_WARN("Auth_parse_token_value: " + "Values for key %s should%s be quoted.\n", + token, expect_quoted ? "" : " not"); - /* skip space characters */ - while (**auth == ' ') - (*auth)++; + keep_going = callback(auth_parse, token, value->str); + dStr_free(value, 1); + if (!keep_going) + break; - /* is this value the realm? */ - set_realm = - auth_parse->realm == NULL && - dStrncasecmp(realm_token,token,token_size) == 0 && - strlen(realm_token) == (size_t)token_size; + /* skip ' ' and ',' */ + while ((**auth == ' ') || (**auth == ',')) + (*auth)++; + } + return 1; +} - return Auth_parse_quoted_string(auth_parse, set_realm, auth); +static int Auth_parse_basic_challenge_cb(AuthParse_t *auth_parse, char *token, + const char *value) +{ + if (dStrcasecmp("realm", token) == 0) { + if (!auth_parse->realm) + auth_parse->realm = strdup(value); + return 0; /* end parsing */ + } else + MSG("Auth_parse_basic_challenge_cb: Ignoring unknown parameter: %s = " + "'%s'\n", token, value); + return 1; } -static void Auth_parse_auth_basic(AuthParse_t *auth_parse, char **auth) +static int Auth_parse_digest_challenge_cb(AuthParse_t *auth_parse, char *token, + const char *value) { - int token_value_pairs_found; + const char *const fn = "Auth_parse_digest_challenge_cb"; + + if (!dStrcasecmp("realm", token) && !auth_parse->realm) + auth_parse->realm = strdup(value); + else if (!strcmp("domain", token) && !auth_parse->domain) + auth_parse->domain = strdup(value); + else if (!strcmp("nonce", token) && !auth_parse->nonce) + auth_parse->nonce = strdup(value); + else if (!strcmp("opaque", token) && !auth_parse->opaque) + auth_parse->opaque = strdup(value); + else if (strcmp("stale", token) == 0) { + if (dStrcasecmp("true", value) == 0) + auth_parse->stale = 1; + else if (dStrcasecmp("false", value) == 0) + auth_parse->stale = 0; + else { + MSG("%s: Invalid stale value: %s\n", fn, value); + return 0; + } + } else if (strcmp("algorithm", token) == 0) { + if (strcmp("MD5", value) == 0) + auth_parse->algorithm = MD5; + else if (strcmp("MD5-sess", value) == 0) { + /* auth_parse->algorithm = MD5SESS; */ + MSG("%s: MD5-sess algorithm disabled (not tested because 'not " + "correctly implemented yet' in Apache 2.2)\n", fn); + return 0; + } else { + MSG("%s: Unknown algorithm: %s\n", fn, value); + return 0; + } + } else if (strcmp("qop", token) == 0) { + while (*value) { + int len = strcspn(value, ", \t"); + if (len == 4 && strncmp("auth", value, 4) == 0) { + auth_parse->qop = AUTH; + break; + } + if (len == 8 && strncmp("auth-int", value, 8) == 0) { + /* auth_parse->qop = AUTHINT; */ + /* Keep searching; maybe we'll find an "auth" yet. */ + MSG("%s: auth-int qop disabled (not tested because 'not " + "implemented yet' in Apache 2.2)\n", fn); + } else { + MSG("%s: Unknown qop value in %s\n", fn, value); + } + value += len; + while (*value == ' ' || *value == '\t') + value++; + if (*value == ',') + value++; + while (*value == ' ' || *value == '\t') + value++; + } + } else { + MSG("%s: Ignoring unknown parameter: %s = '%s'\n", fn, token, value); + } + return 1; +} +static void Auth_parse_challenge_args(AuthParse_t *auth_parse, + char **challenge, + Auth_parse_token_value_callback_t *cb) +{ /* parse comma-separated token-value pairs */ - token_value_pairs_found = 0; while (1) { /* skip space and comma characters */ - while (**auth == ' ' || **auth == ',') - (*auth)++; + while (**challenge == ' ' || **challenge == ',') + (*challenge)++; /* end of string? */ - if (!**auth) + if (!**challenge) break; /* parse token-value pair */ - if (!Auth_parse_token_value(auth_parse, auth)) + if (!Auth_parse_token_value(auth_parse, challenge, cb)) break; - token_value_pairs_found = 1; } - if (!token_value_pairs_found) { - MSG("auth.c: Auth_parse_auth_basic: " - "missing Basic auth token-value pairs\n"); - return; - } - - if (!auth_parse->realm) { - MSG("auth.c: Auth_parse_auth_basic: " - "missing Basic auth realm\n"); - return; + if (auth_parse->type == BASIC) { + if (auth_parse->realm) { + auth_parse->ok = 1; + } else { + MSG("Auth_parse_challenge_args: missing Basic auth realm\n"); + return; + } + } else if (auth_parse->type == DIGEST) { + if (auth_parse->realm && auth_parse->nonce) { + auth_parse->ok = 1; + } else { + MSG("Auth_parse_challenge_args: Digest challenge incomplete\n"); + return; + } } } -static void Auth_parse_auth(AuthParse_t *auth_parse, char *auth) +static void Auth_parse_challenge(AuthParse_t *auth_parse, char *challenge) { - _MSG("auth.c: Auth_parse_auth: auth = '%s'\n", auth); - if (dStrncasecmp(auth, "Basic ", 6) == 0) { - auth += 6; - Auth_parse_auth_basic(auth_parse, &auth); + Auth_parse_token_value_callback_t *cb; + + MSG("auth.c: Auth_parse_challenge: challenge = '%s'\n", challenge); + if (auth_parse->type == DIGEST) { + challenge += 7; + cb = Auth_parse_digest_challenge_cb; } else { - MSG("auth.c: Auth_parse_auth: " - "unknown authorization scheme: auth = {%s}\n", - auth); + challenge += 6; + cb = Auth_parse_basic_challenge_cb; } + Auth_parse_challenge_args(auth_parse, &challenge, cb); } /* @@ -305,7 +376,7 @@ static AuthRealm_t *Auth_realm_by_name(const AuthHost_t *host, int i; for (i = 0; (realm = dList_nth_data(host->realms, i)); i++) - if (strcmp(realm->name,name) == 0) + if (strcmp(realm->name, name) == 0) return realm; return NULL; @@ -319,9 +390,8 @@ static AuthRealm_t *Auth_realm_by_path(const AuthHost_t *host, { AuthRealm_t *realm_best, *realm; int i, j; - int match_length; + int match_length = 0; - match_length = 0; realm_best = NULL; for (i = 0; (realm = dList_nth_data(host->realms, i)); i++) { char *realm_path; @@ -339,6 +409,24 @@ static AuthRealm_t *Auth_realm_by_path(const AuthHost_t *host, return realm_best; } +static void Auth_realm_delete(AuthRealm_t *realm) +{ + int i; + + MSG("Auth_realm_delete: \"%s\"\n", realm->name); + for (i = dList_length(realm->paths) - 1; i >= 0; i--) + dFree(dList_nth_data(realm->paths, i)); + dList_free(realm->paths); + dFree(realm->name); + dFree(realm->username); + dFree(realm->authorization); + dFree(realm->cnonce); + dFree(realm->nonce); + dFree(realm->opaque); + dFree(realm->domain); + dFree(realm); +} + static int Auth_realm_includes_path(const AuthRealm_t *realm, const char *path) { int i; @@ -377,22 +465,33 @@ static void Auth_realm_add_path(AuthRealm_t *realm, const char *path) /* * Return the authorization header for an HTTP query. + * request_uri is a separate argument because we want it precisely as + * formatted in the request. */ -const char *a_Auth_get_auth_str(const DilloUrl *url) +char *a_Auth_get_auth_str(const DilloUrl *url, const char *request_uri) { + char *ret = NULL; AuthHost_t *host; AuthRealm_t *realm; - return - ((host = Auth_host_by_url(url)) && - (realm = Auth_realm_by_path(host, URL_PATH(url)))) ? - realm->authorization : NULL; + if ((host = Auth_host_by_url(url)) && + (realm = Auth_realm_by_path(host, URL_PATH(url)))) { + if (realm->type == BASIC) + ret = dStrdup(realm->authorization); + else if (realm->type == DIGEST) + ret = a_Digest_authorization_hdr(realm, url, request_uri); + else + MSG("a_Auth_get_auth_str() got an unknown realm type: %i.\n", + realm->type); + } + return ret; } /* * Determine whether the user needs to authenticate. */ -static int Auth_do_auth_required(const char *realm_name, const DilloUrl *url) +static int Auth_do_auth_required(const AuthParse_t *auth_parse, + const DilloUrl *url) { /* * TO DO: I dislike the way that this code must decide whether we @@ -420,12 +519,20 @@ static int Auth_do_auth_required(const char *realm_name, const DilloUrl *url) * we will re-authenticate. */ if ((host = Auth_host_by_url(url)) && - (realm = Auth_realm_by_name(host, realm_name)) && - (!Auth_realm_includes_path(realm, URL_PATH(url)))) { - _MSG("Auth_do_auth_required: updating realm '%s' with URL '%s'\n", - realm_name, URL_STR(url)); - Auth_realm_add_path(realm, URL_PATH(url)); - return 0; + (realm = Auth_realm_by_name(host, auth_parse->realm))) { + if (!Auth_realm_includes_path(realm, URL_PATH(url))) { + _MSG("Auth_do_auth_required: updating realm '%s' with URL '%s'\n", + auth_parse->realm, URL_STR(url)); + Auth_realm_add_path(realm, URL_PATH(url)); + return 0; + } + + if (auth_parse->type == DIGEST && auth_parse->stale) { + /* we do have valid credentials but our nonce is old */ + dFree((void *)realm->nonce); + realm->nonce = dStrdup(auth_parse->nonce); + return 0; + } } /* @@ -441,7 +548,6 @@ static void Auth_do_auth_dialog_cb(const char *user, const char *password, AuthDialogData_t *data; AuthHost_t *host; AuthRealm_t *realm; - char *user_password, *response, *authorization, *authorization_old; data = (AuthDialogData_t *)vData; @@ -456,45 +562,78 @@ static void Auth_do_auth_dialog_cb(const char *user, const char *password, } /* find or create the realm */ - if (!(realm = Auth_realm_by_name(host, data->realm_name))) { - /* create a new realm */ - realm = dNew(AuthRealm_t, 1); - realm->name = dStrdup(data->realm_name); + if (!(realm = Auth_realm_by_name(host, data->auth_parse->realm))) { + realm = dNew0(AuthRealm_t, 1); + realm->name = dStrdup(data->auth_parse->realm); realm->paths = dList_new(1); - realm->authorization = NULL; dList_append(host->realms, realm); } + realm->type = data->auth_parse->type; + dFree(realm->authorization); + realm->authorization = NULL; Auth_realm_add_path(realm, URL_PATH(data->url)); - /* create and set the authorization */ - user_password = dStrconcat(user, ":", password, NULL); - response = a_Misc_encode_base64(user_password); - authorization = - dStrconcat("Authorization: Basic ", response, "\r\n", NULL); - authorization_old = realm->authorization; - realm->authorization = authorization; - dFree(authorization_old); - dFree(user_password); - dFree(response); + if (realm->type == BASIC) { + char *user_password = dStrconcat(user, ":", password, NULL); + char *response = a_Misc_encode_base64(user_password); + char *authorization = + dStrconcat("Authorization: Basic ", response, "\r\n", NULL); + dFree(realm->authorization); + realm->authorization = authorization; + dFree(response); + dStrshred(user_password); + dFree(user_password); + } else if (realm->type == DIGEST) { + dFree(realm->username); + realm->username = dStrdup(user); + realm->nonce_count = 0; + dFree(realm->nonce); + realm->nonce = dStrdup(data->auth_parse->nonce); + dFree(realm->opaque); + realm->opaque = dStrdup(data->auth_parse->opaque); + realm->algorithm = data->auth_parse->algorithm; + dFree(realm->domain); + realm->domain = dStrdup(data->auth_parse->domain); + realm->qop = data->auth_parse->qop; + dFree(realm->cnonce); + if (realm->qop != QOPNOTSET) + realm->cnonce = a_Digest_create_cnonce(); + if (!a_Digest_compute_digest(realm, user, password)) { + MSG("Auth_do_auth_dialog_cb: a_Digest_compute_digest failed.\n"); + dList_remove_fast(host->realms, realm); + Auth_realm_delete(realm); + } + } else { + MSG("Auth_do_auth_dialog_cb: Unknown auth type: %i\n", + realm->type); + } + dStrshred((char *)password); } -static int Auth_do_auth_dialog(const char *realm, const DilloUrl *url) +/* + * Return: Nonzero if we got new credentials from the user and everything + * seems fine. + */ +static int Auth_do_auth_dialog(const AuthParse_t *auth_parse, + const DilloUrl *url) { int ret; char *message; AuthDialogData_t *data; + const char *typestr = auth_parse->type == DIGEST ? "Digest" : "Basic"; + + _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", auth_parse->realm); - _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", realm); message = dStrconcat("The server at ", URL_HOST(url), " requires a username" - " and password for \"", realm, "\".", NULL); + " and password for \"", auth_parse->realm, "\".\n\n" + "Authentication scheme: ", typestr, NULL); data = dNew(AuthDialogData_t, 1); - data->realm_name = dStrdup(realm); + data->auth_parse = auth_parse; data->url = a_Url_dup(url); ret = a_Dialog_user_password(message, Auth_do_auth_dialog_cb, data); dFree(message); - dFree((void*)data->realm_name); - a_Url_free((void*)data->url); + a_Url_free((void *)data->url); dFree(data); return ret; } @@ -502,19 +641,20 @@ static int Auth_do_auth_dialog(const char *realm, const DilloUrl *url) /* * Do authorization for an auth string. */ -static int Auth_do_auth(char *auth, const DilloUrl *url) +static int Auth_do_auth(char *challenge, enum AuthParseHTTPAuthType_t type, + const DilloUrl *url) { - int reload; AuthParse_t *auth_parse; + int reload = 0; - _MSG("auth.c: Auth_do_auth: auth={%s}\n", auth); - reload = 0; + _MSG("auth.c: Auth_do_auth: challenge={%s}\n", challenge); auth_parse = Auth_parse_new(); - Auth_parse_auth(auth_parse, auth); + auth_parse->type = type; + Auth_parse_challenge(auth_parse, challenge); if (auth_parse->ok) reload = - Auth_do_auth_required(auth_parse->realm, url) ? - Auth_do_auth_dialog(auth_parse->realm, url) + Auth_do_auth_required(auth_parse, url) ? + Auth_do_auth_dialog(auth_parse, url) : 1; Auth_parse_free(auth_parse); @@ -522,18 +662,24 @@ static int Auth_do_auth(char *auth, const DilloUrl *url) } /* - * Do authorization for a set of auth strings. + * Given authentication challenge(s), prepare authorization. + * Return: 0 on failure + * nonzero on success. A new query will be sent to the server. */ -int a_Auth_do_auth(Dlist *auths, const DilloUrl *url) +int a_Auth_do_auth(Dlist *challenges, const DilloUrl *url) { - int reload, i; - char *auth; + int i; + char *chal; - reload = 0; - for (i = 0; (auth = dList_nth_data(auths, i)); ++i) - if (Auth_do_auth(auth, url)) - reload = 1; + for (i = 0; (chal = dList_nth_data(challenges, i)); ++i) + if (!dStrncasecmp(chal, "Digest ", 7)) + if (Auth_do_auth(chal, DIGEST, url)) + return 1; + for (i = 0; (chal = dList_nth_data(challenges, i)); ++i) + if (!dStrncasecmp(chal, "Basic ", 6)) + if (Auth_do_auth(chal, BASIC, url)) + return 1; - return reload; + return 0; } @@ -7,8 +7,29 @@ extern "C" { #include "url.h" +enum AuthParseHTTPAuthType_t { TYPENOTSET, BASIC, DIGEST }; +enum AuthParseDigestAlgorithm_t { ALGORITHMNOTSET, MD5, MD5SESS }; +enum AuthParseDigestQOP_t { QOPNOTSET, AUTH, AUTHINT }; -const char *a_Auth_get_auth_str(const DilloUrl *request_url); +typedef struct { + enum AuthParseHTTPAuthType_t type; + char *name; + Dlist *paths; /* stripped of any trailing '/', so the root path is "" */ + char *authorization; /* BASIC: the authorization request header */ + /* DIGEST: the hexdigest of A1 */ + /* digest state ahead */ + char *username; + char *cnonce; + unsigned int nonce_count; + char *nonce; + char *opaque; + enum AuthParseDigestAlgorithm_t algorithm; + char *domain; /* NOT USED */ + enum AuthParseDigestQOP_t qop; +} AuthRealm_t; + + +char *a_Auth_get_auth_str(const DilloUrl *url, const char *request_uri); int a_Auth_do_auth(Dlist *auth_string, const DilloUrl *url); void a_Auth_init(void); |