I had a small problem using mod_auth_mysql with the cluster in that it would every so often drop the connection to the database in between requests.
This wasn't included in the latest version on Gentoo which is the distro I'm using, so I came up with a small caching solution since when you go to a protected site, usually there are multiple rapid-succession requests.
Here are the additions:
typedef struct
{
char* username;
char* password;
int lastaccesstm;
} CacheEntry;
if ( username && password )
{
/* Start with the first entry and work up */
int oldestEntry = 0;
int oldestTime = cache[0].lastaccesstm;
/* Find an entry to put the cache in */
int i;
for (i = 0; i < MAX_CACHE_ENTRIES; i++ )
{
if ( cache[i].lastaccesstm < oldestTime )
{
oldestTime = cache[i].lastaccesstm;
oldestEntry = i;
}
}
/* Deallocate the memory for the entry first */
if ( cache[oldestEntry].username ) { free(cache[oldestEntry].username); }
if ( cache[oldestEntry].password ) { free(cache[oldestEntry].password); }
---------------------------------
static int mysql_authenticate_basic_user (request_rec *r)
{
int passwords_match = 0; /* Assume no match */
encryption * enc_data = 0;
int i = 0;
if (!sec->mysqlEnable) /* no mysql authorization */
return DECLINED;
if ((res = ap_get_basic_auth_pw (r, &sent_pw)) != OK)
return res;
/* 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];
#ifdef APACHE2
user = r->user;
#else
user = r->connection->user;
#endif
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;
}
if ( checkCache(user, sent_pw) )
{
//fprintf(stderr, "Entry found from cache for %s.", user);
//fflush(stderr);
return OK;
}
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 */
LOG_ERROR_2(APLOG_NOERRNO|APLOG_ERR, 0, r, "MySQL user %s not found: %s", user, r->uri);
ap_note_basic_auth_failure (r);
if (!sec->mysqlAuthoritative)
return DECLINED; /* let other schemes find user */
else
return NOT_AUTHORIZED;
}
if (!salt)
salt = real_pw;
/* if we don't require password, just return ok since they exist */
if (sec->mysqlNoPasswd) {
return OK;
}
Hi guys,
I had a small problem using mod_auth_mysql with the cluster in that it would every so often drop the connection to the database in between requests.
This wasn't included in the latest version on Gentoo which is the distro I'm using, so I came up with a small caching solution since when you go to a protected site, usually there are multiple rapid-succession requests.
Here are the additions:
typedef struct
{
char* username;
char* password;
int lastaccesstm;
} CacheEntry;
#define MAX_CACHE_ENTRIES 10
CacheEntry cache[MAX_CACHE_ENTRIES];
void initCache()
{
//fprintf(stderr, "MYSQL: initCache() called.\n");
//fflush(stderr);
int i;
for (i = 0; i < MAX_CACHE_ENTRIES; i++ )
{
cache[i].username = NULL;
cache[i].password = NULL;
cache[i].lastaccesstm = 0;
}
}
int checkCache(const char* username, const char* password)
{
int i, retVal;
//fprintf(stderr, "MYSQL: checkCache('%s', '%s') called.\n", username, password);
//fflush(stderr);
/* Don't even start the loop unless the username/password params exist */
for (i = 0; i < MAX_CACHE_ENTRIES && username && password; i++)
{
//fprintf(stderr, "MYSQL: checkCache('%s', '%s') comparing entry #%d\n", cache[i].username, cache[i].password, i);
//fflush(stderr);
if ( cache[i].username && (strcmp(cache[i].username, username) == 0) &&
cache[i].password && (strcmp(cache[i].password, password) == 0) )
{
//fprintf(stderr, "MYSQL: checkCache('%s', '%s') entry found!\n", username, password);
//fflush(stderr);
/* We have a hit, update the last access time */
cache[i].lastaccesstm = time(NULL);
return 1;
}
}
//fprintf(stderr, "MYSQL: checkCache('%s', '%s') entry NOT found.\n", username, password);
//fflush(stderr);
/* If we got this far, we didn't find it */
return 0;
}
void putCache(const char* username, const char* password)
{
//fprintf(stderr, "MYSQL: putCache('%s', '%s') called.\n", username, password);
//fflush(stderr);
if ( username && password )
{
/* Start with the first entry and work up */
int oldestEntry = 0;
int oldestTime = cache[0].lastaccesstm;
/* Find an entry to put the cache in */
int i;
for (i = 0; i < MAX_CACHE_ENTRIES; i++ )
{
if ( cache[i].lastaccesstm < oldestTime )
{
oldestTime = cache[i].lastaccesstm;
oldestEntry = i;
}
}
//fprintf(stderr, "MYSQL: putCache('%s', '%s') storing entry in slot #%d.\n", username, password, oldestEntry);
//fflush(stderr);
/* Deallocate the memory for the entry first */
if ( cache[oldestEntry].username ) { free(cache[oldestEntry].username); }
if ( cache[oldestEntry].password ) { free(cache[oldestEntry].password); }
cache[oldestEntry].username = strdup(username);
cache[oldestEntry].password = strdup(password);
cache[oldestEntry].lastaccesstm = time(NULL);
}
}
---------------------------------
static int mysql_authenticate_basic_user (request_rec *r)
{
int passwords_match = 0; /* Assume no match */
encryption * enc_data = 0;
int i = 0;
char *user;
mysql_auth_config_rec *sec =
(mysql_auth_config_rec *)ap_get_module_config (r->per_dir_config,
&mysql_auth_module);
const char *sent_pw, *real_pw, *salt = 0, *salt_column = 0;
int res;
if (!sec->mysqlEnable) /* no mysql authorization */
return DECLINED;
if ((res = ap_get_basic_auth_pw (r, &sent_pw)) != OK)
return res;
/* 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];
#ifdef APACHE2
user = r->user;
#else
user = r->connection->user;
#endif
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;
}
if ( checkCache(user, sent_pw) )
{
//fprintf(stderr, "Entry found from cache for %s.", user);
//fflush(stderr);
return OK;
}
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 */
LOG_ERROR_2(APLOG_NOERRNO|APLOG_ERR, 0, r, "MySQL user %s not found: %s", user, r->uri);
ap_note_basic_auth_failure (r);
if (!sec->mysqlAuthoritative)
return DECLINED; /* let other schemes find user */
else
return NOT_AUTHORIZED;
}
if (!salt)
salt = real_pw;
/* if we don't require password, just return ok since they exist */
if (sec->mysqlNoPasswd) {
return OK;
}
if(passwords_match) {
putCache(user, sent_pw);
return OK;
} else {
LOG_ERROR_2(APLOG_NOERRNO|APLOG_ERR, 0, r,
"user %s: password mismatch: %s", user, r->uri);
ap_note_basic_auth_failure (r);
return NOT_AUTHORIZED;
}
}
-Hamid