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/
configure
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
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
@ -12,8 +12,8 @@ without warranty of any kind.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
Briefly, the shell command `./configure && make && make install'
should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`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).
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
======================
@ -367,4 +368,3 @@ operates.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View File

@ -2,7 +2,7 @@
mysql_LIBS = `mysql_config --libs`
mysql_CFLAGS = `mysql_config --cflags`
vn_mysql_libdir = $(libdir)/mysql/plugin
vn_mysql_libdir = /usr/lib/mysql/plugin
vn_mysql_CFLAGS = \
-Wall -O3 \
$(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.

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
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 ''@'%';
CREATE USER ''@'%' IDENTIFIED WITH proxy_auth;
GRANT USAGE ON *.* TO ''@'%';

View File

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

View File

@ -15,11 +15,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define MYSQL_ABI_CHECK
#include <stdio.h>
#include <string.h>
#include <mysql.h>
#include <mysql/errmsg.h>
#include <mysql/plugin_auth.h>
#include <glib-unix.h>
#define CONFIG_FILE _CONFIG_DIR"/proxy-auth.ini"
@ -57,56 +60,56 @@ typedef struct
RegexData;
ProxyAuth *
proxy_auth_new ()
proxy_auth_new()
{
ProxyAuth * self = g_new (ProxyAuth, 1);
ProxyAuth * self = g_new(ProxyAuth, 1);
self->initialized = FALSE;
g_mutex_init (&self->mutex);
g_mutex_init(&self->mutex);
return self;
}
void
proxy_auth_deinit (ProxyAuth * self)
proxy_auth_deinit(ProxyAuth * self)
{
if (!self->initialized)
return;
g_free (self->socket);
g_free (self->host);
g_free (self->user);
g_free (self->pass);
g_free (self->schema);
g_free (self->queryt);
g_free(self->socket);
g_free(self->host);
g_free(self->user);
g_free(self->pass);
g_free(self->schema);
g_free(self->queryt);
if (self->regex)
g_regex_unref (self->regex);
g_regex_unref(self->regex);
// FIXME: Connection can't be closed because mysql_close() causes MySQL
// process crash with signal 11 when the process is shutdown.
// MySQL version 5.5.40
//if (self->conn_pool)
// g_async_queue_unref (self->conn_pool);
// g_async_queue_unref(self->conn_pool);
}
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);
g_mutex_clear (&self->mutex);
g_free (self);
proxy_auth_deinit(self);
g_mutex_clear(&self->mutex);
g_free(self);
}
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;
GError * error = NULL;
proxy_auth_deinit (self);
proxy_auth_deinit(self);
self->initialized = TRUE;
self->socket = NULL;
self->host = NULL;
@ -120,53 +123,53 @@ proxy_auth_init (ProxyAuth * self)
self->last_error = 0;
self->debug = FALSE;
mysql_library_init (0, NULL, NULL);
mysql_library_init(0, NULL, NULL);
// 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;
}
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)
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->pass = g_key_file_get_string (key_file, "db", "pass", 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->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->user = g_key_file_get_string(key_file, "db", "user", 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->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->debug = g_key_file_get_boolean(key_file, "db", "debug", NULL);
// 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;
}
// Creates the regular expression
self->regex = g_regex_new ("#\\w+",
self->regex = g_regex_new("#\\w+",
G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, &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;
}
// 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->last_error = 0;
@ -175,26 +178,26 @@ proxy_auth_init (ProxyAuth * self)
res = TRUE;
end:
g_clear_error (&error);
g_key_file_free (key_file);
g_clear_error(&error);
g_key_file_free(key_file);
return res;
}
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;
gchar * match = g_match_info_fetch (info, 0);
gchar * match = g_match_info_fetch(info, 0);
gchar * str = NULL;
gulong str_len;
if (!g_strcmp0 (match, "#user"))
if (!g_strcmp0(match, "#user"))
{
str = regex_data->user;
str_len = regex_data->user_len;
}
else if (!g_strcmp0 (match, "#pass"))
else if (!g_strcmp0(match, "#pass"))
{
str = regex_data->pass;
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;
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
//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_real_escape_string(regex_data->conn, 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_c (res, '\'');
g_string_append_len(res, escaped_str,(gssize) scaped_len);
g_string_append_c(res, '\'');
}
else
g_string_append (res, match);
g_string_append(res, match);
g_free (match);
g_free(match);
return FALSE;
}
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;
guint conn_error = mysql_errno (conn);
guint conn_error = mysql_errno(conn);
if (conn_error && self->last_error != conn_error)
g_warning ("ProxyAuth: Can't connect to database: %s", mysql_error (conn));
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 connect to database: %s", mysql_error(conn));
else if (mysql_set_character_set(conn, "latin1"))
g_warning("ProxyAuth: Can't set character set: %s", mysql_error(conn));
self->last_error = conn_error;
return connected;
}
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;
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;
if (info->user_name == NULL
&& (user_len = vio->read_packet (vio, &pkt)) < 0)
&&(user_len = vio->read_packet(vio, &pkt)) < 0)
return CR_ERROR;
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
int pass_len = vio->read_packet (vio, &pkt) - 1;
int pass_len = vio->read_packet(vio, &pkt) - 1;
if (pass_len < 0)
return CR_ERROR;
@ -274,49 +277,49 @@ proxy_auth_authenticate (ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_
}
char pass[pass_len + 1];
memcpy (pass, pkt, pass_len);
memcpy(pass, pkt, pass_len);
pass[pass_len] = '\0';
info->password_used = PASSWORD_USED_YES;
// 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)
{
g_mutex_lock (&self->mutex);
g_mutex_lock(&self->mutex);
if (self->pool_size < self->max_connections)
{
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--;
g_mutex_unlock (&self->mutex);
g_mutex_unlock(&self->mutex);
mysql_close (conn);
mysql_close(conn);
conn = NULL;
goto end;
}
}
else
{
g_mutex_unlock (&self->mutex);
conn = (MYSQL *) g_async_queue_pop (self->conn_pool);
g_mutex_unlock(&self->mutex);
conn = (MYSQL *) g_async_queue_pop(self->conn_pool);
}
}
switch (mysql_errno (conn))
switch (mysql_errno(conn))
{
case CR_SERVER_LOST:
case CR_SERVER_GONE_ERROR:
if (!proxy_auth_reconnect (self, conn))
if (!proxy_auth_reconnect(self, conn))
goto end;
}
@ -329,100 +332,137 @@ proxy_auth_authenticate (ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_
regex_data.pass = pass;
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);
if (error)
{
g_warning ("ProxyAuth: Can't evaluate regex: %s", error->message);
g_warning("ProxyAuth: Can't evaluate regex: %s", error->message);
goto end;
}
// Sends the query to the database
if (self->debug)
g_message ("ProxyAuth: Query: %s", query);
g_message("ProxyAuth: Query: %s", query);
MYSQL_RES * result;
if (!mysql_query (conn, query)
&& (result = mysql_store_result (conn)))
if (!mysql_query(conn, query)
&&(result = mysql_store_result(conn)))
{
MYSQL_ROW row = mysql_fetch_row (result);
MYSQL_ROW row = mysql_fetch_row(result);
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)
{
strcpy (info->external_user, info->user_name);
strncpy (info->authenticated_as, row[0], row_len);
strcpy(info->external_user, info->user_name);
strncpy(info->authenticated_as, row[0], row_len);
info->authenticated_as[row_len] = '\0';
res = CR_OK;
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
g_warning ("ProxyAuth: Error executing query: %s", mysql_error (conn));
g_warning("ProxyAuth: Error executing query: %s", mysql_error(conn));
end:
if (conn)
g_async_queue_push (self->conn_pool, conn);
g_async_queue_push(self->conn_pool, conn);
g_clear_error (&error);
g_free (query);
g_clear_error(&error);
g_free(query);
return res;
}
ProxyAuth * pauth = NULL;
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
proxy_auth_plugin_init ()
proxy_auth_plugin_init()
{
pauth = proxy_auth_new ();
return proxy_auth_init (pauth) ? 0 : 1;
pauth = proxy_auth_new();
return proxy_auth_init(pauth) ? 0 : 1;
}
static int
proxy_auth_plugin_deinit ()
proxy_auth_plugin_deinit()
{
proxy_auth_free (pauth);
proxy_auth_free(pauth);
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
,"mysql_clear_password" // Cleartext plugin required in the client
,proxy_auth_plugin_main
if (*buflen < inbuflen)
return 1;
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_AUTHENTICATION_PLUGIN
,&proxy_auth_handler
,"proxy_auth"
,"Alejandro T. Colombini"
,"Proxy user authentication server-side plugin"
,PLUGIN_LICENSE_GPL
,proxy_auth_plugin_init
,proxy_auth_plugin_deinit
,0x0100 // version 1.0
,NULL
,NULL
,NULL
,0
MYSQL_AUTHENTICATION_PLUGIN,
&proxy_auth_handler,
"proxy_auth",
"Alejandro T. Colombini",
"Proxy user authentication server-side plugin",
PLUGIN_LICENSE_GPL,
proxy_auth_plugin_init,
proxy_auth_plugin_deinit,
0x0100, // version 1.0,
NULL,
NULL,
NULL,
0,
}
mysql_declare_plugin_end;

View File

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