1a73f3
diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c
1a73f3
index cbb4434..b50bcf9 100644
1a73f3
--- a/modules/aaa/mod_auth_digest.c
1a73f3
+++ b/modules/aaa/mod_auth_digest.c
1a73f3
@@ -26,20 +26,13 @@
1a73f3
  * reports to the Apache bug-database, or send them directly to me
1a73f3
  * at ronald@innovation.ch.
1a73f3
  *
1a73f3
- * Requires either /dev/random (or equivalent) or the truerand library,
1a73f3
- * available for instance from
1a73f3
- * ftp://research.att.com/dist/mab/librand.shar
1a73f3
- *
1a73f3
  * Open Issues:
1a73f3
  *   - qop=auth-int (when streams and trailer support available)
1a73f3
  *   - nonce-format configurability
1a73f3
  *   - Proxy-Authorization-Info header is set by this module, but is
1a73f3
  *     currently ignored by mod_proxy (needs patch to mod_proxy)
1a73f3
- *   - generating the secret takes a while (~ 8 seconds) if using the
1a73f3
- *     truerand library
1a73f3
  *   - The source of the secret should be run-time directive (with server
1a73f3
- *     scope: RSRC_CONF). However, that could be tricky when trying to
1a73f3
- *     choose truerand vs. file...
1a73f3
+ *     scope: RSRC_CONF)
1a73f3
  *   - shared-mem not completely tested yet. Seems to work ok for me,
1a73f3
  *     but... (definitely won't work on Windoze)
1a73f3
  *   - Sharing a realm among multiple servers has following problems:
1a73f3
@@ -52,6 +45,8 @@
1a73f3
  *       captures a packet sent to one server and sends it to another
1a73f3
  *       one. Should we add "AuthDigestNcCheck Strict"?
1a73f3
  *   - expired nonces give amaya fits.
1a73f3
+ *   - MD5-sess and auth-int are not yet implemented. An incomplete
1a73f3
+ *     implementation has been removed and can be retrieved from svn history.
1a73f3
  */
1a73f3
 
1a73f3
 #include "apr_sha1.h"
1a73f3
@@ -94,7 +89,6 @@ typedef struct digest_config_struct {
1a73f3
     apr_array_header_t *qop_list;
1a73f3
     apr_sha1_ctx_t  nonce_ctx;
1a73f3
     apr_time_t    nonce_lifetime;
1a73f3
-    const char  *nonce_format;
1a73f3
     int          check_nc;
1a73f3
     const char  *algorithm;
1a73f3
     char        *uri_list;
1a73f3
@@ -112,7 +106,8 @@ typedef struct digest_config_struct {
1a73f3
 #define NONCE_HASH_LEN  (2*APR_SHA1_DIGESTSIZE)
1a73f3
 #define NONCE_LEN       (int )(NONCE_TIME_LEN + NONCE_HASH_LEN)
1a73f3
 
1a73f3
-#define SECRET_LEN      20
1a73f3
+#define SECRET_LEN          20
1a73f3
+#define RETAINED_DATA_ID    "mod_auth_digest"
1a73f3
 
1a73f3
 
1a73f3
 /* client list definitions */
1a73f3
@@ -121,7 +116,6 @@ typedef struct hash_entry {
1a73f3
     unsigned long      key;                     /* the key for this entry    */
1a73f3
     struct hash_entry *next;                    /* next entry in the bucket  */
1a73f3
     unsigned long      nonce_count;             /* for nonce-count checking  */
1a73f3
-    char               ha1[2*APR_MD5_DIGESTSIZE+1]; /* for algorithm=MD5-sess    */
1a73f3
     char               last_nonce[NONCE_LEN+1]; /* for one-time nonce's      */
1a73f3
 } client_entry;
1a73f3
 
1a73f3
@@ -170,7 +164,7 @@ typedef union time_union {
1a73f3
     unsigned char arr[sizeof(apr_time_t)];
1a73f3
 } time_rec;
1a73f3
 
1a73f3
-static unsigned char secret[SECRET_LEN];
1a73f3
+static unsigned char *secret;
1a73f3
 
1a73f3
 /* client-list, opaque, and one-time-nonce stuff */
1a73f3
 
1a73f3
@@ -228,35 +222,11 @@ static apr_status_t cleanup_tables(void *not_used)
1a73f3
     return APR_SUCCESS;
1a73f3
 }
1a73f3
 
1a73f3
-static apr_status_t initialize_secret(server_rec *s)
1a73f3
-{
1a73f3
-    apr_status_t status;
1a73f3
-
1a73f3
-    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(01757)
1a73f3
-                 "generating secret for digest authentication ...");
1a73f3
-
1a73f3
-#if APR_HAS_RANDOM
1a73f3
-    status = apr_generate_random_bytes(secret, sizeof(secret));
1a73f3
-#else
1a73f3
-#error APR random number support is missing; you probably need to install the truerand library.
1a73f3
-#endif
1a73f3
-
1a73f3
-    if (status != APR_SUCCESS) {
1a73f3
-        ap_log_error(APLOG_MARK, APLOG_CRIT, status, s, APLOGNO(01758)
1a73f3
-                     "error generating secret");
1a73f3
-        return status;
1a73f3
-    }
1a73f3
-
1a73f3
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01759) "done");
1a73f3
-
1a73f3
-    return APR_SUCCESS;
1a73f3
-}
1a73f3
-
1a73f3
 static void log_error_and_cleanup(char *msg, apr_status_t sts, server_rec *s)
