summaryrefslogtreecommitdiff
path: root/src/ne_auth.c
diff options
context:
space:
mode:
authorjoe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845>2007-11-19 15:55:30 +0000
committerjoe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845>2007-11-19 15:55:30 +0000
commit7cddc0e0ce48ee9a61393a2ad98a1ba3ace5d140 (patch)
treef47fd821e6eecc947e934b7ee89741ba327ce5ba /src/ne_auth.c
parent2a7c2c299dfba98a9a28091018291c46a92a8e37 (diff)
downloadneon-7cddc0e0ce48ee9a61393a2ad98a1ba3ace5d140.tar.gz
Add support for domain handling in Digest authentication:
* src/ne_auth.c (struct auth_challenge): Add domain field. (auth_session): Add domains, ndomains fields. (free_domains, parse_domain, inside_domain): New functions. (clean_session): Call free_domains. (digest_challenge): Parse the domain parameter. (request_digest): Don't submit credentials if request falls outside the defined auth domain, if any. (auth_challenge): Capture the domain parameter. * test/auth.c (make_digest_header, serve_digest): Update for handling domains test. (domains): New test case. git-svn-id: http://svn.webdav.org/repos/projects/neon/trunk@1273 61a7d7f5-40b7-0310-9c16-bb0ea8cb1845
Diffstat (limited to 'src/ne_auth.c')
-rw-r--r--src/ne_auth.c113
1 files changed, 110 insertions, 3 deletions
diff --git a/src/ne_auth.c b/src/ne_auth.c
index 178d705..8bee30e 100644
--- a/src/ne_auth.c
+++ b/src/ne_auth.c
@@ -107,9 +107,7 @@ struct auth_handler {
struct auth_challenge {
const struct auth_protocol *protocol;
struct auth_handler *handler;
- const char *realm;
- const char *nonce;
- const char *opaque;
+ const char *realm, *nonce, *opaque, *domain;
unsigned int stale; /* if stale=true */
unsigned int got_qop; /* we were given a qop directive */
unsigned int qop_auth; /* "auth" token in qop attrib */
@@ -178,6 +176,8 @@ typedef struct {
char *nonce;
char *cnonce;
char *opaque;
+ char **domains; /* list of paths given as domain. */
+ size_t ndomains; /* size of domains array */
auth_qop qop;
auth_algorithm alg;
unsigned int nonce_count;
@@ -244,6 +244,16 @@ struct auth_protocol {
static void challenge_error(ne_buffer **errmsg, const char *fmt, ...)
ne_attribute((format(printf, 2, 3)));
+/* Free the domains array, precondition sess->ndomains > 0. */
+static void free_domains(auth_session *sess)
+{
+ do {
+ ne_free(sess->domains[sess->ndomains - 1]);
+ } while (--sess->ndomains);
+ ne_free(sess->domains);
+ sess->domains = NULL;
+}
+
static void clean_session(auth_session *sess)
{
if (sess->basic) ne_free(sess->basic);
@@ -257,6 +267,7 @@ static void clean_session(auth_session *sess)
ne_md5_destroy_ctx(sess->stored_rdig);
sess->stored_rdig = NULL;
}
+ if (sess->ndomains) free_domains(sess);
#ifdef HAVE_GSSAPI
{
unsigned int major;
@@ -612,6 +623,61 @@ static int sspi_challenge(auth_session *sess, int attempt,
}
#endif
+/* Parse the "domain" challenge parameter and set the domains array up
+ * in the session appropriately. */
+static int parse_domain(auth_session *sess, const char *domain)
+{
+ char *cp = ne_strdup(domain), *p = cp;
+ ne_uri base = {0};
+ int invalid = 0;
+
+ ne_fill_server_uri(sess->sess, &base);
+
+ do {
+ char *token = ne_token(&p, ',');
+ ne_uri rel, absolute;
+
+ if (ne_uri_parse(token, &rel) == 0) {
+ /* Resolve relative to the Request-URI. */
+ ne_uri_resolve(&base, &rel, &absolute);
+
+ base.path = absolute.path;
+
+ /* Ignore URIs not on this server. */
+ if (ne_uri_cmp(&absolute, &base) == 0) {
+ sess->domains = ne_realloc(sess->domains,
+ ++sess->ndomains *
+ sizeof(*sess->domains));
+ sess->domains[sess->ndomains - 1] = ne_strdup(absolute.path);
+ NE_DEBUG(NE_DBG_HTTPAUTH, "auth: Using domain %s from %s\n",
+ absolute.path, token);
+ absolute.path = NULL;
+ }
+ else {
+ NE_DEBUG(NE_DBG_HTTPAUTH, "auth: Ignoring domain %s\n",
+ token);
+ }
+
+ ne_uri_free(&absolute);
+ }
+ else {
+ invalid = 1;
+ }
+
+ ne_uri_free(&rel);
+
+ } while (p && !invalid);
+
+ if (invalid && sess->ndomains) {
+ free_domains(sess);
+ }
+
+ ne_free(cp);
+ ne_uri_free(&base);
+
+ return invalid;
+}
+
/* Examine a digest challenge: return 0 if it is a valid Digest challenge,
* else non-zero. */
static int digest_challenge(auth_session *sess, int attempt,
@@ -648,6 +714,14 @@ static int digest_challenge(auth_session *sess, int attempt,
/* Non-stale challenge: clear session and request credentials. */
clean_session(sess);
+ /* The domain paramater must be parsed after the session is
+ * cleaned; ignore domain for proxy auth. */
+ if (parms->domain && sess->spec == &ah_server_class
+ && parse_domain(sess, parms->domain)) {
+ challenge_error(errmsg, _("could not parse domain in Digest challenge"));
+ return -1;
+ }
+
sess->realm = ne_strdup(parms->realm);
sess->alg = parms->alg;
sess->cnonce = get_cnonce();
@@ -721,6 +795,30 @@ static int digest_challenge(auth_session *sess, int attempt,
return 0;
}
+/* Returns non-zero if given URI is inside the authentication domain
+ * defined for the session. */
+static int inside_domain(auth_session *sess, const char *uri)
+{
+ size_t n;
+ int inside = 0;
+
+ /* For non-abs_path URIs, ignore. */
+ if (uri[0] != '/') {
+ return 1;
+ }
+
+ for (n = 0; n < sess->ndomains && !inside; n++) {
+ const char *d = sess->domains[n];
+
+ inside = (d[strlen(d)-1] == '/' && strncmp(uri, d, strlen(d)) == 0)
+ || strcmp(d, uri) == 0;
+ }
+
+ NE_DEBUG(NE_DBG_HTTPAUTH, "auth: Inside auth domain: %d.\n", inside);
+
+ return inside;
+}
+
/* Return Digest authentication credentials header value for the given
* session. */
static char *request_digest(auth_session *sess, struct auth_request *req)
@@ -731,6 +829,12 @@ static char *request_digest(auth_session *sess, struct auth_request *req)
const char *qop_value = "auth"; /* qop-value */
ne_buffer *ret;
+ /* Do not submit credentials if an auth domain is defined and this
+ * request-uri fails outside it. */
+ if (sess->ndomains && !inside_domain(sess, req->uri)) {
+ return NULL;
+ }
+
/* Increase the nonce-count */
if (sess->qop != auth_qop_none) {
sess->nonce_count++;
@@ -1163,6 +1267,9 @@ static int auth_challenge(auth_session *sess, int attempt,
chall->got_qop = chall->qop_auth;
}
+ else if (ne_strcasecmp(key, "domain") == 0) {
+ chall->domain = val;
+ }
}
sess->protocol = NULL;