Main Page | Modules | Namespace List | Class List | Directories | File List | Class Members | File Members | Related Pages | Examples

mod_auth_digest.c File Reference

#include "apr_sha1.h"
#include "apr_base64.h"
#include "apr_lib.h"
#include "apr_time.h"
#include "apr_errno.h"
#include "apr_global_mutex.h"
#include "apr_strings.h"
#include "apr_want.h"
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_request.h"
#include "http_log.h"
#include "http_protocol.h"
#include "apr_uri.h"
#include "util_md5.h"
#include "apr_shm.h"
#include "apr_rmm.h"
#include "ap_provider.h"
#include "mod_auth.h"

Go to the source code of this file.

Classes

struct  digest_config_struct
struct  hash_entry
struct  hash_table
struct  digest_header_struct
union  time_union

Defines

#define APR_WANT_STRFUNC
#define APR_HAS_SHARED_MEMORY   0
#define DFLT_ALGORITHM   "MD5"
#define DFLT_NONCE_LIFE   apr_time_from_sec(300)
#define NEXTNONCE_DELTA   apr_time_from_sec(30)
#define NONCE_TIME_LEN   (((sizeof(apr_time_t)+2)/3)*4)
#define NONCE_HASH_LEN   (2*APR_SHA1_DIGESTSIZE)
#define NONCE_LEN   (int )(NONCE_TIME_LEN + NONCE_HASH_LEN)
#define SECRET_LEN   20
#define DEF_SHMEM_SIZE   1000L
#define DEF_NUM_BUCKETS   15L
#define HASH_DEPTH   5

Typedefs

typedef digest_config_struct digest_config_rec
typedef hash_entry client_entry
typedef digest_header_struct digest_header_rec
typedef time_union time_rec

Enumerations

enum  hdr_sts { NO_HEADER, NOT_DIGEST, INVALID, VALID }

Functions