1a73f3
 {
1a73f3
     ap_log_error(APLOG_MARK, APLOG_ERR, sts, s, APLOGNO(01760)
1a73f3
-                 "%s - all nonce-count checking, one-time nonces, and "
1a73f3
-                 "MD5-sess algorithm disabled", msg);
1a73f3
+                 "%s - all nonce-count checking and one-time nonces"
1a73f3
+                 "disabled", msg);
1a73f3
 
1a73f3
     cleanup_tables(NULL);
1a73f3
 }
1a73f3
@@ -377,16 +347,32 @@ static int initialize_tables(server_rec *s, apr_pool_t *ctx)
1a73f3
 static int pre_init(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
1a73f3
 {
1a73f3
     apr_status_t rv;
1a73f3
+    void *retained;
1a73f3
 
1a73f3
     rv = ap_mutex_register(pconf, client_mutex_type, NULL, APR_LOCK_DEFAULT, 0);
1a73f3
-    if (rv == APR_SUCCESS) {
1a73f3
-        rv = ap_mutex_register(pconf, opaque_mutex_type, NULL, APR_LOCK_DEFAULT,
1a73f3
-                               0);
1a73f3
-    }
1a73f3
-    if (rv != APR_SUCCESS) {
1a73f3
-        return rv;
1a73f3
-    }
1a73f3
+    if (rv != APR_SUCCESS)
1a73f3
+        return !OK;
1a73f3
+    rv = ap_mutex_register(pconf, opaque_mutex_type, NULL, APR_LOCK_DEFAULT, 0);
1a73f3
+    if (rv != APR_SUCCESS)
1a73f3
+        return !OK;
1a73f3
 
1a73f3
+    retained = ap_retained_data_get(RETAINED_DATA_ID);
1a73f3
+    if (retained == NULL) {
1a73f3
+        retained = ap_retained_data_create(RETAINED_DATA_ID, SECRET_LEN);
1a73f3
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(01757)
1a73f3
+                     "generating secret for digest authentication");
1a73f3
+#if APR_HAS_RANDOM
1a73f3
+        rv = apr_generate_random_bytes(retained, SECRET_LEN);
1a73f3
+#else
1a73f3
+#error APR random number support is missing
1a73f3
+#endif
1a73f3
+        if (rv != APR_SUCCESS) {
1a73f3
+            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(01758)
1a73f3
+                         "error generating secret");
1a73f3
+            return !OK;
1a73f3
+        }
1a73f3
+    }
1a73f3
+    secret = retained;
1a73f3
     return OK;
1a73f3
 }
1a73f3
 
1a73f3
@@ -399,10 +385,6 @@ static int initialize_module(apr_pool_t *p, apr_pool_t *plog,
1a73f3
     if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG)
1a73f3
         return OK;
1a73f3
 
1a73f3
-    if (initialize_secret(s) != APR_SUCCESS) {
1a73f3
-        return !OK;
1a73f3
-    }
1a73f3
-
1a73f3
 #if APR_HAS_SHARED_MEMORY
