[mod_auth] mod_authn_mysql.c MySQL auth backend (fixes #752, fixes #1845)

(automatically load mod_authn_mysql with mod_auth for compatibility with
 existing config usage via patches in various distros, e.g. FreeBSD)

x-ref:
  "mySQL auth"
  https://redmine.lighttpd.net/issues/752
  "MySQL Digest Authentication"
  https://redmine.lighttpd.net/issues/1845
personal/stbuehler/mod-csrf-old
Glenn Strauss 2016-09-09 22:31:06 -04:00
parent 17b2a38721
commit ae91578895
5 changed files with 577 additions and 0 deletions

View File

@ -561,6 +561,7 @@ add_and_install_library(mod_alias mod_alias.c)
add_and_install_library(mod_auth "mod_auth.c")
add_and_install_library(mod_authn_file "mod_authn_file.c")
add_and_install_library(mod_authn_ldap "mod_authn_ldap.c")
add_and_install_library(mod_authn_mysql "mod_authn_mysql.c")
if(NOT WIN32)
add_and_install_library(mod_cgi mod_cgi.c)
endif()
@ -640,6 +641,12 @@ add_target_properties(mod_cml COMPILE_FLAGS ${LUA_CFLAGS})
if(HAVE_MYSQL_H AND HAVE_MYSQL)
target_link_libraries(mod_mysql_vhost mysqlclient)
include_directories(/usr/include/mysql)
set(L_MOD_AUTHN_MYSQL)
if(HAVE_LIBCRYPT)
set(L_MOD_AUTHN_MYSQL ${L_MOD_AUTHN_MYSQL} crypt)
endif()
target_link_libraries(mod_authn_mysql ${L_MOD_AUTHN_MYSQL} mysqlclient)
endif()
set(L_MOD_WEBDAV)

View File

@ -267,6 +267,12 @@ mod_authn_ldap_la_SOURCES = mod_authn_ldap.c
mod_authn_ldap_la_LDFLAGS = $(common_module_ldflags)
mod_authn_ldap_la_LIBADD = $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
lib_LTLIBRARIES += mod_authn_mysql.la
mod_authn_mysql_la_SOURCES = mod_authn_mysql.c
mod_authn_mysql_la_LDFLAGS = $(common_module_ldflags)
mod_authn_mysql_la_LIBADD = $(CRYPT_LIB) $(MYSQL_LIBS) $(common_libadd)
mod_authn_mysql_la_CPPFLAGS = $(MYSQL_INCLUDE)
lib_LTLIBRARIES += mod_rewrite.la
mod_rewrite_la_SOURCES = mod_rewrite.c
mod_rewrite_la_LDFLAGS = $(common_module_ldflags)
@ -318,6 +324,7 @@ lighttpd_SOURCES = \
mod_auth.c \
mod_authn_file.c \
mod_authn_ldap.c \
mod_authn_mysql.c \
mod_cgi.c \
mod_cml.c mod_cml_lua.c mod_cml_funcs.c \
mod_compress.c \

View File

@ -103,6 +103,7 @@ modules = {
'mod_auth' : { 'src' : [ 'mod_auth.c' ] },
'mod_authn_file' : { 'src' : [ 'mod_authn_file.c' ], 'lib' : [ env['LIBCRYPT'] ] },
'mod_authn_ldap' : { 'src' : [ 'mod_authn_ldap.c' ], 'lib' : [ env['LIBLDAP'], env['LIBLBER'] ] },
'mod_authn_mysql' : { 'src' : [ 'mod_authn_mysql.c' ], 'lib' : [ env['LIBCRYPT'], env['LIBMYSQL'] ] },
'mod_webdav' : { 'src' : [ 'mod_webdav.c' ], 'lib' : [ env['LIBXML2'], env['LIBSQLITE3'], env['LIBUUID'] ] },
'mod_mysql_vhost' : { 'src' : [ 'mod_mysql_vhost.c' ], 'lib' : [ env['LIBMYSQL'] ] },
# 'mod_uploadprogress' : { 'src' : [ 'mod_uploadprogress.c' ] },

View File

@ -343,6 +343,7 @@ static int config_insert(server *srv) {
int append_mod_staticfile = 1;
int append_mod_authn_file = 1;
int append_mod_authn_ldap = 1;
int append_mod_authn_mysql = 1;
int contains_mod_auth = 0;
/* prepend default modules */
@ -369,6 +370,10 @@ static int config_insert(server *srv) {
append_mod_authn_ldap = 0;
}
if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_authn_mysql"))) {
append_mod_authn_mysql = 0;
}
if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_auth"))) {
contains_mod_auth = 1;
}
@ -378,6 +383,7 @@ static int config_insert(server *srv) {
0 == append_mod_staticfile &&
0 == append_mod_authn_file &&
0 == append_mod_authn_ldap &&
0 == append_mod_authn_mysql &&
1 == contains_mod_auth) {
break;
}
@ -429,6 +435,13 @@ static int config_insert(server *srv) {
array_insert_unique(srv->srvconf.modules, (data_unset *)ds);
#endif
}
if (append_mod_authn_mysql) {
#if defined(HAVE_MYSQL)
ds = data_string_init();
buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_authn_mysql"));
array_insert_unique(srv->srvconf.modules, (data_unset *)ds);
#endif
}
}
}