static apr_status_t cleanup_tables (void *not_used)
static apr_status_t initialize_secret (server_rec *s)
static void log_error_and_cleanup (char *msg, apr_status_t sts, server_rec *s)
static int initialize_module (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
static void initialize_child (apr_pool_t *p, server_rec *s)
static void * create_digest_dir_config (apr_pool_t *p, char *dir)
static const char * set_realm (cmd_parms *cmd, void *config, const char *realm)
static const char * add_authn_provider (cmd_parms *cmd, void *config, const char *arg)
static const char * set_qop (cmd_parms *cmd, void *config, const char *op)
static const char * set_nonce_lifetime (cmd_parms *cmd, void *config, const char *t)
static const char * set_nonce_format (cmd_parms *cmd, void *config, const char *fmt)
static const char * set_nc_check (cmd_parms *cmd, void *config, int flag)
static const char * set_algorithm (cmd_parms *cmd, void *config, const char *alg)
static const char * set_uri_list (cmd_parms *cmd, void *config, const char *uri)
static const char * set_shmem_size (cmd_parms *cmd, void *config, const char *size_str)
static client_entryget_client (unsigned long key, const request_rec *r)
static long gc (void)
static client_entryadd_client (unsigned long key, client_entry *info, server_rec *s)
static int get_digest_rec (request_rec *r, digest_header_rec *resp)
static int parse_hdr_and_update_nc (request_rec *r)
static void gen_nonce_hash (char *hash, const char *timestr, const char *opaque, const server_rec *server, const digest_config_rec *conf)
static const char * gen_nonce (apr_pool_t *p, apr_time_t now, const char *opaque, const server_rec *server, const digest_config_rec *conf)
static client_entrygen_client (const request_rec *r)
static const char * get_userpw_hash (const request_rec *r, const digest_header_rec *resp, const digest_config_rec *conf)
static const char * get_session_HA1 (const request_rec *r, digest_header_rec *resp, const digest_config_rec *conf, int generate)
static void clear_session (const digest_header_rec *resp)
static const char * ltox (apr_pool_t *p, unsigned long num)
static void note_digest_auth_failure (request_rec *r, const digest_config_rec *conf, digest_header_rec *resp, int stale)
static authn_status get_hash (request_rec *r, const char *user, digest_config_rec *conf)
static int check_nc (const request_rec *r, const digest_header_rec *resp, const digest_config_rec *conf)
static int check_nonce (request_rec *r, digest_header_rec *resp, const digest_config_rec *conf)
static const char * old_digest (const request_rec *r, const digest_header_rec *resp, const char *ha1)
static const char * new_digest (const request_rec *r, digest_header_rec *resp, const digest_config_rec *conf)
static void copy_uri_components (apr_uri_t *dst, apr_uri_t *src, request_rec *r)
static int authenticate_digest_user (request_rec *r)
static int add_auth_info (request_rec *r)
static void register_hooks (apr_pool_t *p)

Variables

static struct hash_tableclient_list
static unsigned char secret [SECRET_LEN]
static apr_shm_tclient_shm = NULL
static apr_rmm_tclient_rmm = NULL
static unsigned long * opaque_cntr
static apr_time_totn_counter
static apr_global_mutex_tclient_lock = NULL
static apr_global_mutex_topaque_lock = NULL
static char client_lock_name [L_tmpnam]
static char opaque_lock_name [L_tmpnam]
static long shmem_size = DEF_SHMEM_SIZE
static long num_buckets = DEF_NUM_BUCKETS
module AP_MODULE_DECLARE_DATA auth_digest_module
static const command_rec digest_cmds []


Define Documentation

#define APR_HAS_SHARED_MEMORY   0
 

Definition at line 87 of file mod_auth_digest.c.

Referenced by testshm().

#define APR_WANT_STRFUNC
 

Definition at line 65 of file mod_auth_digest.c.

#define DEF_NUM_BUCKETS   15L
 

Definition at line 188 of file mod_auth_digest.c.

#define DEF_SHMEM_SIZE   1000L
 

Definition at line 187 of file mod_auth_digest.c.

#define DFLT_ALGORITHM   "MD5"
 

Definition at line 106 of file mod_auth_digest.c.

Referenced by create_digest_dir_config().

#define DFLT_NONCE_LIFE   apr_time_from_sec(300)
 

Definition at line 108 of file mod_auth_digest.c.

Referenced by create_digest_dir_config().

#define HASH_DEPTH   5
 

Definition at line 189 of file mod_auth_digest.c.

Referenced by set_shmem_size().

#define NEXTNONCE_DELTA   apr_time_from_sec(30)
 

Definition at line 109 of file mod_auth_digest.c.

Referenced by add_auth_info().

#define NONCE_HASH_LEN   (2*APR_SHA1_DIGESTSIZE)
 

Definition at line 113 of file mod_auth_digest.c.

Referenced by check_nonce().

#define NONCE_LEN   (int )(NONCE_TIME_LEN + NONCE_HASH_LEN)
 

Definition at line 114 of file mod_auth_digest.c.

Referenced by add_auth_info(), check_nonce(), gen_nonce(), and note_digest_auth_failure().

#define NONCE_TIME_LEN   (((sizeof(apr_time_t)+2)/3)*4)
 

Definition at line 112 of file mod_auth_digest.c.

Referenced by check_nonce(), and gen_nonce().

#define SECRET_LEN   20
 

Definition at line 116 of file mod_auth_digest.c.


Typedef Documentation

typedef struct hash_entry client_entry
 

typedef struct digest_config_struct digest_config_rec
 

typedef struct digest_header_struct digest_header_rec
 

typedef union time_union time_rec
 


Enumeration Type Documentation

enum hdr_sts
 

Enumerator:
NO_HEADER 
NOT_DIGEST 
INVALID 
VALID 

Definition at line 141 of file mod_auth_digest.c.


Function Documentation

static int add_auth_info request_rec r  )  [static]
 

Definition at line 1866 of file mod_auth_digest.c.