1a73f3
     /* Note: this stuff is currently fixed for the lifetime of the server,
1a73f3
      * i.e. even across restarts. This means that A) any shmem-size
1a73f3
@@ -483,6 +465,16 @@ static void *create_digest_dir_config(apr_pool_t *p, char *dir)
1a73f3
 static const char *set_realm(cmd_parms *cmd, void *config, const char *realm)
1a73f3
 {
1a73f3
     digest_config_rec *conf = (digest_config_rec *) config;
1a73f3
+#ifdef AP_DEBUG
1a73f3
+    int i;
1a73f3
+
1a73f3
+    /* check that we got random numbers */
1a73f3
+    for (i = 0; i < SECRET_LEN; i++) {
1a73f3
+        if (secret[i] != 0)
1a73f3
+            break;
1a73f3
+    }
1a73f3
+    ap_assert(i < SECRET_LEN);
1a73f3
+#endif
1a73f3
 
1a73f3
     /* The core already handles the realm, but it's just too convenient to
1a73f3
      * grab it ourselves too and cache some setups. However, we need to
1a73f3
@@ -496,7 +488,7 @@ static const char *set_realm(cmd_parms *cmd, void *config, const char *realm)
1a73f3
      * and directives outside a virtual host section)
1a73f3
      */
1a73f3
     apr_sha1_init(&conf->nonce_ctx);
1a73f3
-    apr_sha1_update_binary(&conf->nonce_ctx, secret, sizeof(secret));
1a73f3
+    apr_sha1_update_binary(&conf->nonce_ctx, secret, SECRET_LEN);
1a73f3
     apr_sha1_update_binary(&conf->nonce_ctx, (const unsigned char *) realm,
1a73f3
                            strlen(realm));
1a73f3
 
