Compatibility with Debian stretch & MySQL 5.7

This commit is contained in:
Juan 2018-07-02 17:20:11 +02:00
parent b77a9af188
commit 933bf0c347
10 changed files with 203 additions and 134 deletions

19
.gitignore vendored
View File

@ -1,7 +1,16 @@
.anjuta/
.anjuta_sym_db.db
aclocal.m4
build/ build/
configure
debian/build/ debian/build/
vn-mysql.anjuta autom4te.cache/
aclocal.m4
.anjuta_sym_db.db
config.log
config.status
libtool
configure
Makefile
Makefile.in
.deps
.libs
*.lo
*.o
*.la

12
INSTALL
View File

@ -1,7 +1,7 @@
Installation Instructions Installation Instructions
************************* *************************
Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc. Inc.
Copying and distribution of this file, with or without modification, Copying and distribution of this file, with or without modification,
@ -12,8 +12,8 @@ without warranty of any kind.
Basic Installation Basic Installation
================== ==================
Briefly, the shell commands `./configure; make; make install' should Briefly, the shell command `./configure && make && make install'
configure, build, and install this package. The following should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented `INSTALL' file but do not implement all of the features documented
@ -309,9 +309,10 @@ causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script). overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround: an Autoconf limitation. Until the limitation is lifted, you can use
this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation `configure' Invocation
====================== ======================
@ -367,4 +368,3 @@ operates.
`configure' also accepts some other, not widely useful, options. Run `configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details. `configure --help' for more details.

View File

@ -2,7 +2,7 @@
mysql_LIBS = `mysql_config --libs` mysql_LIBS = `mysql_config --libs`
mysql_CFLAGS = `mysql_config --cflags` mysql_CFLAGS = `mysql_config --cflags`
vn_mysql_libdir = $(libdir)/mysql/plugin vn_mysql_libdir = /usr/lib/mysql/plugin
vn_mysql_CFLAGS = \ vn_mysql_CFLAGS = \
-Wall -O3 \ -Wall -O3 \
$(mysql_CFLAGS) $(mysql_CFLAGS)

18
clean.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
dir=$PWD
if [ ! -r $dir/configure.ac ]
then
echo "$0: Invalid source directory: $dir"
exit 2
fi
rm -rf $dir/build
rm -rf $dir/configure
rm -rf $dir/gtk-doc.make
rm -rf $dir/aclocal.m4
rm -rf $dir/autom4te.cache
rm -rf $dir/po/Makefile.in.in
rm -rf `find $dir -name Makefile.in`
rm -rf `find $dir -name Makefile`

2
debian/changelog vendored
View File

@ -1,4 +1,4 @@
vn-mysql (1.4-deb8) unstable; urgency=low vn-mysql (1.5.0) unstable; urgency=low
* Initial Release. * Initial Release.

2
debian/compat vendored
View File

@ -1 +1 @@
8 9

View File

@ -5,6 +5,10 @@ DROP TABLE IF EXISTS account.user;
CREATE TABLE account.user CREATE TABLE account.user
SELECT 'proxy' mysql_user, 'test-user' user, '1234' password; SELECT 'proxy' mysql_user, 'test-user' user, '1234' password;
DROP USER 'proxy-auth'@'%';
CREATE USER 'proxy-auth'@'%' IDENTIFIED BY 'password';
GRANT SELECT ON TABLE account.user TO 'proxy-auth'@'%';
DROP USER ''@'%'; DROP USER ''@'%';
CREATE USER ''@'%' IDENTIFIED WITH proxy_auth; CREATE USER ''@'%' IDENTIFIED WITH proxy_auth;
GRANT USAGE ON *.* TO ''@'%'; GRANT USAGE ON *.* TO ''@'%';

View File

@ -68,8 +68,8 @@ char * sql_printf (UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long
delimiter = "`"; delimiter = "`";
break; break;
case 'v': case 'v':
if (buffer->org_type[i] == STRING_RESULT) if (buffer->org_type[i] == STRING_RESULT)
delimiter = "'"; delimiter = "'";
break; break;
case 's': case 's':
break; break;

View File

@ -15,11 +15,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define MYSQL_ABI_CHECK
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <mysql.h> #include <mysql.h>
#include <mysql/errmsg.h> #include <mysql/errmsg.h>
#include <mysql/plugin_auth.h> #include <mysql/plugin_auth.h>
#include <glib-unix.h> #include <glib-unix.h>
#define CONFIG_FILE _CONFIG_DIR"/proxy-auth.ini" #define CONFIG_FILE _CONFIG_DIR"/proxy-auth.ini"
@ -57,56 +60,56 @@ typedef struct
RegexData; RegexData;
ProxyAuth * ProxyAuth *
proxy_auth_new () proxy_auth_new()
{ {
ProxyAuth * self = g_new (ProxyAuth, 1); ProxyAuth * self = g_new(ProxyAuth, 1);
self->initialized = FALSE; self->initialized = FALSE;
g_mutex_init (&self->mutex); g_mutex_init(&self->mutex);
return self; return self;
} }
void void
proxy_auth_deinit (ProxyAuth * self) proxy_auth_deinit(ProxyAuth * self)
{ {
if (!self->initialized) if (!self->initialized)
return; return;
g_free (self->socket); g_free(self->socket);
g_free (self->host); g_free(self->host);
g_free (self->user); g_free(self->user);
g_free (self->pass); g_free(self->pass);
g_free (self->schema); g_free(self->schema);
g_free (self->queryt); g_free(self->queryt);
if (self->regex) if (self->regex)
g_regex_unref (self->regex); g_regex_unref(self->regex);
// FIXME: Connection can't be closed because mysql_close() causes MySQL // FIXME: Connection can't be closed because mysql_close() causes MySQL
// process crash with signal 11 when the process is shutdown. // process crash with signal 11 when the process is shutdown.
// MySQL version 5.5.40 // MySQL version 5.5.40
//if (self->conn_pool) //if (self->conn_pool)
// g_async_queue_unref (self->conn_pool); // g_async_queue_unref(self->conn_pool);
} }
void void
proxy_auth_free (ProxyAuth * self) proxy_auth_free(ProxyAuth * self)
{ {
g_return_if_fail (self != NULL); g_return_if_fail(self != NULL);
proxy_auth_deinit (self); proxy_auth_deinit(self);
g_mutex_clear (&self->mutex); g_mutex_clear(&self->mutex);
g_free (self); g_free(self);
} }
gboolean gboolean
proxy_auth_init (ProxyAuth * self) proxy_auth_init(ProxyAuth * self)
{ {
g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail(self != NULL, FALSE);
gboolean res = FALSE; gboolean res = FALSE;
GError * error = NULL; GError * error = NULL;
proxy_auth_deinit (self); proxy_auth_deinit(self);
self->initialized = TRUE; self->initialized = TRUE;
self->socket = NULL; self->socket = NULL;
self->host = NULL; self->host = NULL;
@ -120,53 +123,53 @@ proxy_auth_init (ProxyAuth * self)
self->last_error = 0; self->last_error = 0;
self->debug = FALSE; self->debug = FALSE;
mysql_library_init (0, NULL, NULL); mysql_library_init(0, NULL, NULL);
// Reading the configuration file // Reading the configuration file
GKeyFile * key_file = g_key_file_new (); GKeyFile * key_file = g_key_file_new();
if (!g_key_file_load_from_file (key_file, CONFIG_FILE, G_KEY_FILE_NONE, &error)) if (!g_key_file_load_from_file(key_file, CONFIG_FILE, G_KEY_FILE_NONE, &error))
{ {
g_warning ("ProxyAuth: Can't open configuration file: %s", error->message); g_warning("ProxyAuth: Can't open configuration file: %s", error->message);
goto end; goto end;
} }
self->socket = NULL; self->socket = NULL;
self->host = g_key_file_get_string (key_file, "db", "host", NULL); self->host = g_key_file_get_string(key_file, "db", "host", NULL);
if (!self->host) if (!self->host)
self->socket = g_key_file_get_string (key_file, "db", "socket", NULL); self->socket = g_key_file_get_string(key_file, "db", "socket", NULL);
self->user = g_key_file_get_string (key_file, "db", "user", NULL); self->user = g_key_file_get_string(key_file, "db", "user", NULL);
self->pass = g_key_file_get_string (key_file, "db", "pass", NULL); self->pass = g_key_file_get_string(key_file, "db", "pass", NULL);
self->schema = g_key_file_get_string (key_file, "db", "schema", NULL); self->schema = g_key_file_get_string(key_file, "db", "schema", NULL);
self->port = (guint) g_key_file_get_integer (key_file, "db", "port", NULL); self->port = (guint) g_key_file_get_integer(key_file, "db", "port", NULL);
self->max_connections = g_key_file_get_integer (key_file, "db", "maxConnections", NULL); self->max_connections = g_key_file_get_integer(key_file, "db", "maxConnections", NULL);
self->debug = g_key_file_get_boolean (key_file, "db", "debug", NULL); self->debug = g_key_file_get_boolean(key_file, "db", "debug", NULL);
// Reading the query template // Reading the query template
if (!g_file_get_contents (SQL_FILE, &self->queryt, &self->queryt_len, &error)) if (!g_file_get_contents(SQL_FILE, &self->queryt, &self->queryt_len, &error))
{ {
g_warning ("ProxyAuth: Can't read the query template: %s", error->message); g_warning("ProxyAuth: Can't read the query template: %s", error->message);
goto end; goto end;
} }
// Creates the regular expression // Creates the regular expression
self->regex = g_regex_new ("#\\w+", self->regex = g_regex_new("#\\w+",
G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, &error); G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, &error);
if (error) if (error)
{ {
g_warning ("ProxyAuth: Can't create the regex: %s", error->message); g_warning("ProxyAuth: Can't create the regex: %s", error->message);
goto end; goto end;
} }
// Creates the connection pool // Creates the connection pool
self->conn_pool = g_async_queue_new_full ((GDestroyNotify) mysql_close); self->conn_pool = g_async_queue_new_full((GDestroyNotify) mysql_close);
self->pool_size = 0; self->pool_size = 0;
self->last_error = 0; self->last_error = 0;
@ -175,26 +178,26 @@ proxy_auth_init (ProxyAuth * self)
res = TRUE; res = TRUE;
end: end:
g_clear_error (&error); g_clear_error(&error);
g_key_file_free (key_file); g_key_file_free(key_file);
return res; return res;
} }
static gboolean static gboolean
proxy_auth_regex_func (const GMatchInfo * info, GString * res, gpointer data) proxy_auth_regex_func(const GMatchInfo * info, GString * res, gpointer data)
{ {
RegexData * regex_data = (RegexData *) data; RegexData * regex_data = (RegexData *) data;
gchar * match = g_match_info_fetch (info, 0); gchar * match = g_match_info_fetch(info, 0);
gchar * str = NULL; gchar * str = NULL;
gulong str_len; gulong str_len;
if (!g_strcmp0 (match, "#user")) if (!g_strcmp0(match, "#user"))
{ {
str = regex_data->user; str = regex_data->user;
str_len = regex_data->user_len; str_len = regex_data->user_len;
} }
else if (!g_strcmp0 (match, "#pass")) else if (!g_strcmp0(match, "#pass"))
{ {
str = regex_data->pass; str = regex_data->pass;
str_len = regex_data->pass_len; str_len = regex_data->pass_len;
@ -205,44 +208,44 @@ proxy_auth_regex_func (const GMatchInfo * info, GString * res, gpointer data)
unsigned long scaped_len; unsigned long scaped_len;
char escaped_str[str_len * 2 + 1]; char escaped_str[str_len * 2 + 1];
g_string_append_c (res, '\''); g_string_append_c(res, '\'');
// FIXME: mysql_real_escape_string() causes MySQL process crash with signal 11 // FIXME: mysql_real_escape_string() causes MySQL process crash with signal 11
//scaped_len = mysql_real_escape_string (regex_data->conn, escaped_str, str, str_len); //scaped_len = mysql_real_escape_string(regex_data->conn, escaped_str, str, str_len);
scaped_len = mysql_escape_string (escaped_str, str, str_len); scaped_len = mysql_escape_string(escaped_str, str, str_len);
g_string_append_len (res, escaped_str, (gssize) scaped_len); g_string_append_len(res, escaped_str,(gssize) scaped_len);
g_string_append_c (res, '\''); g_string_append_c(res, '\'');
} }
else else
g_string_append (res, match); g_string_append(res, match);
g_free (match); g_free(match);
return FALSE; return FALSE;
} }
static gboolean static gboolean
proxy_auth_reconnect (ProxyAuth * self, MYSQL * conn) proxy_auth_reconnect(ProxyAuth * self, MYSQL * conn)
{ {
g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail(self != NULL, FALSE);
gboolean connected = mysql_real_connect (conn, gboolean connected = mysql_real_connect(conn,
self->host, self->user, self->pass, self->schema, self->port, self->socket, 0) != NULL; self->host, self->user, self->pass, self->schema, self->port, self->socket, 0) != NULL;
guint conn_error = mysql_errno (conn); guint conn_error = mysql_errno(conn);
if (conn_error && self->last_error != conn_error) if (conn_error && self->last_error != conn_error)
g_warning ("ProxyAuth: Can't connect to database: %s", mysql_error (conn)); g_warning("ProxyAuth: Can't connect to database: %s", mysql_error(conn));
else if (mysql_set_character_set (conn, "latin1")) else if (mysql_set_character_set(conn, "latin1"))
g_warning ("ProxyAuth: Can't set character set: %s", mysql_error (conn)); g_warning("ProxyAuth: Can't set character set: %s", mysql_error(conn));
self->last_error = conn_error; self->last_error = conn_error;
return connected; return connected;
} }
int int
proxy_auth_authenticate (ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_AUTH_INFO * info) proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_AUTH_INFO * info)
{ {
g_return_val_if_fail (self != NULL, CR_ERROR); g_return_val_if_fail(self != NULL, CR_ERROR);
int res = CR_ERROR; int res = CR_ERROR;
gchar * query = NULL; gchar * query = NULL;
@ -254,7 +257,7 @@ proxy_auth_authenticate (ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_
int user_len = info->user_name_length; int user_len = info->user_name_length;
if (info->user_name == NULL if (info->user_name == NULL
&& (user_len = vio->read_packet (vio, &pkt)) < 0) &&(user_len = vio->read_packet(vio, &pkt)) < 0)
return CR_ERROR; return CR_ERROR;
if (user_len > MYSQL_USERNAME_LENGTH) if (user_len > MYSQL_USERNAME_LENGTH)
@ -262,7 +265,7 @@ proxy_auth_authenticate (ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_
// Read the password and check if it's valid // Read the password and check if it's valid
int pass_len = vio->read_packet (vio, &pkt) - 1; int pass_len = vio->read_packet(vio, &pkt) - 1;
if (pass_len < 0) if (pass_len < 0)
return CR_ERROR; return CR_ERROR;
@ -274,49 +277,49 @@ proxy_auth_authenticate (ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_
} }
char pass[pass_len + 1]; char pass[pass_len + 1];
memcpy (pass, pkt, pass_len); memcpy(pass, pkt, pass_len);
pass[pass_len] = '\0'; pass[pass_len] = '\0';
info->password_used = PASSWORD_USED_YES; info->password_used = PASSWORD_USED_YES;
// Gets a connection from the pool // Gets a connection from the pool
MYSQL * conn = (MYSQL *) g_async_queue_try_pop (self->conn_pool); MYSQL * conn = (MYSQL *) g_async_queue_try_pop(self->conn_pool);
if (!conn) if (!conn)
{ {
g_mutex_lock (&self->mutex); g_mutex_lock(&self->mutex);
if (self->pool_size < self->max_connections) if (self->pool_size < self->max_connections)
{ {
self->pool_size++; self->pool_size++;
g_mutex_unlock (&self->mutex); g_mutex_unlock(&self->mutex);
conn = mysql_init (NULL); conn = mysql_init(NULL);
if (!proxy_auth_reconnect (self, conn)) if (!proxy_auth_reconnect(self, conn))
{ {
g_mutex_lock (&self->mutex); g_mutex_lock(&self->mutex);
self->pool_size--; self->pool_size--;
g_mutex_unlock (&self->mutex); g_mutex_unlock(&self->mutex);
mysql_close (conn); mysql_close(conn);
conn = NULL; conn = NULL;
goto end; goto end;
} }
} }
else else
{ {
g_mutex_unlock (&self->mutex); g_mutex_unlock(&self->mutex);
conn = (MYSQL *) g_async_queue_pop (self->conn_pool); conn = (MYSQL *) g_async_queue_pop(self->conn_pool);
} }
} }
switch (mysql_errno (conn)) switch (mysql_errno(conn))
{ {
case CR_SERVER_LOST: case CR_SERVER_LOST:
case CR_SERVER_GONE_ERROR: case CR_SERVER_GONE_ERROR:
if (!proxy_auth_reconnect (self, conn)) if (!proxy_auth_reconnect(self, conn))
goto end; goto end;
} }
@ -329,100 +332,137 @@ proxy_auth_authenticate (ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_
regex_data.pass = pass; regex_data.pass = pass;
regex_data.pass_len = pass_len; regex_data.pass_len = pass_len;
query = g_regex_replace_eval (self->regex, query = g_regex_replace_eval(self->regex,
self->queryt, self->queryt_len, 0, 0, proxy_auth_regex_func, &regex_data, &error); self->queryt, self->queryt_len, 0, 0, proxy_auth_regex_func, &regex_data, &error);
if (error) if (error)
{ {
g_warning ("ProxyAuth: Can't evaluate regex: %s", error->message); g_warning("ProxyAuth: Can't evaluate regex: %s", error->message);
goto end; goto end;
} }
// Sends the query to the database // Sends the query to the database
if (self->debug) if (self->debug)
g_message ("ProxyAuth: Query: %s", query); g_message("ProxyAuth: Query: %s", query);
MYSQL_RES * result; MYSQL_RES * result;
if (!mysql_query (conn, query) if (!mysql_query(conn, query)
&& (result = mysql_store_result (conn))) &&(result = mysql_store_result(conn)))
{ {
MYSQL_ROW row = mysql_fetch_row (result); MYSQL_ROW row = mysql_fetch_row(result);
if (row && row[0]) if (row && row[0])
{ {
unsigned long row_len = mysql_fetch_lengths (result)[0]; unsigned long row_len = mysql_fetch_lengths(result)[0];
if (row_len > 0 && row_len <= MYSQL_USERNAME_LENGTH) if (row_len > 0 && row_len <= MYSQL_USERNAME_LENGTH)
{ {
strcpy (info->external_user, info->user_name); strcpy(info->external_user, info->user_name);
strncpy (info->authenticated_as, row[0], row_len); strncpy(info->authenticated_as, row[0], row_len);
info->authenticated_as[row_len] = '\0'; info->authenticated_as[row_len] = '\0';
res = CR_OK; res = CR_OK;
if (self->debug) if (self->debug)
g_message ("ProxyAuth: Proxy user: %s", info->authenticated_as); g_message("ProxyAuth: Proxy user: %s", info->authenticated_as);
} }
} }
mysql_free_result (result); mysql_free_result(result);
} }
else else
g_warning ("ProxyAuth: Error executing query: %s", mysql_error (conn)); g_warning("ProxyAuth: Error executing query: %s", mysql_error(conn));
end: end:
if (conn) if (conn)
g_async_queue_push (self->conn_pool, conn); g_async_queue_push(self->conn_pool, conn);
g_clear_error (&error); g_clear_error(&error);
g_free (query); g_free(query);
return res; return res;
} }
ProxyAuth * pauth = NULL; ProxyAuth * pauth = NULL;
static int static int
proxy_auth_plugin_main (MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_AUTH_INFO * info) proxy_auth_plugin_main(MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_AUTH_INFO * info)
{ {
return proxy_auth_authenticate (pauth, vio, info); return proxy_auth_authenticate(pauth, vio, info);
} }
static int static int
proxy_auth_plugin_init () proxy_auth_plugin_init()
{ {
pauth = proxy_auth_new (); pauth = proxy_auth_new();
return proxy_auth_init (pauth) ? 0 : 1; return proxy_auth_init(pauth) ? 0 : 1;
} }
static int static int
proxy_auth_plugin_deinit () proxy_auth_plugin_deinit()
{ {
proxy_auth_free (pauth); proxy_auth_free(pauth);
return 0; return 0;
} }
static struct st_mysql_auth proxy_auth_handler = int
generate_auth_string_hash(
char *outbuf, unsigned int *buflen,
const char *inbuf,
unsigned int inbuflen)
{ {
MYSQL_AUTHENTICATION_INTERFACE_VERSION if (*buflen < inbuflen)
,"mysql_clear_password" // Cleartext plugin required in the client return 1;
,proxy_auth_plugin_main
strncpy(outbuf, inbuf, inbuflen);
*buflen = strlen(inbuf);
return 0;
}
int
validate_auth_string_hash(
char* const inbuf __attribute__((unused)),
unsigned int buflen __attribute__((unused)))
{
return 0;
}
int
set_salt(
const char* password __attribute__((unused)),
unsigned int password_len __attribute__((unused)),
unsigned char* salt __attribute__((unused)),
unsigned char* salt_len)
{
*salt_len = 0;
return 0;
}
static struct st_mysql_auth
proxy_auth_handler =
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
"mysql_clear_password", // Cleartext plugin required in the client
proxy_auth_plugin_main,
generate_auth_string_hash,
validate_auth_string_hash,
set_salt,
AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE
}; };
mysql_declare_plugin(proxy_auth) mysql_declare_plugin(proxy_auth)
{ {
MYSQL_AUTHENTICATION_PLUGIN MYSQL_AUTHENTICATION_PLUGIN,
,&proxy_auth_handler &proxy_auth_handler,
,"proxy_auth" "proxy_auth",
,"Alejandro T. Colombini" "Alejandro T. Colombini",
,"Proxy user authentication server-side plugin" "Proxy user authentication server-side plugin",
,PLUGIN_LICENSE_GPL PLUGIN_LICENSE_GPL,
,proxy_auth_plugin_init proxy_auth_plugin_init,
,proxy_auth_plugin_deinit proxy_auth_plugin_deinit,
,0x0100 // version 1.0 0x0100, // version 1.0,
,NULL NULL,
,NULL NULL,
,NULL NULL,
,0 0,
} }
mysql_declare_plugin_end; mysql_declare_plugin_end;

View File

@ -1,5 +1,3 @@
SELECT m.user SELECT mysql_user FROM account.user
FROM user u WHERE user = #user AND password = #pass
JOIN mysql_user m ON u.mysql_user_id = m.id
WHERE u.name = #user AND u.password = MD5(#pass) AND u.active