--- 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); }