References digest_header_struct::algorithm, ap_get_module_config, APLOG_ERR, APLOG_MARK, apr_rfc822_date(), APR_RFC822_DATE_LEN, auth_digest_module, digest_header_struct::client, digest_header_struct::cnonce, conf, request_rec::content_encoding, request_rec::content_type, digest, gen_nonce(), get_session_HA1(), digest_config_struct::ha1, hdr, request_rec::headers_out, hash_entry::last_nonce, digest_header_struct::message_qop, request_rec::method, digest_header_struct::needed_auth, NEXTNONCE_DELTA, request_rec::no_cache, digest_header_struct::nonce, digest_header_struct::nonce_count, hash_entry::nonce_count, NONCE_LEN, digest_config_struct::nonce_lifetime, digest_header_struct::nonce_time, NULL, OK, digest_header_struct::opaque, request_rec::per_dir_config, request_rec::pool, request_rec::proxyreq, PROXYREQ_PROXY, digest_config_struct::qop_list, digest_header_struct::raw_request_uri, request_rec::request_config, request_rec::request_time, request_rec::server, strcasecmp(), digest_header_struct::uri, and digest_header_struct::username.

Referenced by register_hooks().

01867 {
01868     const digest_config_rec *conf =
01869                 (digest_config_rec *) ap_get_module_config(r->per_dir_config,
01870                                                            &auth_digest_module);
01871     digest_header_rec *resp =
01872                 (digest_header_rec *) ap_get_module_config(r->request_config,
01873                                                            &auth_digest_module);
01874     const char *ai = NULL, *digest = NULL, *nextnonce = "";
01875 
01876     if (resp == NULL || !resp->needed_auth || conf == NULL) {
01877         return OK;
01878     }
01879 
01880 
01881     /* rfc-2069 digest
01882      */
01883     if (resp->message_qop == NULL) {
01884         /* old client, so calc rfc-2069 digest */
01885 
01886 #ifdef SEND_DIGEST
01887         /* most of this totally bogus because the handlers don't set the
01888          * headers until the final handler phase (I wonder why this phase
01889          * is called fixup when there's almost nothing you can fix up...)
01890          *
01891          * Because it's basically impossible to get this right (e.g. the
01892          * Content-length is never set yet when we get here, and we can't
01893          * calc the entity hash) it's best to just leave this #def'd out.
01894          */
01895         char date[APR_RFC822_DATE_LEN];
01896         apr_rfc822_date(date, r->request_time);
01897         char *entity_info =
01898             ap_md5(r->pool,
01899                    (unsigned char *) apr_pstrcat(r->pool, resp->raw_request_uri,
01900                        ":",
01901                        r->content_type ? r->content_type : ap_default_type(r), ":",
01902                        hdr(r->headers_out, "Content-Length"), ":",
01903                        r->content_encoding ? r->content_encoding : "", ":",
01904                        hdr(r->headers_out, "Last-Modified"), ":",
01905                        r->no_cache && !apr_table_get(r->headers_out, "Expires") ?
01906                             date :
01907                             hdr(r->headers_out, "Expires"),
01908                        NULL));
01909         digest =
01910             ap_md5(r->pool,
01911                    (unsigned char *)apr_pstrcat(r->pool, conf->ha1, ":",
01912                                                resp->nonce, ":",
01913                                                r->method, ":",
01914                                                date, ":",
01915                                                entity_info, ":",
01916                                                ap_md5(r->pool, (unsigned char *) ""), /* H(entity) - TBD */
01917                                                NULL));
01918 #endif
01919     }
01920 
01921 
01922     /* setup nextnonce
01923      */
01924     if (conf->nonce_lifetime > 0) {
01925         /* send nextnonce if current nonce will expire in less than 30 secs */
01926         if ((r->request_time - resp->nonce_time) > (conf->nonce_lifetime-NEXTNONCE_DELTA)) {
01927             nextnonce = apr_pstrcat(r->pool, ", nextnonce=\"",
01928                                    gen_nonce(r->pool, r->request_time,
01929                                              resp->opaque, r->server, conf),
01930                                    "\"", NULL);
01931             if (resp->client)
01932                 resp->client->nonce_count = 0;
01933         }
01934     }
01935     else if (conf->nonce_lifetime == 0 && resp->client) {
01936         const char *nonce = gen_nonce(r->pool, 0, resp->opaque, r->server,
01937                                       conf);
01938         nextnonce = apr_pstrcat(r->pool, ", nextnonce=\"", nonce, "\"", NULL);
01939         memcpy(resp->client->last_nonce, nonce, NONCE_LEN+1);
01940     }
01941     /* else nonce never expires, hence no nextnonce */
01942 
01943 
01944     /* do rfc-2069 digest
01945      */
01946     if (conf->qop_list[0] && !strcasecmp(conf->qop_list[0], "none")
01947         && resp->message_qop == NULL) {
01948         /* use only RFC-2069 format */
01949         if (digest) {
01950             ai = apr_pstrcat(r->pool, "digest=\"", digest, "\"", nextnonce,NULL);
01951         }
01952         else {
01953             ai = nextnonce;
01954         }
01955     }
01956     else {
01957         const char *resp_dig, *ha1, *a2, *ha2;
01958 
01959         /* calculate rspauth attribute
01960          */
01961         if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess")) {
01962             ha1 = get_session_HA1(r, resp, conf, 0);
01963             if (!ha1) {
01964                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01965                               "Digest: internal error: couldn't find session "
01966                               "info for user %s", resp->username);
01967                 return !OK;
01968             }
01969         }
01970         else {
01971             ha1 = conf->ha1;
01972         }
01973 
01974         if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int")) {
01975             a2 = apr_pstrcat(r->pool, ":", resp->uri, ":",
01976                              ap_md5(r->pool,(const unsigned char *) ""), NULL);
01977                              /* TBD */
01978         }
01979         else {
01980             a2 = apr_pstrcat(r->pool, ":", resp->uri, NULL);
01981         }
01982         ha2 = ap_md5(r->pool, (const unsigned char *)a2);
01983 
01984         resp_dig = ap_md5(r->pool,
01985                           (unsigned char *)apr_pstrcat(r->pool, ha1, ":",
01986                                                        resp->nonce, ":",
01987                                                        resp->nonce_count, ":",
01988                                                        resp->cnonce, ":",
01989                                                        resp->message_qop ?
01990                                                          resp->message_qop : "",
01991                                                        ":", ha2, NULL));
01992 
01993         /* assemble Authentication-Info header
01994          */
01995         ai = apr_pstrcat(r->pool,
01996                          "rspauth=\"", resp_dig, "\"",
01997                          nextnonce,
01998                          resp->cnonce ? ", cnonce=\"" : "",
01999                          resp->cnonce
02000                            ? ap_escape_quotes(r->pool, resp->cnonce)
02001                            : "",
02002                          resp->cnonce ? "\"" : "",
02003                          resp->nonce_count ? ", nc=" : "",
02004                          resp->nonce_count ? resp->nonce_count : "",
02005                          resp->message_qop ? ", qop=" : "",
02006                          resp->message_qop ? resp->message_qop : "",
02007                          digest ? "digest=\"" : "",
02008                          digest ? digest : "",
02009                          digest ? "\"" : "",
02010                          NULL);
02011     }
02012 
02013     if (ai && ai[0]) {
02014         apr_table_mergen(r->headers_out,
02015                          (PROXYREQ_PROXY == r->proxyreq)
02016                              ? "Proxy-Authentication-Info"
02017                              : "Authentication-Info",
02018                          ai);
02019     }
02020 
02021     return OK;
02022 }

