mod_auth_digest.c revision 92108a6c4fd7ca6e9acc94d2485920436763e491
6de8046f8f7e07cd83895a528df25d977e502c76nd/* Licensed to the Apache Software Foundation (ASF) under one or more
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * contributor license agreements. See the NOTICE file distributed with
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * this work for additional information regarding copyright ownership.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * The ASF licenses this file to You under the Apache License, Version 2.0
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * (the "License"); you may not use this file except in compliance with
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * the License. You may obtain a copy of the License at
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * limitations under the License.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * mod_auth_digest: MD5 digest authentication
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Originally by Alexei Kosut <akosut@nueva.pvt.k12.ca.us>
cd5c0afc86ca2eb23d6d12e14590e03cf2f80450gstein * Updated to RFC-2617 by Ronald Tschal�r <ronald@innovation.ch>
f4c310fd2555c6faca1f980f00b161eadb089023gstein * based on mod_auth, by Rob McCool and Robert S. Thau
f6b86fd524444dacf82f64148300d8be04918314gstein * This module an updated version of modules/standard/mod_digest.c
f4c310fd2555c6faca1f980f00b161eadb089023gstein * It is still fairly new and problems may turn up - submit problem
f4c310fd2555c6faca1f980f00b161eadb089023gstein * reports to the Apache bug-database, or send them directly to me
f69b31136266022effeb1272d153c92a09de072djerenkrantz * at ronald@innovation.ch.
f6b86fd524444dacf82f64148300d8be04918314gstein * Requires either /dev/random (or equivalent) or the truerand library,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * available for instance from
aa552377469071a421252dab6568c204a99cf770gstein * Open Issues:
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * - qop=auth-int (when streams and trailer support available)
3a02a42c92afc04c1cfca12eabdf19963784ae83nd * - nonce-format configurability
aa552377469071a421252dab6568c204a99cf770gstein * - Proxy-Authorization-Info header is set by this module, but is
aa552377469071a421252dab6568c204a99cf770gstein * currently ignored by mod_proxy (needs patch to mod_proxy)
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * - generating the secret takes a while (~ 8 seconds) if using the
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * truerand library
226b4a760e9b997415cf061bb3d979c0c31ae642jorton * - The source of the secret should be run-time directive (with server
f4c310fd2555c6faca1f980f00b161eadb089023gstein * scope: RSRC_CONF). However, that could be tricky when trying to
aa552377469071a421252dab6568c204a99cf770gstein * choose truerand vs. file...
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * - shared-mem not completely tested yet. Seems to work ok for me,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * but... (definitely won't work on Windoze)
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * - Sharing a realm among multiple servers has following problems:
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * o Server name and port can't be included in nonce-hash
f69b31136266022effeb1272d153c92a09de072djerenkrantz * (we need two nonce formats, which must be configured explicitly)
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * o Nonce-count check can't be for equal, or then nonce-count checking
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * must be disabled. What we could do is the following:
f69b31136266022effeb1272d153c92a09de072djerenkrantz * (expected < received) ? set expected = received : issue error
f69b31136266022effeb1272d153c92a09de072djerenkrantz * The only problem is that it allows replay attacks when somebody
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * captures a packet sent to one server and sends it to another
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * one. Should we add "AuthDigestNcCheck Strict"?
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * - expired nonces give amaya fits.
f69b31136266022effeb1272d153c92a09de072djerenkrantz/* struct to hold the configuration info */
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz const char *realm;
aa552377469071a421252dab6568c204a99cf770gstein const char *ha1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein#define NONCE_LEN (int )(NONCE_TIME_LEN + NONCE_HASH_LEN)
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* client list definitions */
aa552377469071a421252dab6568c204a99cf770gsteintypedef struct hash_entry {
aa552377469071a421252dab6568c204a99cf770gstein struct hash_entry *next; /* next entry in the bucket */
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned long nonce_count; /* for nonce-count checking */
aa552377469071a421252dab6568c204a99cf770gstein char ha1[2*APR_MD5_DIGESTSIZE+1]; /* for algorithm=MD5-sess */
f4c310fd2555c6faca1f980f00b161eadb089023gstein char last_nonce[NONCE_LEN+1]; /* for one-time nonce's */
aa552377469071a421252dab6568c204a99cf770gsteinstatic struct hash_table {
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz unsigned long tbl_len;
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz unsigned long num_entries;
aa552377469071a421252dab6568c204a99cf770gstein unsigned long num_created;
226b4a760e9b997415cf061bb3d979c0c31ae642jorton unsigned long num_removed;
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned long num_renewed;
} *client_list;
typedef struct digest_header_struct {
const char *scheme;
const char *realm;
const char *username;
char *nonce;
const char *uri;
const char *method;
const char *digest;
const char *algorithm;
const char *cnonce;
const char *opaque;
unsigned long opaque_num;
const char *message_qop;
const char *nonce_count;
const char *raw_request_uri;
int needed_auth;
typedef union time_union {
} time_rec;
static unsigned long *opaque_cntr;
static const char *client_shm_filename;
if (client_rmm) {
if (client_shm) {
if (client_lock) {
if (opaque_lock) {
return APR_SUCCESS;
#if APR_HAS_RANDOM
return status;
return APR_SUCCESS;
unsigned long idx;
return HTTP_INTERNAL_SERVER_ERROR;
return !OK;
if (!client_list) {
return !OK;
s, ctx, 0);
return !OK;
return !OK;
s, ctx, 0);
return !OK;
return !OK;
*otn_counter = 0;
return OK;
return rv;
return OK;
return OK;
return !OK;
return !OK;
return OK;
if (!client_shm) {
NULL,
return NULL;
if (conf) {
return conf;
return DECLINE_CMD;
const char *arg)
return NULL;
return NULL;
return NULL;
char *endptr;
long lifetime;
t, NULL);
return NULL;
const char *fmt)
if (flag) {
return NULL;
return NULL;
if (c->uri_list) {
return NULL;
const char *size_str)
char *endptr;
if (num_buckets == 0) {
return NULL;
{NULL}
int bucket;
if (entry) {
return entry;
static long gc(void)
if (prev) {
num_removed++;
return num_removed;
server_rec *s)
int bucket;
return NULL;
if (!entry) {
if (!entry) {
return entry;
const char *auth_line;
apr_size_t l;
if (!auth_line) {
return !OK;
return !OK;
auth_line++;
vk = 0;
auth_line++;
auth_line++;
auth_line++;
vv = 0;
auth_line++;
auth_line++;
auth_line++;
auth_line++;
return !OK;
return OK;
int res;
if (!ap_is_initial_req(r)) {
return DECLINED;
return DECLINED;
if (opaque) {
time_rec t;
else if (otn_counter) {
return nonce;
unsigned long op;
if (!opaque_cntr) {
return NULL;
return NULL;
return entry;
* people need not modify mod_auth_digest.c each time they install a new
int generate)
else if (!generate) {
return NULL;
if (ha1) {
return ha1;
if (num != 0) {
NULL);
if (opaque[0]) {
return DECLINED;
mainreq = r;
return OK;
char *password;
if (!current_provider) {
&password);
} while (current_provider);
return auth_result;
unsigned long nc;
char *endptr;
return OK;
return OK;
snc);
return !OK;
return OK;
return !OK;
return !OK;
return !OK;
return OK;
return HTTP_UNAUTHORIZED;
return HTTP_UNAUTHORIZED;
return HTTP_UNAUTHORIZED;
return HTTP_UNAUTHORIZED;
return HTTP_UNAUTHORIZED;
return OK;
const char *ha2;
if (!ha1) {
return NULL;
NULL));
int res;
return DECLINED;
if (!ap_auth_name(r)) {
return HTTP_INTERNAL_SERVER_ERROR;
mainreq = r;
r->uri);
return HTTP_UNAUTHORIZED;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_UNAUTHORIZED;
return HTTP_UNAUTHORIZED;
return HTTP_UNAUTHORIZED;
return HTTP_UNAUTHORIZED;
return HTTP_UNAUTHORIZED;
return HTTP_INTERNAL_SERVER_ERROR;
r->uri);
return HTTP_UNAUTHORIZED;
const char *exp_digest;
++tmp;
if (!match
return HTTP_UNAUTHORIZED;
if (!exp_digest) {
return HTTP_INTERNAL_SERVER_ERROR;
r->uri);
return HTTP_UNAUTHORIZED;
return HTTP_UNAUTHORIZED;
return res;
return OK;
return OK;
conf);
if (!ha1) {
return !OK;
NULL);
ai);
return OK;