From be04d1a47953188ced936a81824fdf871b8e9656 Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Thu, 29 Oct 2009 22:06:10 -0700 Subject: [PATCH 1/3] Bug#48319: Server crashes on "GRANT/REVOKE ... TO CURRENT_USER" CURRENT_USER() in GRANT ... TO CURRENT_USER() only gave us a definer, not a full user (i.e., password-element was not initiliazed). Hence dereferencing the password led to a crash. Properly initializes definers now, just so there are no misunderstandings. Also does some magic so IDENTIFIED BY ... works with CURRENT_USER(). mysql-test/r/grant2.result: Show GRANT ... TO CURRENT_USER() no longer crashes. Show it to work with IDENTIFIED BY to boot. mysql-test/t/grant2.test: Show GRANT ... TO CURRENT_USER() no longer crashes. Show it to work with IDENTIFIED BY to boot. sql/sql_acl.cc: Make IDENTIFIED BY ... work with CURRENT_USER() sql/sql_parse.cc: Zero password-part of definer just in case somebody mistakes this for a complete LEX_USER! --- mysql-test/r/grant2.result | 27 +++++++++++++++++++++++++++ mysql-test/t/grant2.test | 35 +++++++++++++++++++++++++++++++++++ sql/sql_acl.cc | 7 +++++++ sql/sql_parse.cc | 5 +++++ 4 files changed, 74 insertions(+) diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 7c2023127f0..12269f0cb1c 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -443,3 +443,30 @@ DROP TABLE db1.t1, db1.t2; DROP USER mysqltest1@localhost; DROP DATABASE db1; End of 5.0 tests +USE mysql; +SELECT LEFT(CURRENT_USER(),INSTR(CURRENT_USER(),'@')-1) INTO @u; +SELECT MID(CURRENT_USER(),INSTR(CURRENT_USER(),'@')+1) INTO @h; +SELECT password FROM user WHERE user=@u AND host=@h INTO @pwd; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost Y +UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost N +GRANT INSERT ON *.* TO CURRENT_USER(); +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost Y +UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h; +GRANT INSERT ON *.* TO CURRENT_USER() IDENTIFIED BY 'keksdose'; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost *0BB7188CF0DE9B403BA66E9DD810D82652D002EB Y +UPDATE user SET password=@pwd WHERE user=@u AND host=@h; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost Y +FLUSH PRIVILEGES; +USE test; +End of 5.1 tests diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 54cdf8d6cc1..447848013f9 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -632,5 +632,40 @@ DROP DATABASE db1; --echo End of 5.0 tests +# +# Bug #48319: Server crashes on "GRANT/REVOKE ... TO CURRENT_USER" +# + +# work out who we are. +USE mysql; +SELECT LEFT(CURRENT_USER(),INSTR(CURRENT_USER(),'@')-1) INTO @u; +SELECT MID(CURRENT_USER(),INSTR(CURRENT_USER(),'@')+1) INTO @h; +SELECT password FROM user WHERE user=@u AND host=@h INTO @pwd; + +# show current privs. +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; + +# toggle INSERT +UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; + +# show that GRANT ... TO CURRENT_USER() no longer crashes +GRANT INSERT ON *.* TO CURRENT_USER(); +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h; + +# show that GRANT ... TO CURRENT_USER() IDENTIFIED BY ... works now +GRANT INSERT ON *.* TO CURRENT_USER() IDENTIFIED BY 'keksdose'; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; + +UPDATE user SET password=@pwd WHERE user=@u AND host=@h; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; + +FLUSH PRIVILEGES; + +USE test; + +--echo End of 5.1 tests + # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0592bb3be1d..5259b560532 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3451,6 +3451,13 @@ bool mysql_grant(THD *thd, const char *db, List &list, result= TRUE; continue; } + /* + No User, but a password? + They did GRANT ... TO CURRENT_USER() IDENTIFIED BY ... ! + Get the current user, and shallow-copy the new password to them! + */ + if (!tmp_Str->user.str && tmp_Str->password.str) + Str->password= tmp_Str->password; if (replace_user_table(thd, tables[0].table, *Str, (!db ? rights : 0), revoke_grant, create_new_users, test(thd->variables.sql_mode & diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2e150ca1542..65d86814045 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7573,6 +7573,9 @@ void get_default_definer(THD *thd, LEX_USER *definer) definer->host.str= (char *) sctx->priv_host; definer->host.length= strlen(definer->host.str); + + definer->password.str= NULL; + definer->password.length= 0; } @@ -7624,6 +7627,8 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) definer->user= *user_name; definer->host= *host_name; + definer->password.str= NULL; + definer->password.length= 0; return definer; } From 1b0be8c5b8b419419867b29014d36503404c66b3 Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Mon, 2 Nov 2009 00:46:00 -0800 Subject: [PATCH 2/3] Bug#47655: Memory free error when connecting to 4.1 server from 5.1+ client When starting the (5.1+) mysql command-line client, we try to get "select @@version_comment" from the server to present it to the user. Recent clients are aware that older servers do not have that variable and fall back on other info to be able to present *something* at least. This fallback string was allocated through the POSIX interface, but released through the my*() suite, which rightfully complained about the imbalance in calls when compiled with --debug. While this wasn't as bad as it looked (no double-free, use of uninitialized or freed buffer, etc.), it did look funky. Using my_strdup() now for what will be my_free()d later. client/mysql.cc: Use my_strdup() for server_version, as we'll my_free() it later and don't want to upset the mysql client's memory accounting. --- client/mysql.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index b76a3d624ab..4f9aef411ca 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -4474,9 +4474,7 @@ server_version_string(MYSQL *con) */ if (server_version == NULL) - { - server_version= strdup(mysql_get_server_info(con)); - } + server_version= my_strdup(mysql_get_server_info(con), MYF(MY_WME)); } return server_version ? server_version : ""; From 6cfe31e382ac5fb22eada408dc37eb368536a592 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 24 Nov 2009 19:25:23 -0200 Subject: [PATCH 3/3] Post-merge fix for bug 41728: revert fix that was pushed in mistake to 5.1 and up. --- include/mysql.h | 10 ---------- include/mysql.h.pp | 10 ---------- libmysql/libmysql.c | 14 -------------- libmysql/libmysql.def | 1 - libmysqld/libmysqld.def | 1 - 5 files changed, 36 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index 68cce3196a0..d114afb6c93 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -557,16 +557,6 @@ unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); void STDCALL mysql_debug(const char *debug); -char * STDCALL mysql_odbc_escape_string(MYSQL *mysql, - char *to, - unsigned long to_length, - const char *from, - unsigned long from_length, - void *param, - char * - (*extend_buffer) - (void *, char *to, - unsigned long *length)); void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int STDCALL mysql_thread_safe(void); my_bool STDCALL mysql_embedded(void); diff --git a/include/mysql.h.pp b/include/mysql.h.pp index bd4c79916dd..633cde41130 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -518,16 +518,6 @@ unsigned long mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); void mysql_debug(const char *debug); -char * mysql_odbc_escape_string(MYSQL *mysql, - char *to, - unsigned long to_length, - const char *from, - unsigned long from_length, - void *param, - char * - (*extend_buffer) - (void *, char *to, - unsigned long *length)); void myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int mysql_thread_safe(void); my_bool mysql_embedded(void); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 77ff2a01d7c..1264f2765ba 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1629,20 +1629,6 @@ mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, return (uint) escape_string_for_mysql(mysql->charset, to, 0, from, length); } - -char * STDCALL -mysql_odbc_escape_string(MYSQL *mysql __attribute__((unused)), - char *to __attribute__((unused)), - ulong to_length __attribute__((unused)), - const char *from __attribute__((unused)), - ulong from_length __attribute__((unused)), - void *param __attribute__((unused)), - char * (*extend_buffer)(void *, char *, ulong *) - __attribute__((unused))) -{ - return NULL; -} - void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name) { diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 8c6b71d9553..81f86dc8726 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -78,7 +78,6 @@ EXPORTS mysql_next_result mysql_num_fields mysql_num_rows - mysql_odbc_escape_string mysql_options mysql_stmt_param_count mysql_stmt_param_metadata diff --git a/libmysqld/libmysqld.def b/libmysqld/libmysqld.def index e0f02003963..047cfe0fe57 100644 --- a/libmysqld/libmysqld.def +++ b/libmysqld/libmysqld.def @@ -50,7 +50,6 @@ EXPORTS mysql_next_result mysql_num_fields mysql_num_rows - mysql_odbc_escape_string mysql_options mysql_ping mysql_query