static const char* add_authn_provider cmd_parms cmd,
void *  config,
const char *  arg
[static]
 

Definition at line 444 of file mod_auth_digest.c.

References apr_pcalloc, AUTHN_PROVIDER_GROUP, conf, authn_provider::get_realm_hash, last, authn_provider_list::next, NULL, cmd_parms_struct::pool, authn_provider_list::provider, authn_provider_list::provider_name, and digest_config_struct::providers.

00446 {
00447     digest_config_rec *conf = (digest_config_rec*)config;
00448     authn_provider_list *newp;
00449 
00450     newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list));
00451     newp->provider_name = apr_pstrdup(cmd->pool, arg);
00452 
00453     /* lookup and cache the actual provider now */
00454     newp->provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP,
00455                                         newp->provider_name, "0");
00456 
00457     if (newp->provider == NULL) {
00458        /* by the time they use it, the provider should be loaded and
00459            registered with us. */
00460         return apr_psprintf(cmd->pool,
00461                             "Unknown Authn provider: %s",
00462                             newp->provider_name);
00463     }
00464 
00465     if (!newp->provider->get_realm_hash) {
00466         /* if it doesn't provide the appropriate function, reject it */
00467         return apr_psprintf(cmd->pool,
00468                             "The '%s' Authn provider doesn't support "
00469                             "Digest Authentication", newp->provider_name);
00470     }
00471 
00472     /* Add it to the list now. */
00473     if (!conf->providers) {
00474         conf->providers = newp;
00475     }
00476     else {
00477         authn_provider_list *last = conf->providers;
00478 
00479         while (last->next) {
00480             last = last->next;
00481         }
00482         last->next = newp;
00483     }
00484 
00485     return NULL;
00486 }

