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