From 933bf0c347d8a02200c9eb53086a1feb50b427ad Mon Sep 17 00:00:00 2001 From: Juan Date: Mon, 2 Jul 2018 17:20:11 +0200 Subject: [PATCH] Compatibility with Debian stretch & MySQL 5.7 --- .gitignore | 19 ++- INSTALL | 12 +- Makefile.decl | 2 +- clean.sh | 18 +++ debian/changelog | 2 +- debian/compat | 2 +- proxy-test/test.sql | 4 + src/functions/sql_printf.c | 4 +- src/proxy-auth/proxy-auth.c | 268 +++++++++++++++++++--------------- src/proxy-auth/proxy-auth.sql | 6 +- 10 files changed, 203 insertions(+), 134 deletions(-) create mode 100755 clean.sh diff --git a/.gitignore b/.gitignore index 5952efe..cbc9f02 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/INSTALL b/INSTALL index a1e89e1..2099840 100644 --- a/INSTALL +++ b/INSTALL @@ -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. - diff --git a/Makefile.decl b/Makefile.decl index d057d63..f9a7be6 100644 --- a/Makefile.decl +++ b/Makefile.decl @@ -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) diff --git a/clean.sh b/clean.sh new file mode 100755 index 0000000..95f28ab --- /dev/null +++ b/clean.sh @@ -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` \ No newline at end of file diff --git a/debian/changelog b/debian/changelog index a23c0a7..690a8e9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -vn-mysql (1.4-deb8) unstable; urgency=low +vn-mysql (1.5.0) unstable; urgency=low * Initial Release. diff --git a/debian/compat b/debian/compat index 45a4fb7..f11c82a 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -8 +9 \ No newline at end of file diff --git a/proxy-test/test.sql b/proxy-test/test.sql index 77d2dc9..0731f4f 100644 --- a/proxy-test/test.sql +++ b/proxy-test/test.sql @@ -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 ''@'%'; diff --git a/src/functions/sql_printf.c b/src/functions/sql_printf.c index a36eb9d..d3bcf27 100644 --- a/src/functions/sql_printf.c +++ b/src/functions/sql_printf.c @@ -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; diff --git a/src/proxy-auth/proxy-auth.c b/src/proxy-auth/proxy-auth.c index 351ed5b..7cedc37 100644 --- a/src/proxy-auth/proxy-auth.c +++ b/src/proxy-auth/proxy-auth.c @@ -15,11 +15,14 @@ * along with this program. If not, see . */ +#define MYSQL_ABI_CHECK + #include #include #include #include #include + #include #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, ®ex_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; - diff --git a/src/proxy-auth/proxy-auth.sql b/src/proxy-auth/proxy-auth.sql index 2eee74a..4b7bd2f 100644 --- a/src/proxy-auth/proxy-auth.sql +++ b/src/proxy-auth/proxy-auth.sql @@ -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