static client_entry* add_client unsigned long  key,
client_entry info,
server_rec s
[static]
 

Definition at line 795 of file mod_auth_digest.c.

References APLOG_DEBUG, APLOG_INFO, APLOG_MARK, bucket, entry, gc(), hash_entry::key, hash_entry::next, and NULL.

Referenced by gen_client().

00797 {
00798     int bucket;
00799     client_entry *entry;
00800 
00801 
00802     if (!key || !client_shm) {
00803         return NULL;
00804     }
00805 
00806     bucket = key % client_list->tbl_len;
00807     entry  = client_list->table[bucket];
00808 
00809     apr_global_mutex_lock(client_lock);
00810 
00811     /* try to allocate a new entry */
00812 
00813     entry = (client_entry *)apr_rmm_malloc(client_rmm, sizeof(client_entry));
00814     if (!entry) {
00815         long num_removed = gc();
00816         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
00817                      "Digest: gc'd %ld client entries. Total new clients: "
00818                      "%ld; Total removed clients: %ld; Total renewed clients: "
00819                      "%ld", num_removed,
00820                      client_list->num_created - client_list->num_renewed,
00821                      client_list->num_removed, client_list->num_renewed);
00822         entry = (client_entry *)apr_rmm_malloc(client_rmm, sizeof(client_entry));
00823         if (!entry) {
00824             return NULL;       /* give up */
00825         }
00826     }
00827 
00828     /* now add the entry */
00829 
00830     memcpy(entry, info, sizeof(client_entry));
00831     entry->key  = key;
00832     entry->next = client_list->table[bucket];
00833     client_list->table[bucket] = entry;
00834     client_list->num_created++;
00835     client_list->num_entries++;
00836 
00837     apr_global_mutex_unlock(client_lock);
00838 
00839     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
00840                  "allocated new client %lu", key);
00841 
00842     return entry;
00843 }

static int authenticate_digest_user request_rec r  )  [static]
 

Definition at line 1583 of file mod_auth_digest.c.

