--- mod_auth_mysql-3.0.0/mod_auth_mysql.c.digest	2009-05-30 23:01:24.000000000 +0100
+++ mod_auth_mysql-3.0.0/mod_auth_mysql.c	2009-05-31 10:54:43.000000000 +0100
@@ -214,6 +214,8 @@
   #include "apr_sha1.h"
   #include "apr_base64.h"
   #include "apr_lib.h"
+  #include "ap_provider.h"
+  #include "mod_auth.h"
   #define ISSPACE apr_isspace
   #ifdef CRYPT
     #include "crypt.h"
@@ -1016,7 +1018,7 @@
  * If we are in NoPasswd mode, returns user name instead.
  * If user or password not found, returns NULL
  */
-static char * get_mysql_pw(request_rec *r, char *user, mysql_auth_config_rec *m, const char *salt_column, const char ** psalt) {
+static char * get_mysql_pw(request_rec *r, const char *user, mysql_auth_config_rec *m, const char *salt_column, const char ** psalt) {
   MYSQL_RES *result;
   char *pw = NULL;		/* password retrieved */
   char *sql_safe_user = NULL;
@@ -1335,8 +1337,129 @@
 }
 
 #ifdef APACHE2
+/*
+ * callback from Apache to do the authentication of the user to his
+ * password.
+ */
+static authn_status check_password(request_rec *r, const char *user,
+                                   const char *sent_pw)
+{
+  int passwords_match = 0;	/* Assume no match */
+  encryption * enc_data = 0;
+  int i = 0;
+
+  mysql_auth_config_rec *sec =
+    (mysql_auth_config_rec *)ap_get_module_config (r->per_dir_config,
+						   &mysql_auth_module);
+
+  const char *real_pw, *salt = 0, *salt_column = 0;
+
+/* Determine the encryption method */
+  if (sec->mysqlEncryptionField) {
+    for (i = 0; i < sizeof(encryptions) / sizeof(encryptions[0]); i++) {
+      if (strcasecmp(sec->mysqlEncryptionField, encryptions[i].string) == 0) {
+	enc_data = &(encryptions[i]);
+	break;
+      }
+    }
+    if (!enc_data) {  /* Entry was not found in the list */
+      LOG_ERROR_1(APLOG_NOERRNO|APLOG_ERR, 0, r, "mysql invalid encryption method %s", sec->mysqlEncryptionField);
+      ap_note_basic_auth_failure(r);
+      return NOT_AUTHORIZED;
+    }
+  }
+  else
+    enc_data = &encryptions[0];
+
+  if (enc_data->salt_status == NO_SALT || !sec->mysqlSaltField)
+    salt = salt_column = 0;
+  else { 			/* Parse the mysqlSaltField */
+    short salt_length = strlen(sec->mysqlSaltField);
+
+    if (strcasecmp(sec->mysqlSaltField, "<>") == 0) { /* Salt against self */
+      salt = salt_column = 0;
+    } else if (sec->mysqlSaltField[0] == '<' && sec->mysqlSaltField[salt_length-1] == '>') {
+      salt =  PSTRNDUP(r->pool, sec->mysqlSaltField+1, salt_length - 2);
+      salt_column = 0;
+    } else {
+      salt = 0;
+      salt_column = sec->mysqlSaltField;
+    }
+  }
+
+  if (enc_data->salt_status == SALT_REQUIRED && !salt && !salt_column) {
+    LOG_ERROR_1(APLOG_NOERRNO | APLOG_ERR, 0, r, "MySQL Salt field not specified for encryption %s", sec->mysqlEncryptionField);
+    return DECLINED;
+  }
+
+  real_pw = get_mysql_pw(r, user, sec, salt_column, &salt ); /* Get a salt if one was specified */
+
+  if(!real_pw)
+  {
+    /* user not found in database */
+    return AUTH_USER_NOT_FOUND;		/* let other schemes find user */
+  }
+
+  if (!salt)
+    salt = real_pw;
+
+  /* if we don't require password, just return ok since they exist */
+  if (sec->mysqlNoPasswd) {
+    return AUTH_GRANTED;
+  }
+
+  passwords_match = enc_data->func(r->pool, real_pw, sent_pw, salt);
+
+  if(passwords_match) {
+	return AUTH_GRANTED;
+  } else {
+    return AUTH_DENIED;
+  }
+}
+
+static char * digest_md5(POOL * pool, const char * user, const char * realm, const char * password) {
+  int len = strlen(user) + strlen(realm) + strlen(password) + 4;
+  char * a1 = PCALLOC(pool, len);
+  SNPRINTF(a1,len-1,"%s:%s:%s", user, realm, password);
+  return ap_md5(pool, (const unsigned char *) a1);
+}
+
+static authn_status get_realm_hash(request_rec *r, const char *user,
+                                   const char *realm, char **rethash)
+{
+  mysql_auth_config_rec *sec =
+      (mysql_auth_config_rec *)ap_get_module_config (r->per_dir_config,
+  						   &mysql_auth_module);
+  char *real_pw;
+  real_pw = get_mysql_pw(r, user, sec, NULL, NULL ); /* Get a salt if one was specified */
+
+  if(!real_pw)
+  {
+    /* user not found in database */
+    return AUTH_USER_NOT_FOUND;		/* let other schemes find user */
+  }
+
+  if (strcasecmp(sec->mysqlEncryptionField, "none") == 0) {
+    real_pw = digest_md5(r->pool, user, realm, real_pw);
+  }
+
+  *rethash = real_pw;
+
+  return AUTH_USER_FOUND;
+}
+
+static const authn_provider authn_mysql_provider =
+{
+  &check_password,
+  &get_realm_hash,
+};
+
 static void register_hooks(POOL *p)
 {
+	ap_register_provider(p,
+					AUTHN_PROVIDER_GROUP,
+					"mysql", "0",
+					&authn_mysql_provider);
 	ap_hook_check_user_id(mysql_authenticate_basic_user, NULL, NULL, APR_HOOK_MIDDLE);
 	ap_hook_auth_checker(mysql_check_auth, NULL, NULL, APR_HOOK_MIDDLE);
 }
