mod_auth_digest.c revision 8ec8f1c8f0f37ca3f5ebb0e0b491dd07481dccbf
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor/* ====================================================================
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * The Apache Software License, Version 1.1
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * Copyright (c) 2000 The Apache Software Foundation. All rights
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * reserved.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * Redistribution and use in source and binary forms, with or without
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * modification, are permitted provided that the following conditions
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * 1. Redistributions of source code must retain the above copyright
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * notice, this list of conditions and the following disclaimer.
2e545ce2450a9953665f701bb05350f0d3f26275nd * 2. Redistributions in binary form must reproduce the above copyright
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * notice, this list of conditions and the following disclaimer in
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * the documentation and/or other materials provided with the
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * distribution.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * 3. The end-user documentation included with the redistribution,
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * if any, must include the following acknowledgment:
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * "This product includes software developed by the
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * Apache Software Foundation (http://www.apache.org/)."
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * Alternately, this acknowledgment may appear in the software itself,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * if and wherever such third-party acknowledgments normally appear.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * 4. The names "Apache" and "Apache Software Foundation" must
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * not be used to endorse or promote products derived from this
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * software without prior written permission. For written
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * permission, please contact apache@apache.org.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * 5. Products derived from this software may not be called "Apache",
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung * nor may "Apache" appear in their name, without prior written
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * permission of the Apache Software Foundation.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * SUCH DAMAGE.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * ====================================================================
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * This software consists of voluntary contributions made by many
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * individuals on behalf of the Apache Software Foundation. For more
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * information on the Apache Software Foundation, please see
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * Portions of this software are based upon public domain software
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * originally written at the National Center for Supercomputing Applications,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * University of Illinois, Urbana-Champaign.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * mod_auth_digest: MD5 digest authentication
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * Originally by Alexei Kosut <akosut@nueva.pvt.k12.ca.us>
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * Updated to RFC-2617 by Ronald Tschal�r <ronald@innovation.ch>
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * based on mod_auth, by Rob McCool and Robert S. Thau
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * This module an updated version of modules/standard/mod_digest.c
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * It is still fairly new and problems may turn up - submit problem
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * reports to the Apache bug-database, or send them directly to me
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * at ronald@innovation.ch.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * Requires either /dev/random (or equivalent) or the truerand library,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * available for instance from
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * Open Issues:
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * - qop=auth-int (when streams and trailer support available)
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * - nonce-format configurability
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * - Proxy-Authorization-Info header is set by this module, but is
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * currently ignored by mod_proxy (needs patch to mod_proxy)
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * - generating the secret takes a while (~ 8 seconds) if using the
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * truerand library
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * - The source of the secret should be run-time directive (with server
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * scope: RSRC_CONF). However, that could be tricky when trying to
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * choose truerand vs. file...
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * - shared-mem not completely tested yet. Seems to work ok for me,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * but... (definitely won't work on Windoze)
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * - Sharing a realm among multiple servers has following problems:
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * o Server name and port can't be included in nonce-hash
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * (we need two nonce formats, which must be configured explicitly)
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * o Nonce-count check can't be for equal, or then nonce-count checking
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * must be disabled. What we could do is the following:
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * (expected < received) ? set expected = received : issue error
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * The only problem is that it allows replay attacks when somebody
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * captures a packet sent to one server and sends it to another
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * one. Should we add "AuthDigestNcCheck Strict"?
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * - expired nonces give amaya fits.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor/* just provide dummies - the code does run-time checks anyway */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzortypedef void ap_shmem_t;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorap_status_t ap_shm_init(ap_shmem_t **m, ap_size_t reqsize, const char *file, ap_pool_t *cont) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorvoid *ap_shm_malloc(ap_shmem_t *c, ap_size_t reqsize) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorvoid *ap_shm_calloc(ap_shmem_t *shared, ap_size_t size) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorap_status_t ap_shm_free(ap_shmem_t *shared, void *free) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorap_status_t ap_get_shm_name(ap_shmem_t *c, ap_shm_name_t **name) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorap_status_t ap_set_shm_name(ap_shmem_t *c, ap_shm_name_t *name) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorap_status_t ap_shm_avail(ap_shmem_t *c, ap_size_t *avail) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor/* struct to hold the configuration info */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzortypedef struct digest_config_struct {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *dir_name;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *pwfile;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *grpfile;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *realm;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char **qop_list;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *algorithm;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *ha1;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor/* client list definitions */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzortypedef struct hash_entry {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor struct hash_entry *next; /* next entry in the bucket */
3c08156e511e20e221c69dfd20006c2269d1e3cdrjung unsigned long nonce_count; /* for nonce-count checking */
3c08156e511e20e221c69dfd20006c2269d1e3cdrjung char ha1[2*MD5_DIGESTSIZE+1]; /* for algorithm=MD5-sess */
3c08156e511e20e221c69dfd20006c2269d1e3cdrjung char last_nonce[NONCE_LEN+1]; /* for one-time nonce's */
3c08156e511e20e221c69dfd20006c2269d1e3cdrjungstatic struct hash_table {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor unsigned long tbl_len;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor unsigned long num_entries;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor unsigned long num_created;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor unsigned long num_removed;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor unsigned long num_renewed;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor/* struct to hold a parsed Authorization header */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorenum hdr_sts { NO_HEADER, NOT_DIGEST, INVALID, VALID };
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzortypedef struct digest_header_struct {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *scheme;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *realm;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *username;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *uri;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *digest;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *algorithm;
e881a4190c2ee92f38e32a394029c047fb885753lgentis const char *cnonce;
e881a4190c2ee92f38e32a394029c047fb885753lgentis const char *opaque;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor unsigned long opaque_num;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor /* the following fields are not (directly) from the header */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor/* (mostly) nonce stuff */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzortypedef union time_union {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorstatic int call_cnt = 0;
727872d18412fc021f03969b8641810d8896820bhumbedooh/* client-list, opaque, and one-time-nonce stuff */
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedoohstatic unsigned long *opaque_cntr;
0d0ba3a410038e179b695446bb149cce6264e0abndstatic ap_time_t *otn_counter; /* one-time-nonce counter */
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * initialization code
if (client_shm) {
if (client_lock) {
if (opaque_lock) {
return APR_SUCCESS;
unsigned long idx;
if (!client_list) {
*otn_counter = 0;
#define APR_HAS_SHARED_MEMORY 0
initialize_tables(s, p);
if (!client_shm)
!= APR_SUCCESS
!= APR_SUCCESS) {
if (conf) {
return conf;
return DECLINE_CMD;
const char *file)
return NULL;
const char *file)
return NULL;
const char **tmp;
int cnt;
return NULL;
return NULL;
char *endptr;
long lifetime;
return NULL;
const char *fmt)
return NULL;
if (!client_shm) {
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)
num_removed++;
return num_removed;
server_rec *s)
int bucket;
if (!entry) {
return entry;
const char *auth_line;
size_t l;
if (!auth_line) {
return !OK;
return !OK;
vk = 0;
auth_line++;
vv = 0;
auth_line++;
return !OK;
return OK;
int res;
if (!ap_is_initial_req(r))
return DECLINED;
return DECLINED;
int idx;
if (opaque)
int len;
time_rec t;
else if (otn_counter)
return nonce;
unsigned long op;
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;
return dir;
return "http://0.0.0.0/";
return dir;
return tmp;
if (num != 0)
int cnt;
if (opaque[0])
if (r->proxyreq)
configfile_t *f;
char l[MAX_STRING_LEN];
const char *rpw;
return NULL;
rpw = l;
ap_cfg_closefile(f);
ap_cfg_closefile(f);
return NULL;
unsigned long nc;
char *endptr;
return OK;
return !OK;
return !OK;
return !OK;
return OK;
double dt;
int len;
return AUTH_REQUIRED;
return AUTH_REQUIRED;
return AUTH_REQUIRED;
return AUTH_REQUIRED;
return AUTH_REQUIRED;
return OK;
const char *ha2;
if (!ha1)
return NULL;
NULL));
request_rec *r) {
int res;
return DECLINED;
if (!ap_auth_name(r)) {
return SERVER_ERROR;
mainreq = r;
r->uri);
return AUTH_REQUIRED;
return BAD_REQUEST;
return BAD_REQUEST;
return BAD_REQUEST;
return AUTH_REQUIRED;
return AUTH_REQUIRED;
return AUTH_REQUIRED;
return DECLINED;
return AUTH_REQUIRED;
r->uri);
return AUTH_REQUIRED;
const char *exp_digest;
if (!match
return AUTH_REQUIRED;
if (!exp_digest) {
return SERVER_ERROR;
r->uri);
return AUTH_REQUIRED;
return AUTH_REQUIRED;
return res;
return OK;
const char *grpfile)
configfile_t *f;
char l[MAX_STRING_LEN];
return NULL;
return NULL;
ll = l;
while (ll[0]) {
ap_cfg_closefile(f);
return grps;
int m = r->method_number;
int method_restricted = 0;
return DECLINED;
if (!reqs_arr)
return OK;
return OK;
return OK;
if (!grpstatus)
return DECLINED;
return OK;
return DECLINED;
if (!method_restricted)
return OK;
return AUTH_REQUIRED;
#ifdef SEND_DIGEST
if (val)
return val;
return OK;
#ifdef SEND_DIGEST
char *entity_info =
date :
NULL));
digest =
NULL));
conf);
if (digest)
if (!ha1) {
return !OK;
NULL);
ai);
return OK;
static void register_hooks(void)