1a73f3
@@ -590,8 +582,7 @@ static const char *set_nonce_lifetime(cmd_parms *cmd, void *config,
1a73f3
 static const char *set_nonce_format(cmd_parms *cmd, void *config,
1a73f3
                                     const char *fmt)
1a73f3
 {
1a73f3
-    ((digest_config_rec *) config)->nonce_format = fmt;
1a73f3
-    return "AuthDigestNonceFormat is not implemented (yet)";
1a73f3
+    return "AuthDigestNonceFormat is not implemented";
1a73f3
 }
1a73f3
 
1a73f3
 static const char *set_nc_check(cmd_parms *cmd, void *config, int flag)
1a73f3
@@ -612,7 +603,7 @@ static const char *set_algorithm(cmd_parms *cmd, void *config, const char *alg)
1a73f3
 {
1a73f3
     if (!strcasecmp(alg, "MD5-sess")) {
1a73f3
         return "AuthDigestAlgorithm: ERROR: algorithm `MD5-sess' "
1a73f3
-                "is not fully implemented";
1a73f3
+                "is not implemented";
1a73f3
     }
1a73f3
     else if (strcasecmp(alg, "MD5")) {
1a73f3
         return apr_pstrcat(cmd->pool, "Invalid algorithm in AuthDigestAlgorithm: ", alg, NULL);
1a73f3
@@ -1138,7 +1129,7 @@ static const char *gen_nonce(apr_pool_t *p, apr_time_t now, const char *opaque,
1a73f3
 static client_entry *gen_client(const request_rec *r)
1a73f3
 {
1a73f3
     unsigned long op;
1a73f3
-    client_entry new_entry = { 0, NULL, 0, "", "" }, *entry;
1a73f3
+    client_entry new_entry = { 0, NULL, 0, "" }, *entry;
1a73f3
 
1a73f3
     if (!opaque_cntr) {
1a73f3
         return NULL;
1a73f3
@@ -1158,92 +1149,6 @@ static client_entry *gen_client(const request_rec *r)
1a73f3
 }
1a73f3
 
1a73f3
 
1a73f3
-/*
1a73f3
- * MD5-sess code.
1a73f3
- *
1a73f3
- * If you want to use algorithm=MD5-sess you must write get_userpw_hash()
1a73f3
- * yourself (see below). The dummy provided here just uses the hash from
1a73f3
- * the auth-file, i.e. it is only useful for testing client implementations
1a73f3
- * of MD5-sess .
1a73f3
- */
1a73f3
-
1a73f3
-/*
1a73f3
- * get_userpw_hash() will be called each time a new session needs to be
1a73f3
- * generated and is expected to return the equivalent of
1a73f3
- *
1a73f3
- * h_urp = ap_md5(r->pool,
1a73f3
- *         apr_pstrcat(r->pool, username, ":", ap_auth_name(r), ":", passwd))
1a73f3
- * ap_md5(r->pool,
1a73f3
- *         (unsigned char *) apr_pstrcat(r->pool, h_urp, ":", resp->nonce, ":",
1a73f3
- *                                      resp->cnonce, NULL));
1a73f3
- *
1a73f3
- * or put differently, it must return
1a73f3
- *
1a73f3
- *   MD5(MD5(username ":" realm ":" password) ":" nonce ":" cnonce)
1a73f3
- *
1a73f3
- * If something goes wrong, the failure must be logged and NULL returned.
1a73f3
- *
1a73f3
- * You must implement this yourself, which will probably consist of code
1a73f3
- * contacting the password server with the necessary information (typically
1a73f3
- * the username, realm, nonce, and cnonce) and receiving the hash from it.
1a73f3
- *
1a73f3
- * TBD: This function should probably be in a separate source file so that
1a73f3
- * people need not modify mod_auth_digest.c each time they install a new
1a73f3
- * version of apache.
1a73f3
- */
1a73f3
-static const char *get_userpw_hash(const request_rec *r,
1a73f3
-                                   const digest_header_rec *resp,
1a73f3
-                                   const digest_config_rec *conf)
1a73f3
-{
1a73f3
-    return ap_md5(r->pool,
1a73f3
-             (unsigned char *) apr_pstrcat(r->pool, conf->ha1, ":", resp->nonce,
1a73f3
-                                           ":", resp->cnonce, NULL));
1a73f3
-}
1a73f3
-
1a73f3
-
1a73f3
-/* Retrieve current session H(A1). If there is none and "generate" is
1a73f3
- * true then a new session for MD5-sess is generated and stored in the
1a73f3
- * client struct; if generate is false, or a new session could not be
1a73f3
- * generated then NULL is returned (in case of failure to generate the
1a73f3
- * failure reason will have been logged already).
1a73f3
- */
1a73f3
-static const char *get_session_HA1(const request_rec *r,
1a73f3
-                                   digest_header_rec *resp,
1a73f3
-                                   const digest_config_rec *conf,
1a73f3
-                                   int generate)
1a73f3
-{
1a73f3
-    const char *ha1 = NULL;
1a73f3
-
1a73f3
-    /* return the current sessions if there is one */
1a73f3
-    if (resp->opaque && resp->client && resp->client->ha1[0]) {
1a73f3
-        return resp->client->ha1;
1a73f3
-    }
1a73f3
-    else if (!generate) {
1a73f3
-        return NULL;
1a73f3
-    }
1a73f3
-
1a73f3
-    /* generate a new session */
1a73f3
-    if (!resp->client) {
1a73f3
-        resp->client = gen_client(r);
1a73f3
-    }
1a73f3
-    if (resp->client) {
1a73f3
-        ha1 = get_userpw_hash(r, resp, conf);
1a73f3
-        if (ha1) {
1a73f3
-            memcpy(resp->client->ha1, ha1, sizeof(resp->client->ha1));
1a73f3
-        }
1a73f3
-    }
1a73f3
-
1a73f3
-    return ha1;
1a73f3
-}
1a73f3
-
1a73f3
-
1a73f3
-static void clear_session(const digest_header_rec *resp)
1a73f3
-{
1a73f3
-    if (resp->client) {
1a73f3
-        resp->client->ha1[0] = '\0';
1a73f3
-    }
1a73f3
-}
1a73f3
-
1a73f3
 /*
1a73f3
  * Authorization challenge generation code (for WWW-Authenticate)
1a73f3
  */
1a73f3
@@ -1282,8 +1187,7 @@ static void note_digest_auth_failure(request_rec *r,
1a73f3
 
1a73f3
     if (resp->opaque == NULL) {
1a73f3
         /* new client */
1a73f3
-        if ((conf->check_nc || conf->nonce_lifetime == 0
1a73f3
-             || !strcasecmp(conf->algorithm, "MD5-sess"))
1a73f3
+        if ((conf->check_nc || conf->nonce_lifetime == 0)
1a73f3
             && (resp->client = gen_client(r)) != NULL) {
1a73f3
             opaque = ltox(r->pool, resp->client->key);
1a73f3
         }
1a73f3
@@ -1323,15 +1227,6 @@ static void note_digest_auth_failure(request_rec *r,
1a73f3
         memcpy(resp->client->last_nonce, nonce, NONCE_LEN+1);
1a73f3
     }
1a73f3
 
1a73f3
-    /* Setup MD5-sess stuff. Note that we just clear out the session
1a73f3
-     * info here, since we can't generate a new session until the request
1a73f3
-     * from the client comes in with the cnonce.
1a73f3
-     */
1a73f3
-
1a73f3
-    if (!strcasecmp(conf->algorithm, "MD5-sess")) {
1a73f3
-        clear_session(resp);
1a73f3
-    }
1a73f3
-
1a73f3
     /* setup domain attribute. We want to send this attribute wherever
1a73f3
      * possible so that the client won't send the Authorization header
1a73f3
      * unnecessarily (it's usually > 200 bytes!).
1a73f3
@@ -1597,24 +1492,9 @@ static const char *new_digest(const request_rec *r,
1a73f3
 {
1a73f3
     const char *ha1, *ha2, *a2;
1a73f3
 
1a73f3
-    if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess")) {
1a73f3
-        ha1 = get_session_HA1(r, resp, conf, 1);
1a73f3
-        if (!ha1) {
1a73f3
-            return NULL;
1a73f3
-        }
1a73f3
-    }
1a73f3
-    else {
1a73f3
-        ha1 = conf->ha1;
1a73f3
-    }
1a73f3
+    ha1 = conf->ha1;
1a73f3
 
1a73f3
-    if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int")) {
1a73f3
-        a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, ":",
1a73f3
-                         ap_md5(r->pool, (const unsigned char*) ""), NULL);
1a73f3
-                         /* TBD */
1a73f3
-    }
1a73f3
-    else {
1a73f3
-        a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, NULL);
1a73f3
-    }
1a73f3
+    a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, NULL);
1a73f3
     ha2 = ap_md5(r->pool, (const unsigned char *)a2);
1a73f3
 
1a73f3
     return ap_md5(r->pool,
1a73f3
@@ -1854,8 +1734,7 @@ static int authenticate_digest_user(request_rec *r)
1a73f3
     }
1a73f3
 
1a73f3
     if (resp->algorithm != NULL
1a73f3
-        && strcasecmp(resp->algorithm, "MD5")
1a73f3
-        && strcasecmp(resp->algorithm, "MD5-sess")) {
1a73f3
+        && strcasecmp(resp->algorithm, "MD5")) {
1a73f3
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01789)
1a73f3
                       "unknown algorithm `%s' received: %s",
1a73f3
                       resp->algorithm, r->uri);
1a73f3
@@ -2007,27 +1886,9 @@ static int add_auth_info(request_rec *r)
1a73f3
 
1a73f3
         /* calculate rspauth attribute
1a73f3
          */
1a73f3
-        if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess")) {
1a73f3
-            ha1 = get_session_HA1(r, resp, conf, 0);
1a73f3
-            if (!ha1) {
1a73f3
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01795)
1a73f3
-                              "internal error: couldn't find session "
1a73f3
-                              "info for user %s", resp->username);
1a73f3
-                return !OK;
1a73f3
-            }
1a73f3
-        }
1a73f3
-        else {
1a73f3
-            ha1 = conf->ha1;
1a73f3
-        }
1a73f3
+        ha1 = conf->ha1;
1a73f3
 
1a73f3
-        if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int")) {
1a73f3
-            a2 = apr_pstrcat(r->pool, ":", resp->uri, ":",
1a73f3
-                             ap_md5(r->pool,(const unsigned char *) ""), NULL);
1a73f3
-                             /* TBD */
1a73f3
-        }
1a73f3
-        else {
1a73f3
-            a2 = apr_pstrcat(r->pool, ":", resp->uri, NULL);
1a73f3
-        }
1a73f3
+        a2 = apr_pstrcat(r->pool, ":", resp->uri, NULL);
1a73f3
         ha2 = ap_md5(r->pool, (const unsigned char *)a2);
1a73f3
 
1a73f3
         resp_dig = ap_md5(r->pool,