References digest_header_struct::algorithm, request_rec::ap_auth_type, ap_default_port, ap_get_module_config, APLOG_ERR, APLOG_INFO, APLOG_MARK, APR_SUCCESS, AUTH_DENIED, auth_digest_module, digest_header_struct::auth_hdr_sts, AUTH_USER_FOUND, AUTH_USER_NOT_FOUND, check_nc(), check_nonce(), conf, copy_uri_components(), DECLINED, digest_header_struct::digest, get_hash(), digest_config_struct::ha1, apr_uri_t::hostinfo, apr_uri_t::hostname, HTTP_BAD_REQUEST, HTTP_INTERNAL_SERVER_ERROR, HTTP_UNAUTHORIZED, INVALID, M_CONNECT, request_rec::main, match(), digest_header_struct::message_qop, request_rec::method_number, digest_header_struct::needed_auth, new_digest(), NOT_DIGEST, note_digest_auth_failure(), NULL, OK, old_digest(), digest_header_struct::opaque, digest_header_struct::opaque_num, apr_uri_t::path, request_rec::per_dir_config, request_rec::pool, apr_uri_t::port, apr_uri_t::port_str, request_rec::prev, digest_header_struct::psd_request_uri, digest_config_struct::qop_list, apr_uri_t::query, digest_header_struct::raw_request_uri, digest_config_struct::realm, digest_header_struct::realm, request_rec::request_config, res, digest_header_struct::scheme, strcasecmp(), request_rec::subprocess_env, t, digest_header_struct::uri, request_rec::uri, request_rec::user, digest_header_struct::username, and VALID.

Referenced by register_hooks().