549
src/mod_authn_mysql.c Normal file
View File

@ -0,0 +1,549 @@
#include "first.h"
/* mod_authn_mysql
*
* KNOWN LIMITATIONS:
* - no mechanism provided to configure SSL connection to a remote MySQL db
*
* FUTURE POTENTIAL PERFORMANCE ENHANCEMENTS:
* - database response is not cached
* TODO: db response caching (for limited time) to reduce load on db
* (only cache successful logins to prevent cache bloat?)
* (or limit number of entries (size) of cache)
* (maybe have negative cache (limited size) of names not found in database)
* - database query is synchronous and blocks waiting for response
* TODO: https://mariadb.com/kb/en/mariadb/using-the-non-blocking-library/
* - opens and closes connection to MySQL db for each request (inefficient)
* (fixed) one-element cache for persistent connection open to last used db
* TODO: db connection pool (if asynchronous requests)
*/
#include "plugin.h"
#ifdef HAVE_MYSQL
#include <mysql.h>
#include "server.h"
#include "http_auth.h"
#include "log.h"
#include "md5.h"
#include <ctype.h>
#include <errno.h>
#include <string.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
typedef struct {
MYSQL *mysql_conn;
buffer *mysql_conn_host;
buffer *mysql_conn_user;
buffer *mysql_conn_pass;
buffer *mysql_conn_db;
int mysql_conn_port;
int auth_mysql_port;
buffer *auth_mysql_host;
buffer *auth_mysql_user;
buffer *auth_mysql_pass;
buffer *auth_mysql_db;
buffer *auth_mysql_socket;
buffer *auth_mysql_users_table;
buffer *auth_mysql_col_user;
buffer *auth_mysql_col_pass;
buffer *auth_mysql_col_realm;
} plugin_config;
typedef struct {
PLUGIN_DATA;
plugin_config **config_storage;
plugin_config conf;
} plugin_data;
static void mod_authn_mysql_sock_close(plugin_config *pconf) {
if (NULL != pconf->mysql_conn) {
mysql_close(pconf->mysql_conn);
pconf->mysql_conn = NULL;
}
}
static MYSQL * mod_authn_mysql_sock_connect(server *srv, plugin_config *pconf) {
if (NULL != pconf->mysql_conn) {
/* reuse open db connection if same ptrs to host user pass db port */
if ( pconf->mysql_conn_host == pconf->auth_mysql_host
&& pconf->mysql_conn_user == pconf->auth_mysql_user
&& pconf->mysql_conn_pass == pconf->auth_mysql_pass
&& pconf->mysql_conn_db == pconf->auth_mysql_db
&& pconf->mysql_conn_port == pconf->auth_mysql_port) {
return pconf->mysql_conn;
}
mod_authn_mysql_sock_close(pconf);
}
/* !! mysql_init() is not thread safe !! (see MySQL doc) */
pconf->mysql_conn = mysql_init(NULL);
if (mysql_real_connect(pconf->mysql_conn,
pconf->auth_mysql_host->ptr,
pconf->auth_mysql_user->ptr,
pconf->auth_mysql_pass->ptr,
pconf->auth_mysql_db->ptr,
pconf->auth_mysql_port,
!buffer_string_is_empty(pconf->auth_mysql_socket)
? pconf->auth_mysql_socket->ptr
: NULL,
CLIENT_IGNORE_SIGPIPE)) {
/* (copy ptrs to config data (has lifetime until server shutdown)) */
pconf->mysql_conn_host = pconf->auth_mysql_host;
pconf->mysql_conn_user = pconf->auth_mysql_user;
pconf->mysql_conn_pass = pconf->auth_mysql_pass;
pconf->mysql_conn_db = pconf->auth_mysql_db;
pconf->mysql_conn_port = pconf->auth_mysql_port;
return pconf->mysql_conn;
}
else {
/*(note: any of these params might be buffers with b->ptr == NULL)*/
log_error_write(srv, __FILE__, __LINE__, "sbsb"/*sb*/"sbss",
"opening connection to mysql:", pconf->auth_mysql_host,
"user:", pconf->auth_mysql_user,
/*"pass:", pconf->auth_mysql_pass,*//*(omit from logs)*/
"db:", pconf->auth_mysql_db,
"failed:", mysql_error(pconf->mysql_conn));
mod_authn_mysql_sock_close(pconf);
return NULL;
}
}
static MYSQL * mod_authn_mysql_sock_acquire(server *srv, plugin_config *pconf) {
return mod_authn_mysql_sock_connect(srv, pconf);
}
static void mod_authn_mysql_sock_release(server *srv, plugin_config *pconf) {
UNUSED(srv);
UNUSED(pconf);
/*(empty; leave db connection open)*/
/* Note: mod_authn_mysql_result() calls mod_authn_mysql_sock_error()
* on error, so take that into account if making changes here.
* Must check if (NULL == pconf->mysql_conn) */
}
static void mod_authn_mysql_sock_error(server *srv, plugin_config *pconf) {
UNUSED(srv);
mod_authn_mysql_sock_close(pconf);
}
static handler_t mod_authn_mysql_basic(server *srv, connection *con, void *p_d, const buffer *username, const buffer *realm, const char *pw);
static handler_t mod_authn_mysql_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]);
INIT_FUNC(mod_authn_mysql_init) {
static http_auth_backend_t http_auth_backend_mysql =
{ "mysql", mod_authn_mysql_basic, mod_authn_mysql_digest, NULL, NULL };
plugin_data *p = calloc(1, sizeof(*p));
/* register http_auth_backend_mysql */
http_auth_backend_mysql.p_d = p;
http_auth_backend_set(&http_auth_backend_mysql);
return p;
}
FREE_FUNC(mod_authn_mysql_free) {
plugin_data *p = p_d;
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (NULL == s) continue;
buffer_free(s->auth_mysql_host);
buffer_free(s->auth_mysql_user);
buffer_free(s->auth_mysql_pass);
buffer_free(s->auth_mysql_db);
buffer_free(s->auth_mysql_socket);
buffer_free(s->auth_mysql_users_table);
buffer_free(s->auth_mysql_col_user);
buffer_free(s->auth_mysql_col_pass);
buffer_free(s->auth_mysql_col_realm);
if (s->mysql_conn) mod_authn_mysql_sock_close(s);
free(s);
}
free(p->config_storage);
}
free(p);
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(mod_authn_mysql_set_defaults) {
plugin_data *p = p_d;
size_t i;
config_values_t cv[] = {
{ "auth.backend.mysql.host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.mysql.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.mysql.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.mysql.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.mysql.port", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.mysql.socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.mysql.users_table", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.mysql.col_user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.mysql.col_pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.mysql.col_realm", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
for (i = 0; i < srv->config_context->used; i++) {
data_config const* config = (data_config const*)srv->config_context->data[i];
plugin_config *s;
s = calloc(1, sizeof(plugin_config));
s->mysql_conn = NULL;
s->auth_mysql_host = buffer_init();
s->auth_mysql_user = buffer_init();
s->auth_mysql_pass = buffer_init();
s->auth_mysql_db = buffer_init();
s->auth_mysql_socket = buffer_init();
s->auth_mysql_users_table = buffer_init();
s->auth_mysql_col_user = buffer_init();
s->auth_mysql_col_pass = buffer_init();
s->auth_mysql_col_realm = buffer_init();
cv[0].destination = s->auth_mysql_host;
cv[1].destination = s->auth_mysql_user;
cv[2].destination = s->auth_mysql_pass;
cv[3].destination = s->auth_mysql_db;
cv[4].destination = &s->auth_mysql_port;
cv[5].destination = s->auth_mysql_socket;
cv[6].destination = s->auth_mysql_users_table;
cv[7].destination = s->auth_mysql_col_user;
cv[8].destination = s->auth_mysql_col_pass;
cv[9].destination = s->auth_mysql_col_realm;
p->config_storage[i] = s;
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
return HANDLER_ERROR;
}
if (!buffer_is_empty(s->auth_mysql_col_user)
&& buffer_string_is_empty(s->auth_mysql_col_user)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"auth.backend.mysql.col_user must not be blank");
return HANDLER_ERROR;
}
if (!buffer_is_empty(s->auth_mysql_col_pass)
&& buffer_string_is_empty(s->auth_mysql_col_pass)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"auth.backend.mysql.col_pass must not be blank");
return HANDLER_ERROR;
}
if (!buffer_is_empty(s->auth_mysql_col_realm)
&& buffer_string_is_empty(s->auth_mysql_col_realm)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"auth.backend.mysql.col_realm must not be blank");
return HANDLER_ERROR;
}
}
{
plugin_config *s = p->config_storage[0];
if (buffer_is_empty(s->auth_mysql_col_user)) {
s->auth_mysql_col_user = buffer_init_string("user");
}
if (buffer_is_empty(s->auth_mysql_col_pass)) {
s->auth_mysql_col_pass = buffer_init_string("password");
}
if (buffer_is_empty(s->auth_mysql_col_realm)) {
s->auth_mysql_col_realm = buffer_init_string("realm");
}
}
return HANDLER_GO_ON;
}
#define PATCH(x) \
p->conf.x = s->x;
static int mod_authn_mysql_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
PATCH(auth_mysql_host);
PATCH(auth_mysql_user);
PATCH(auth_mysql_pass);
PATCH(auth_mysql_db);
PATCH(auth_mysql_port);
PATCH(auth_mysql_socket);
PATCH(auth_mysql_users_table);
PATCH(auth_mysql_col_user);
PATCH(auth_mysql_col_pass);
PATCH(auth_mysql_col_realm);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.host"))) {
PATCH(auth_mysql_host);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.user"))) {
PATCH(auth_mysql_user);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.pass"))) {
PATCH(auth_mysql_pass);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.db"))) {
PATCH(auth_mysql_db);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.port"))) {
PATCH(auth_mysql_port);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.socket"))) {
PATCH(auth_mysql_socket);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.users_table"))) {
PATCH(auth_mysql_users_table);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_user"))) {
PATCH(auth_mysql_col_user);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_pass"))) {
PATCH(auth_mysql_col_pass);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_realm"))) {
PATCH(auth_mysql_col_realm);
}
}
}
return 0;
}
#undef PATCH
static int mod_authn_mysql_password_cmp(const char *userpw, unsigned long userpwlen, const char *reqpw) {
#if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)
if (userpwlen >= 3 && userpw[0] == '$' && userpw[2] == '$') {
/* md5 crypt()
* request by Nicola Tiling <nti@w4w.net> */
const char *saltb = userpw+3;
const char *salte = strchr(saltb, '$');
char salt[32];
size_t slen = (NULL != salte) ? (size_t)(salte - saltb) : sizeof(salt);
if (slen < sizeof(salt)) {
char *crypted;
#if defined(HAVE_CRYPT_R)
struct crypt_data crypt_tmp_data;
crypt_tmp_data.initialized = 0;
#endif
memcpy(salt, saltb, slen);
salt[slen] = '\0';
#if defined(HAVE_CRYPT_R)
crypted = crypt_r(reqpw, salt, &crypt_tmp_data);
#else
crypted = crypt(reqpw, salt);
#endif
if (NULL != crypted) {
return strcmp(userpw, crypted);
}
}
}
else
#endif
if (32 == userpwlen) {
/* plain md5 */
li_MD5_CTX Md5Ctx;
unsigned char HA1[16];
unsigned char md5pw[16];
li_MD5_Init(&Md5Ctx);
li_MD5_Update(&Md5Ctx, (unsigned char *)reqpw, strlen(reqpw));
li_MD5_Final(HA1, &Md5Ctx);
/*(compare 16-byte MD5 binary instead of converting to hex strings
* in order to then have to do case-insensitive hex str comparison)*/
return (0 == http_auth_md5_hex2bin(userpw, 32 /*(userpwlen)*/, md5pw))
? memcmp(HA1, md5pw, sizeof(md5pw))
: -1;
}
return -1;
}
static int mod_authn_mysql_result(server *srv, plugin_data *p, const char *pw, unsigned char HA1[16]) {
MYSQL_RES *result = mysql_store_result(p->conf.mysql_conn);
int rc = -1;
my_ulonglong num_rows;
if (NULL == result) {
/*(future: might log mysql_error() string)*/
#if 0
log_error_write(srv, __FILE__, __LINE__, "ss", "mysql_store_result:",
mysql_error(p->conf.mysql_conn));
#endif
mod_authn_mysql_sock_error(srv, &p->conf);
return -1;
}
num_rows = mysql_num_rows(result);
if (1 == num_rows) {
MYSQL_ROW row = mysql_fetch_row(result);
unsigned long *lengths = mysql_fetch_lengths(result);
if (NULL == lengths) {
/*(error; should not happen)*/
}
else if (pw) { /* used with HTTP Basic auth */
rc = mod_authn_mysql_password_cmp(row[0], lengths[0], pw);
}
else { /* used with HTTP Digest auth */
rc = http_auth_md5_hex2bin(row[0], lengths[0], HA1);
}
}
else if (0 == num_rows) {
/* user,realm not found */
}
else {
/* (multiple rows returned, which should not happen) */
/* (future: might log if multiple rows returned; unexpected result) */
}
mysql_free_result(result);
return rc;
}
static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d, const char *username, const char *realm, const char *pw, unsigned char HA1[16]) {
plugin_data *p = (plugin_data *)p_d;
int rc = -1;
mod_authn_mysql_patch_connection(srv, con, p);
if (buffer_string_is_empty(p->conf.auth_mysql_users_table)) {
/*(auth.backend.mysql.host, auth.backend.mysql.db might be NULL; do not log)*/
log_error_write(srv, __FILE__, __LINE__, "sb",
"auth config missing auth.backend.mysql.users_table for uri:",
con->request.uri);
return HANDLER_ERROR;
}
do {
size_t unamelen = strlen(username);
size_t urealmlen = strlen(realm);
char q[1024], uname[512], urealm[512];
unsigned long mrc;
if (unamelen > sizeof(uname)/2-1)
return HANDLER_ERROR;
if (urealmlen > sizeof(urealm)/2-1)
return HANDLER_ERROR;
if (!mod_authn_mysql_sock_acquire(srv, &p->conf)) {
return HANDLER_ERROR;
}
#if 0
mrc = mysql_real_escape_string_quote(p->conf.mysql_conn,uname,username,
(unsigned long)unamelen, '\'');
if ((unsigned long)~0 == mrc) break;
mrc = mysql_real_escape_string_quote(p->conf.mysql_conn,urealm,realm,
(unsigned long)urealmlen, '\'');
if ((unsigned long)~0 == mrc) break;
#else
mrc = mysql_real_escape_string(p->conf.mysql_conn, uname,
username, (unsigned long)unamelen);
if ((unsigned long)~0 == mrc) break;
mrc = mysql_real_escape_string(p->conf.mysql_conn, urealm,
realm, (unsigned long)urealmlen);
if ((unsigned long)~0 == mrc) break;
#endif
rc = snprintf(q, sizeof(q),
"SELECT %s FROM %s WHERE %s='%s' AND %s='%s'",
p->conf.auth_mysql_col_pass->ptr,
p->conf.auth_mysql_users_table->ptr,
p->conf.auth_mysql_col_user->ptr,
uname,
p->conf.auth_mysql_col_realm->ptr,
urealm);
if (rc >= (int)sizeof(q)) {
rc = -1;
break;
}
/* for now we stay synchronous */
if (0 != mysql_query(p->conf.mysql_conn, q)) {
/* reconnect to db and retry once if query error occurs */
mod_authn_mysql_sock_error(srv, &p->conf);
if (!mod_authn_mysql_sock_acquire(srv, &p->conf)) {
rc = -1;
break;
}
if (0 != mysql_query(p->conf.mysql_conn, q)) {
/*(note: any of these params might be bufs w/ b->ptr == NULL)*/
log_error_write(srv, __FILE__, __LINE__, "sbsb"/*sb*/"sbssss",
"mysql_query host:", p->conf.auth_mysql_host,
"user:", p->conf.auth_mysql_user,
/*(omit pass from logs)*/
/*"pass:", p->conf.auth_mysql_pass,*/
"db:", p->conf.auth_mysql_db,
"query:", q,
"failed:", mysql_error(p->conf.mysql_conn));
rc = -1;
break;
}
}
rc = mod_authn_mysql_result(srv, p, pw, HA1);
} while (0);
mod_authn_mysql_sock_release(srv, &p->conf);
return (0 == rc) ? HANDLER_GO_ON : HANDLER_ERROR;
}
static handler_t mod_authn_mysql_basic(server *srv, connection *con, void *p_d, const buffer *username, const buffer *realm, const char *pw) {
/*(HA1 is not written since pw passed should not be NULL;
* avoid passing NULL since subroutine expects unsigned char HA1[16] arg)*/
static unsigned char HA1[16];
return mod_authn_mysql_query(srv,con,p_d,username->ptr,realm->ptr,pw,HA1);
}
static handler_t mod_authn_mysql_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]) {
return mod_authn_mysql_query(srv,con,p_d,username,realm,NULL,HA1);
}
int mod_authn_mysql_plugin_init(plugin *p);
int mod_authn_mysql_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("authn_mysql");
p->init = mod_authn_mysql_init;
p->set_defaults= mod_authn_mysql_set_defaults;
p->cleanup = mod_authn_mysql_free;
p->data = NULL;
return 0;
}
#else
int mod_authn_mysql_plugin_init(plugin *p);
int mod_authn_mysql_plugin_init(plugin *p) {
UNUSED(p);
return -1;
}
#endif