01584 {
01585     digest_config_rec *conf;
01586     digest_header_rec *resp;
01587     request_rec       *mainreq;
01588     const char        *t;
01589     int                res;
01590     authn_status       return_code;
01591 
01592     /* do we require Digest auth for this URI? */
01593 
01594     if (!(t = ap_auth_type(r)) || strcasecmp(t, "Digest")) {
01595         return DECLINED;
01596     }
01597 
01598     if (!ap_auth_name(r)) {
01599         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01600                       "Digest: need AuthName: %s", r->uri);
01601         return HTTP_INTERNAL_SERVER_ERROR;
01602     }
01603 
01604 
01605     /* get the client response and mark */
01606 
01607     mainreq = r;
01608     while (mainreq->main != NULL) {
01609         mainreq = mainreq->main;
01610     }
01611     while (mainreq->prev != NULL) {
01612         mainreq = mainreq->prev;
01613     }
01614     resp = (digest_header_rec *) ap_get_module_config(mainreq->request_config,
01615                                                       &auth_digest_module);
01616     resp->needed_auth = 1;
01617 
01618 
01619     /* get our conf */
01620 
01621     conf = (digest_config_rec *) ap_get_module_config(r->per_dir_config,
01622                                                       &auth_digest_module);
01623 
01624 
01625     /* check for existence and syntax of Auth header */
01626 
01627     if (resp->auth_hdr_sts != VALID) {
01628         if (resp->auth_hdr_sts == NOT_DIGEST) {
01629             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01630                           "Digest: client used wrong authentication scheme "
01631                           "`%s': %s", resp->scheme, r->uri);
01632         }
01633         else if (resp->auth_hdr_sts == INVALID) {
01634             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01635                           "Digest: missing user, realm, nonce, uri, digest, "
01636                           "cnonce, or nonce_count in authorization header: %s",
01637                           r->uri);
01638         }
01639         /* else (resp->auth_hdr_sts == NO_HEADER) */
01640         note_digest_auth_failure(r, conf, resp, 0);
01641         return HTTP_UNAUTHORIZED;
01642     }
01643 
01644     r->user         = (char *) resp->username;
01645     r->ap_auth_type = (char *) "Digest";
01646 
01647     /* check the auth attributes */
01648 
01649     if (strcmp(resp->uri, resp->raw_request_uri)) {
01650         /* Hmm, the simple match didn't work (probably a proxy modified the
01651          * request-uri), so lets do a more sophisticated match
01652          */
01653         apr_uri_t r_uri, d_uri;
01654 
01655         copy_uri_components(&r_uri, resp->psd_request_uri, r);
01656         if (apr_uri_parse(r->pool, resp->uri, &d_uri) != APR_SUCCESS) {
01657             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01658                           "Digest: invalid uri <%s> in Authorization header",
01659                           resp->uri);
01660             return HTTP_BAD_REQUEST;
01661         }
01662 
01663         if (d_uri.hostname) {
01664             ap_unescape_url(d_uri.hostname);
01665         }
01666         if (d_uri.path) {
01667             ap_unescape_url(d_uri.path);
01668         }
01669 
01670         if (d_uri.query) {
01671             ap_unescape_url(d_uri.query);
01672         }
01673         else if (r_uri.query) {
01674             /* MSIE compatibility hack.  MSIE has some RFC issues - doesn't
01675              * include the query string in the uri Authorization component
01676              * or when computing the response component.  the second part
01677              * works out ok, since we can hash the header and get the same
01678              * result.  however, the uri from the request line won't match
01679              * the uri Authorization component since the header lacks the
01680              * query string, leaving us incompatable with a (broken) MSIE.
01681              *
01682              * the workaround is to fake a query string match if in the proper
01683              * environment - BrowserMatch MSIE, for example.  the cool thing
01684              * is that if MSIE ever fixes itself the simple match ought to
01685              * work and this code won't be reached anyway, even if the
01686              * environment is set.
01687              */
01688 
01689             if (apr_table_get(r->subprocess_env,
01690                               "AuthDigestEnableQueryStringHack")) {
01691 
01692                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Digest: "
01693                               "applying AuthDigestEnableQueryStringHack "
01694                               "to uri <%s>", resp->raw_request_uri);
01695 
01696                d_uri.query = r_uri.query;
01697             }
01698         }
01699 
01700         if (r->method_number == M_CONNECT) {
01701             if (!r_uri.hostinfo || strcmp(resp->uri, r_uri.hostinfo)) {
01702                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01703                               "Digest: uri mismatch - <%s> does not match "
01704                               "request-uri <%s>", resp->uri, r_uri.hostinfo);
01705                 return HTTP_BAD_REQUEST;
01706             }
01707         }
01708         else if (
01709             /* check hostname matches, if present */
01710             (d_uri.hostname && d_uri.hostname[0] != '\0'
01711               && strcasecmp(d_uri.hostname, r_uri.hostname))
01712             /* check port matches, if present */
01713             || (d_uri.port_str && d_uri.port != r_uri.port)
01714             /* check that server-port is default port if no port present */
01715             || (d_uri.hostname && d_uri.hostname[0] != '\0'
01716                 && !d_uri.port_str && r_uri.port != ap_default_port(r))
01717             /* check that path matches */
01718             || (d_uri.path != r_uri.path
01719                 /* either exact match */
01720                 && (!d_uri.path || !r_uri.path
01721                     || strcmp(d_uri.path, r_uri.path))
01722                 /* or '*' matches empty path in scheme://host */
01723                 && !(d_uri.path && !r_uri.path && resp->psd_request_uri->hostname
01724                     && d_uri.path[0] == '*' && d_uri.path[1] == '\0'))
01725             /* check that query matches */
01726             || (d_uri.query != r_uri.query
01727                 && (!d_uri.query || !r_uri.query
01728                     || strcmp(d_uri.query, r_uri.query)))
01729             ) {
01730             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01731                           "Digest: uri mismatch - <%s> does not match "
01732                           "request-uri <%s>", resp->uri, resp->raw_request_uri);
01733             return HTTP_BAD_REQUEST;
01734         }
01735     }
01736 
01737     if (resp->opaque && resp->opaque_num == 0) {
01738         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01739                       "Digest: received invalid opaque - got `%s'",
01740                       resp->opaque);
01741         note_digest_auth_failure(r, conf, resp, 0);
01742         return HTTP_UNAUTHORIZED;
01743     }
01744 
01745     if (strcmp(resp->realm, conf->realm)) {
01746         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01747                       "Digest: realm mismatch - got `%s' but expected `%s'",
01748                       resp->realm, conf->realm);
01749         note_digest_auth_failure(r, conf, resp, 0);
01750         return HTTP_UNAUTHORIZED;
01751     }
01752 
01753     if (resp->algorithm != NULL
01754         && strcasecmp(resp->algorithm, "MD5")
01755         && strcasecmp(resp->algorithm, "MD5-sess")) {
01756         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01757                       "Digest: unknown algorithm `%s' received: %s",
01758                       resp->algorithm, r->uri);
01759         note_digest_auth_failure(r, conf, resp, 0);
01760         return HTTP_UNAUTHORIZED;
01761     }
01762 
01763     return_code = get_hash(r, r->user, conf);
01764 
01765     if (return_code == AUTH_USER_NOT_FOUND) {
01766         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01767                       "Digest: user `%s' in realm `%s' not found: %s",
01768                       r->user, conf->realm, r->uri);
01769         note_digest_auth_failure(r, conf, resp, 0);
01770         return HTTP_UNAUTHORIZED;
01771     }
01772     else if (return_code == AUTH_USER_FOUND) {
01773         /* we have a password, so continue */
01774     }
01775     else if (return_code == AUTH_DENIED) {
01776         /* authentication denied in the provider before attempting a match */
01777         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01778                       "Digest: user `%s' in realm `%s' denied by provider: %s",
01779                       r->user, conf->realm, r->uri);
01780         note_digest_auth_failure(r, conf, resp, 0);
01781         return HTTP_UNAUTHORIZED;
01782     }
01783     else {
01784         /* AUTH_GENERAL_ERROR (or worse)
01785          * We'll assume that the module has already said what its error
01786          * was in the logs.
01787          */
01788         return HTTP_INTERNAL_SERVER_ERROR;
01789     }
01790 
01791     if (resp->message_qop == NULL) {
01792         /* old (rfc-2069) style digest */
01793         if (strcmp(resp->digest, old_digest(r, resp, conf->ha1))) {
01794             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01795                           "Digest: user %s: password mismatch: %s", r->user,
01796                           r->uri);
01797             note_digest_auth_failure(r, conf, resp, 0);
01798             return HTTP_UNAUTHORIZED;
01799         }
01800     }
01801     else {
01802         const char *exp_digest;
01803         int match = 0, idx;
01804         for (idx = 0; conf->qop_list[idx] != NULL; idx++) {
01805             if (!strcasecmp(conf->qop_list[idx], resp->message_qop)) {
01806                 match = 1;
01807                 break;
01808             }
01809         }
01810 
01811         if (!match
01812             && !(conf->qop_list[0] == NULL
01813                  && !strcasecmp(resp->message_qop, "auth"))) {
01814             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01815                           "Digest: invalid qop `%s' received: %s",
01816                           resp->message_qop, r->uri);
01817             note_digest_auth_failure(r, conf, resp, 0);
01818             return HTTP_UNAUTHORIZED;
01819         }
01820 
01821         exp_digest = new_digest(r, resp, conf);
01822         if (!exp_digest) {
01823             /* we failed to allocate a client struct */
01824             return HTTP_INTERNAL_SERVER_ERROR;
01825         }
01826         if (strcmp(resp->digest, exp_digest)) {
01827             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
01828                           "Digest: user %s: password mismatch: %s", r->user,
01829                           r->uri);
01830             note_digest_auth_failure(r, conf, resp, 0);
01831             return HTTP_UNAUTHORIZED;
01832         }
01833     }
01834 
01835     if (check_nc(r, resp, conf) != OK) {
01836         note_digest_auth_failure(r, conf, resp, 0);
01837         return HTTP_UNAUTHORIZED;
01838     }
01839 
01840     /* Note: this check is done last so that a "stale=true" can be
01841        generated if the nonce is old */
01842     if ((res = check_nonce(r, resp, conf))) {
01843         return res;
01844     }
01845 
01846     return OK;
01847 }

static int check_nc const request_rec r,
const digest_header_rec resp,
const digest_config_rec conf
[static]
 

Definition at line 1377 of file mod_auth_digest.c.

References APLOG_ERR, APLOG_MARK, apr_isspace, digest_c