From e2219ec965a80b2034d9debcbf12d3e73a684d89 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 8 Aug 2008 13:11:27 +0200 Subject: wt_thd_lazy_init(), per-thread deadlock search depths and timeouts mysys/array.c: lazy alloc in dynamic array sql-common/client.c: for dynamic array, specify init_alloc==alloc_increment explicitly sql/mysqld.cc: per-thread deadlock search depths and timeouts sql/set_var.cc: per-thread deadlock search depths and timeouts sql/sql_class.h: per-thread deadlock search depths and timeouts --- sql-common/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql-common/client.c') diff --git a/sql-common/client.c b/sql-common/client.c index 63c746a3f5a..51744484623 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -996,7 +996,7 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd) { options->init_commands= (DYNAMIC_ARRAY*)my_malloc(sizeof(DYNAMIC_ARRAY), MYF(MY_WME)); - init_dynamic_array(options->init_commands,sizeof(char*),0,5 CALLER_INFO); + init_dynamic_array(options->init_commands,sizeof(char*),5,5 CALLER_INFO); } if (!(tmp= my_strdup(cmd,MYF(MY_WME))) || -- cgit v1.2.1 From e84748406cac825127279a16482756539267ec17 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 23 Jun 2009 14:00:24 +0200 Subject: Fix memory leak in mysql_ssl_set() when called more than once. Fix sleep() synchronisation in innodb_information_schema test case. mysql-test/t/innodb_information_schema.test: Using sleep for synchronisation does not work!!! Replace by looping until the required condition is met. sql-common/client.c: mysql_ssl_set() did not free old pointers before overwriting with new ones (happens when mysql_ssl_set() is called twice without calling mysql_close() in-between). This sometimes caused memory leaks in the slave depending on exact timing of master/slave shutdown. Fixed by freeing old pointers before installing new ones in mysql_ssl_set(), just like mysql_options() does. --- sql-common/client.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sql-common/client.c') diff --git a/sql-common/client.c b/sql-common/client.c index fcee0d80e16..eae3728020f 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1585,6 +1585,11 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) , { DBUG_ENTER("mysql_ssl_set"); #ifdef HAVE_OPENSSL + my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR)); mysql->options.ssl_key= strdup_if_not_null(key); mysql->options.ssl_cert= strdup_if_not_null(cert); mysql->options.ssl_ca= strdup_if_not_null(ca); -- cgit v1.2.1 From 9aafd0dae2e9302b7af877f1670b5dc7360a7daf Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 3 Dec 2009 17:26:54 +0200 Subject: Ensure that mysql_get_server_version() also works if there is a non numerical prefix before the version number --- sql-common/client.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sql-common/client.c') diff --git a/sql-common/client.c b/sql-common/client.c index 9a8444a84e9..56d4cf04044 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -3208,7 +3208,7 @@ const char * STDCALL mysql_error(MYSQL *mysql) mysql Connection EXAMPLE - 4.1.0-alfa -> 40100 + MariaDB-4.1.0-alfa -> 40100 NOTES We will ensure that a newer server always has a bigger number. @@ -3221,7 +3221,11 @@ ulong STDCALL mysql_get_server_version(MYSQL *mysql) { uint major, minor, version; - char *pos= mysql->server_version, *end_pos; + const char *pos= mysql->server_version; + char *end_pos; + /* Skip possible prefix */ + while (*pos && !my_isdigit(&my_charset_latin1, *pos)) + pos++; major= (uint) strtoul(pos, &end_pos, 10); pos=end_pos+1; minor= (uint) strtoul(pos, &end_pos, 10); pos=end_pos+1; version= (uint) strtoul(pos, &end_pos, 10); -- cgit v1.2.1 From f83113df07d6ef8e8a6d1db8f6dc3bb90fb0652a Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 6 Jan 2010 21:20:16 +0200 Subject: Applied Antony T Curtis patch for declaring many CHARSET objects as const Removed compiler warnings extra/libevent/epoll.c: Removed compiler warnings extra/libevent/evbuffer.c: Removed compiler warnings extra/libevent/event.c: Removed compiler warnings extra/libevent/select.c: Removed compiler warnings extra/libevent/signal.c: Removed compiler warnings include/m_ctype.h: Define CHARSET_INFO, MY_CHARSET_HANDLER, MY_COLLATION_HANDLER, MY_UNICASE_INFO, MY_UNI_CTYPE and MY_UNI_IDX as const structures. Declare that pointers point to const data include/m_string.h: Declare that pointers point to const data include/my_sys.h: Redefine variables and function prototypes include/mysql.h: Declare charset as const include/mysql.h.pp: Declare charset as const include/mysql/plugin.h: Declare charset as const include/mysql/plugin.h.pp: Declare charset as const mysys/charset-def.c: Charset can't be of type CHARSET_INFO as they are changed when they are initialized. mysys/charset.c: Functions that change CHARSET_INFO must use 'struct charset_info_st' Add temporary variables to not have to change all_charsets[] (Which now is const) sql-common/client.c: Added cast to const sql/item_cmpfunc.h: Added cast to avoid compiler error. sql/sql_class.cc: Added cast to const sql/sql_lex.cc: Added cast to const storage/maria/ma_ft_boolean_search.c: Added cast to avoid compiler error. storage/maria/ma_ft_parser.c: Added cast to avoid compiler error. storage/maria/ma_search.c: Added cast to const storage/myisam/ft_boolean_search.c: Added cast to avoid compiler error storage/myisam/ft_parser.c: Added cast to avoid compiler error storage/myisam/mi_search.c: Added cast to const storage/pbxt/src/datadic_xt.cc: Added cast to const storage/pbxt/src/ha_pbxt.cc: Added cast to const Removed compiler warning by changing prototype of XTThreadPtr() storage/pbxt/src/myxt_xt.h: Character sets should be const storage/pbxt/src/xt_defs.h: Character sets should be const storage/xtradb/btr/btr0cur.c: Removed compiler warning strings/conf_to_src.c: Added const Functions that change CHARSET_INFO must use 'struct charset_info_st' strings/ctype-big5.c: Made arrays const strings/ctype-bin.c: Made arrays const strings/ctype-cp932.c: Made arrays const strings/ctype-czech.c: Made arrays const strings/ctype-euc_kr.c: Made arrays const strings/ctype-eucjpms.c: Made arrays const strings/ctype-extra.c: Made arrays const strings/ctype-gb2312.c: Made arrays const strings/ctype-gbk.c: Made arrays const strings/ctype-latin1.c: Made arrays const strings/ctype-mb.c: Made arrays const strings/ctype-simple.c: Made arrays const strings/ctype-sjis.c: Made arrays const strings/ctype-tis620.c: Made arrays const strings/ctype-uca.c: Made arrays const strings/ctype-ucs2.c: Made arrays const strings/ctype-ujis.c: Made arrays const strings/ctype-utf8.c: Made arrays const strings/ctype-win1250ch.c: Made arrays const strings/ctype.c: Made arrays const Added cast to const Functions that change CHARSET_INFO must use 'struct charset_info_st' strings/int2str.c: Added cast to const --- sql-common/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql-common/client.c') diff --git a/sql-common/client.c b/sql-common/client.c index 56d4cf04044..bff51d08d75 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -3241,7 +3241,7 @@ mysql_get_server_version(MYSQL *mysql) */ int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name) { - struct charset_info_st *cs; + CHARSET_INFO *cs; const char *save_csdir= charsets_dir; if (mysql->options.charset_dir) -- cgit v1.2.1 From e9bce6c9d4bde35306b845e22e9b5ada69c4512f Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 29 Jan 2010 20:42:22 +0200 Subject: Patch set contributed by Alex Budovski (MCA) Fix for Bug#31173: mysqlslap.exe crashes if called without any parameters .bzrignore: Fixed .bzrignore rules. Many were simply not ignoring what they were meant to. client/mysqlslap.c: Fixed bug for Bug#31173: mysqlslap.exe crashes if called without any parameters The original patch could cause memory leaks and odd problems depending on how connection was made. This code ensures that all mysql_options() are set for each mysql_real_connect(). (This patch by Monty) mysys/my_thr_init.c: Fixed multiply-initialized critical section on Windows, due to code incorrectly checking the wrong field in an attempt to prevent multiple-initialization. sql-common/client.c: Don't use shared memory if it's not set (for example after failed mysql_real_connect). Ensure that mysql_close() resets all resources so that it's safe to call it twice. (Patch by monty, related to Bug#31173: mysqlslap.exe crashes if called without any parameters) sql/CMakeLists.txt: Added page fault counters for SHOW PROFILE on Windows. sql/mysqld.cc: Fixed attempt to set a NULL event. The code now only sets the event if appropriate (i.e. shared memory is being used) sql/sql_profile.cc: Added page fault counters for SHOW PROFILE on Windows. sql/sql_profile.h: Added page fault counters for SHOW PROFILE on Windows. sql/udf_example.def: Some cleanup functions were not exported from udf_example.dll, causing them to never be executed, and as a result multiple-initialization of kernel objects occurred and resources were not being freed correctly. storage/maria/ma_close.c: Condition variable share->key_del_cond was never being destroyed, while its containing heap block was being freed in maria_close(), leaking kernel resources. --- sql-common/client.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sql-common/client.c') diff --git a/sql-common/client.c b/sql-common/client.c index 60a1441a189..e09d94b34be 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1940,7 +1940,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, #if defined(HAVE_SMEM) if ((!mysql->options.protocol || mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) && - (!host || !strcmp(host,LOCAL_HOST))) + (!host || !strcmp(host,LOCAL_HOST)) && + mysql->options.shared_memory_base_name) { if ((create_shared_memory(mysql,net, mysql->options.connect_timeout)) == INVALID_HANDLE_VALUE) @@ -1949,7 +1950,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, ("host: '%s' socket: '%s' shared memory: %s have_tcpip: %d", host ? host : "", unix_socket ? unix_socket : "", - (int) mysql->options.shared_memory_base_name, + mysql->options.shared_memory_base_name, (int) have_tcpip)); if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) goto error; @@ -2752,6 +2753,13 @@ void mysql_detach_stmt_list(LIST **stmt_list __attribute__((unused)), } +/* + Close a MySQL connection and free all resources attached to it. + + This function is coded in such that it can be called multiple times + (As some clients call this after mysql_real_connect() fails) +*/ + void STDCALL mysql_close(MYSQL *mysql) { DBUG_ENTER("mysql_close"); @@ -2785,10 +2793,16 @@ void STDCALL mysql_close(MYSQL *mysql) } #endif if (mysql != mysql->master) + { mysql_close(mysql->master); + mysql->master= 0; + } #ifndef MYSQL_SERVER if (mysql->thd) + { (*mysql->methods->free_embedded_thd)(mysql); + mysql->thd= 0; + } #endif if (mysql->free_me) my_free((uchar*) mysql,MYF(0)); -- cgit v1.2.1 From 1fec5af772809d4d67ebc3c84286bc4956b80773 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sun, 28 Mar 2010 21:10:00 +0300 Subject: Fixed compiler warnings and sporadic failures in test cases mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test: Added missing sync_slave_with_master; Fixes random failures mysql-test/include/default_mysqld.cnf: default-character-set -> character-set-server (removes warning in error files for usage of deprecated options) mysql-test/lib/My/SafeProcess/safe_process.cc: Fixed compiler warning mysql-test/lib/v1/mysql-test-run.pl: default-character-set -> character-set-server (removes warning in error files for usage of deprecated options) mysql-test/suite/rpl/r/rpl_do_grant.result: Updated test results mysql-test/suite/rpl/t/rpl_do_grant.test: Added missing sync_slave_with_master; Fixes random failures Had to explictely do stop slave before DROP USER to avoid failure on slave as the user is already dropped on slave. mysql-test/suite/rpl/t/rpl_name_const.test: Added missing sync_slave_with_master; Fixes random failures mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test: Added missing sync_slave_with_master; Fixes random failures mysql-test/t/bug47671-master.opt: default-character-set -> character-set-server (removes warning in error files for usage of deprecated options) mysql-test/t/ctype_latin1_de-master.opt: default-character-set -> character-set-server (removes warning in error files for usage of deprecated options) mysql-test/t/ctype_ucs2_def-master.opt: default-character-set -> character-set-server (removes warning in error files for usage of deprecated options) sql-common/client.c: Fixed compiler warning sql/item.cc: Renamed function to remove compiler warnings (with gcc) sql/item.h: Renamed function to remove compiler warnings (with gcc) sql/item_cmpfunc.cc: Renamed function to remove compiler warnings (with gcc) sql/item_create.cc: Renamed function to remove compiler warnings (with gcc) sql/item_create.h: Renamed function to remove compiler warnings (with gcc) sql/item_sum.cc: Renamed function to remove compiler warnings (with gcc) sql/item_sum.h: Renamed function to remove compiler warnings (with gcc) sql/set_var.cc: Don't use bit_do_set() / bot_is_set() / bit_do_clear() as this generates compiler warnings (They are also of no use as we know the value can hold the bits) sql/sql_yacc.yy: Renamed function to remove compiler warnings (with gcc) storage/example/ha_example.h: Fixed old read_time() prototype storage/maria/ma_search.c: Added extra variables to remove compiler warnings storage/maria/maria_def.h: Added extra variables to remove compiler warnings storage/myisam/ft_stopwords.c: Added cast to get rid of compiler warning storage/xtradb/fil/fil0fil.c: Added cast to get rid of compiler warning storage/xtradb/include/page0page.h: Added const to get rid of compiler warning storage/xtradb/include/page0page.ic: Added const to get rid of compiler warning support-files/compiler_warnings.supp: Added suppression of strict-aliasing --- sql-common/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql-common/client.c') diff --git a/sql-common/client.c b/sql-common/client.c index e09d94b34be..d29f6647255 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1863,7 +1863,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, uint port, const char *unix_socket,ulong client_flag) { char buff[NAME_LEN+USERNAME_LENGTH+100]; - char error_string[1024]; char *end,*host_info= NULL; my_socket sock; in_addr_t ip_addr; @@ -2304,6 +2303,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, /* Do the SSL layering. */ struct st_mysql_options *options= &mysql->options; struct st_VioSSLFd *ssl_fd; + char error_string[1024]; /* Send client_flag, max_packet_size - unencrypted otherwise -- cgit v1.2.1 From 291fd9698340f3d83ff096542720f7335cb078d2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 29 Mar 2010 17:13:53 +0200 Subject: pluggable auth with plugin examples Makefile.am: add new API files to the check_abi rule, remove duplicates client/CMakeLists.txt: now a client can use dlopen too client/Makefile.am: be csh-friendly include/my_global.h: add dummy plugs for dlopen and co. for the code that needs them to work in static builds mysys/Makefile.am: be csh-friendly plugin/auth/dialog.c: typo fixed --- sql-common/client.c | 1108 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 867 insertions(+), 241 deletions(-) (limited to 'sql-common/client.c') diff --git a/sql-common/client.c b/sql-common/client.c index 783c7f6adc8..96620e919f4 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -107,6 +107,10 @@ my_bool net_flush(NET *net); #include "client_settings.h" #include +#include + +#define native_password_plugin_name "mysql_native_password" +#define old_password_plugin_name "mysql_old_password" uint mysql_port=0; char *mysql_unix_port= 0; @@ -332,7 +336,7 @@ void net_clear_error(NET *net) @param ... variable number of arguments */ -static void set_mysql_extended_error(MYSQL *mysql, int errcode, +void set_mysql_extended_error(MYSQL *mysql, int errcode, const char *sqlstate, const char *format, ...) { @@ -1002,9 +1006,20 @@ static const char *default_options[]= "replication-probe", "enable-reads-from-master", "repl-parse-query", "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name", "multi-results", "multi-statements", "multi-queries", "secure-auth", - "report-data-truncation", + "report-data-truncation", "plugin-dir", "default-auth", NullS }; +enum option_id { + OPT_port=1, OPT_socket, OPT_compress, OPT_password, OPT_pipe, OPT_timeout, OPT_user, + OPT_init_command, OPT_host, OPT_database, OPT_debug, OPT_return_found_rows, + OPT_ssl_key, OPT_ssl_cert, OPT_ssl_ca, OPT_ssl_capath, + OPT_character_sets_dir, OPT_default_character_set, OPT_interactive_timeout, + OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile, + OPT_replication_probe, OPT_enable_reads_from_master, OPT_repl_parse_query, + OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name, + OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth, + OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth, +}; static TYPELIB option_types={array_elements(default_options)-1, "options",default_options, NULL}; @@ -1035,6 +1050,15 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd) return 0; } +#define extension_set_string(OPTS, X, STR) \ + if ((OPTS)->extension) \ + my_free((OPTS)->extension->X, MYF(MY_ALLOW_ZERO_PTR)); \ + else \ + (OPTS)->extension= (struct st_mysql_options_extention *) \ + my_malloc(sizeof(struct st_mysql_options_extention), \ + MYF(MY_WME | MY_ZEROFILL)); \ + (OPTS)->extension->X= my_strdup((STR), MYF(MY_WME)); + void mysql_read_default_options(struct st_mysql_options *options, const char *filename,const char *group) { @@ -1067,134 +1091,134 @@ void mysql_read_default_options(struct st_mysql_options *options, for (end= *option ; *(end= strcend(end,'_')) ; ) *end= '-'; switch (find_type(*option+2,&option_types,2)) { - case 1: /* port */ + case OPT_port: if (opt_arg) options->port=atoi(opt_arg); break; - case 2: /* socket */ + case OPT_socket: if (opt_arg) { my_free(options->unix_socket,MYF(MY_ALLOW_ZERO_PTR)); options->unix_socket=my_strdup(opt_arg,MYF(MY_WME)); } break; - case 3: /* compress */ + case OPT_compress: options->compress=1; options->client_flag|= CLIENT_COMPRESS; break; - case 4: /* password */ + case OPT_password: if (opt_arg) { my_free(options->password,MYF(MY_ALLOW_ZERO_PTR)); options->password=my_strdup(opt_arg,MYF(MY_WME)); } break; - case 5: + case OPT_pipe: options->protocol = MYSQL_PROTOCOL_PIPE; - case 20: /* connect_timeout */ - case 6: /* timeout */ + case OPT_connect_timeout: + case OPT_timeout: if (opt_arg) options->connect_timeout=atoi(opt_arg); break; - case 7: /* user */ + case OPT_user: if (opt_arg) { my_free(options->user,MYF(MY_ALLOW_ZERO_PTR)); options->user=my_strdup(opt_arg,MYF(MY_WME)); } break; - case 8: /* init-command */ + case OPT_init_command: add_init_command(options,opt_arg); break; - case 9: /* host */ + case OPT_host: if (opt_arg) { my_free(options->host,MYF(MY_ALLOW_ZERO_PTR)); options->host=my_strdup(opt_arg,MYF(MY_WME)); } break; - case 10: /* database */ + case OPT_database: if (opt_arg) { my_free(options->db,MYF(MY_ALLOW_ZERO_PTR)); options->db=my_strdup(opt_arg,MYF(MY_WME)); } break; - case 11: /* debug */ + case OPT_debug: #ifdef MYSQL_CLIENT mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace"); break; #endif - case 12: /* return-found-rows */ + case OPT_return_found_rows: options->client_flag|=CLIENT_FOUND_ROWS; break; #ifdef HAVE_OPENSSL - case 13: /* ssl_key */ + case OPT_ssl_key: my_free(options->ssl_key, MYF(MY_ALLOW_ZERO_PTR)); options->ssl_key = my_strdup(opt_arg, MYF(MY_WME)); break; - case 14: /* ssl_cert */ + case OPT_ssl_cert: my_free(options->ssl_cert, MYF(MY_ALLOW_ZERO_PTR)); options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME)); break; - case 15: /* ssl_ca */ + case OPT_ssl_ca: my_free(options->ssl_ca, MYF(MY_ALLOW_ZERO_PTR)); options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME)); break; - case 16: /* ssl_capath */ + case OPT_ssl_capath: my_free(options->ssl_capath, MYF(MY_ALLOW_ZERO_PTR)); options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME)); break; - case 26: /* ssl_cipher */ + case OPT_ssl_cipher: my_free(options->ssl_cipher, MYF(MY_ALLOW_ZERO_PTR)); options->ssl_cipher= my_strdup(opt_arg, MYF(MY_WME)); break; #else - case 13: /* Ignore SSL options */ - case 14: - case 15: - case 16: - case 26: + case OPT_ssl_key: + case OPT_ssl_cert: + case OPT_ssl_ca: + case OPT_ssl_capath: + case OPT_ssl_cipher: break; #endif /* HAVE_OPENSSL */ - case 17: /* charset-lib */ + case OPT_character_sets_dir: my_free(options->charset_dir,MYF(MY_ALLOW_ZERO_PTR)); options->charset_dir = my_strdup(opt_arg, MYF(MY_WME)); break; - case 18: + case OPT_default_character_set: my_free(options->charset_name,MYF(MY_ALLOW_ZERO_PTR)); options->charset_name = my_strdup(opt_arg, MYF(MY_WME)); break; - case 19: /* Interactive-timeout */ + case OPT_interactive_timeout: options->client_flag|= CLIENT_INTERACTIVE; break; - case 21: + case OPT_local_infile: if (!opt_arg || atoi(opt_arg) != 0) options->client_flag|= CLIENT_LOCAL_FILES; else options->client_flag&= ~CLIENT_LOCAL_FILES; break; - case 22: + case OPT_disable_local_infile: options->client_flag&= ~CLIENT_LOCAL_FILES; break; - case 23: /* replication probe */ + case OPT_replication_probe: #ifndef TO_BE_DELETED options->rpl_probe= 1; #endif break; - case 24: /* enable-reads-from-master */ + case OPT_enable_reads_from_master: options->no_master_reads= 0; break; - case 25: /* repl-parse-query */ + case OPT_repl_parse_query: #ifndef TO_BE_DELETED options->rpl_parse= 1; #endif break; - case 27: + case OPT_max_allowed_packet: if (opt_arg) options->max_allowed_packet= atoi(opt_arg); break; - case 28: /* protocol */ + case OPT_protocol: if ((options->protocol= find_type(opt_arg, &sql_protocol_typelib,0)) <= 0) { @@ -1202,26 +1226,32 @@ void mysql_read_default_options(struct st_mysql_options *options, exit(1); } break; - case 29: /* shared_memory_base_name */ + case OPT_shared_memory_base_name: #ifdef HAVE_SMEM if (options->shared_memory_base_name != def_shared_memory_base_name) my_free(options->shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); options->shared_memory_base_name=my_strdup(opt_arg,MYF(MY_WME)); #endif break; - case 30: + case OPT_multi_results: options->client_flag|= CLIENT_MULTI_RESULTS; break; - case 31: - case 32: + case OPT_multi_statements: + case OPT_multi_queries: options->client_flag|= CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS; break; - case 33: /* secure-auth */ + case OPT_secure_auth: options->secure_auth= TRUE; break; - case 34: /* report-data-truncation */ + case OPT_report_data_truncation: options->report_data_truncation= opt_arg ? test(atoi(opt_arg)) : 1; break; + case OPT_plugin_dir: + extension_set_string(options, plugin_dir, opt_arg); + break; + case OPT_default_auth: + extension_set_string(options, default_auth, opt_arg); + break; default: DBUG_PRINT("warning",("unknown option: %s",option[0])); } @@ -1765,6 +1795,11 @@ static int ssl_verify_server_cert(Vio *vio, const char* server_hostname) static my_bool cli_read_query_result(MYSQL *mysql); static MYSQL_RES *cli_use_result(MYSQL *mysql); +int cli_read_change_user_result(MYSQL *mysql) +{ + return cli_safe_read(mysql); +} + static MYSQL_METHODS client_methods= { cli_read_query_result, /* read_query_result */ @@ -1772,7 +1807,8 @@ static MYSQL_METHODS client_methods= cli_read_rows, /* read_rows */ cli_use_result, /* use_result */ cli_fetch_lengths, /* fetch_lengths */ - cli_flush_use_result /* flush_use_result */ + cli_flush_use_result, /* flush_use_result */ + cli_read_change_user_result /* read_change_user_result */ #ifndef MYSQL_SERVER ,cli_list_fields, /* list_fields */ cli_read_prepare_result, /* read_prepare_result */ @@ -1782,7 +1818,6 @@ static MYSQL_METHODS client_methods= NULL, /* free_embedded_thd */ cli_read_statistics, /* read_statistics */ cli_read_query_result, /* next_result */ - cli_read_change_user_result, /* read_change_user_result */ cli_read_binary_rows /* read_rows_from_cursor */ #endif }; @@ -1856,6 +1891,646 @@ int mysql_init_character_set(MYSQL *mysql) } C_MODE_END +/*********** client side authentication support **************************/ + +typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t; +static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int); +static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); +static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); + +static auth_plugin_t native_password_client_plugin= +{ + MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION, + native_password_plugin_name, + "R.J.Silk, Sergei Golubchik", + "Native MySQL authentication", + {1, 0, 0}, + NULL, + NULL, + native_password_auth_client +}; + +static auth_plugin_t old_password_client_plugin= +{ + MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION, + old_password_plugin_name, + "R.J.Silk, Sergei Golubchik", + "Old MySQL-3.23 authentication", + {1, 0, 0}, + NULL, + NULL, + old_password_auth_client +}; + +struct st_mysql_client_plugin *mysql_client_builtins[]= +{ + (struct st_mysql_client_plugin *)&native_password_client_plugin, + (struct st_mysql_client_plugin *)&old_password_client_plugin, + 0 +}; + + + +/* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */ +typedef struct { + int (*read_packet)(struct st_plugin_vio *vio, uchar **buf); + int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, int pkt_len); + void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info); + /* -= end of MYSQL_PLUGIN_VIO =- */ + MYSQL *mysql; + auth_plugin_t *plugin; /**< what plugin we're under */ + const char *db; + struct { + uchar *pkt; /**< pointer into NET::buff */ + uint pkt_len; + } cached_server_reply; + uint packets_read, packets_written; /**< counters for send/received packets */ + my_bool mysql_change_user; /**< if it's mysql_change_user() */ + int last_read_packet_len; /**< the length of the last *read* packet */ +} MCPVIO_EXT; + +/** + sends a COM_CHANGE_USER command with a caller provided payload + + Packet format: + + Bytes Content + ----- ---- + n user name - \0-terminated string + n password + 3.23 scramble - \0-terminated string (9 bytes) + otherwise - length (1 byte) coded + n database name - \0-terminated string + 2 character set number (if the server >= 4.1.x) + n client auth plugin name - \0-terminated string, + (if the server supports plugin auth) + + @retval 0 ok + @retval 1 error +*/ + +static int send_change_user_packet(MCPVIO_EXT *mpvio, + const uchar *data, int data_len) +{ + MYSQL *mysql= mpvio->mysql; + char *buff, *end; + int res= 1; + + buff= my_alloca(USERNAME_LENGTH + data_len + 1 + NAME_LEN + 2 + NAME_LEN); + + end= strmake(buff, mysql->user, USERNAME_LENGTH) + 1; + + if (!data_len) + *end++= 0; + else + { + if (mysql->client_flag & CLIENT_SECURE_CONNECTION) + { + DBUG_ASSERT(data_len <= 255); + if (data_len > 255) + { + set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate); + goto error; + } + *end++= data_len; + } + else + { + DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); + DBUG_ASSERT(data[SCRAMBLE_LENGTH_323] == 0); + } + memcpy(end, data, data_len); + end+= data_len; + } + end= strmake(end, mpvio->db ? mpvio->db : "", NAME_LEN) + 1; + + if (mysql->server_capabilities & CLIENT_PROTOCOL_41) + { + int2store(end, (ushort) mysql->charset->number); + end+= 2; + } + + if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) + end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1; + + res= simple_command(mysql, COM_CHANGE_USER, + (uchar*)buff, (ulong)(end-buff), 1); + +error: + my_afree(buff); + return res; +} + + +/** + sends a client authentication packet (second packet in the 3-way handshake) + + Packet format (when the server is 4.0 or earlier): + + Bytes Content + ----- ---- + 2 client capabilities + 3 max packet size + n user name, \0-terminated + 9 scramble_323, \0-terminated + + Packet format (when the server is 4.1 or newer): + + Bytes Content + ----- ---- + 4 client capabilities + 4 max packet size + 1 charset number + 23 reserved (always 0) + n user name, \0-terminated + n plugin auth data (e.g. scramble), length (1 byte) coded + n database name, \0-terminated + (if CLIENT_CONNECT_WITH_DB is set in the capabilities) + n client auth plugin name - \0-terminated string, + (if CLIENT_PLUGIN_AUTH is set in the capabilities) + + @retval 0 ok + @retval 1 error +*/ + +static int send_client_reply_packet(MCPVIO_EXT *mpvio, + const uchar *data, int data_len) +{ + MYSQL *mysql= mpvio->mysql; + NET *net= &mysql->net; + char *buff, *end; + + /* see end= buff+32 below, fixed size of the packet is 32 bytes */ + buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN); + + mysql->client_flag|= mysql->options.client_flag; + mysql->client_flag|= CLIENT_CAPABILITIES; + + if (mysql->client_flag & CLIENT_MULTI_STATEMENTS) + mysql->client_flag|= CLIENT_MULTI_RESULTS; + +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) + if (mysql->options.ssl_key || mysql->options.ssl_cert || + mysql->options.ssl_ca || mysql->options.ssl_capath || + mysql->options.ssl_cipher) + mysql->options.use_ssl= 1; + if (mysql->options.use_ssl) + mysql->client_flag|= CLIENT_SSL; +#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/ + if (mpvio->db) + mysql->client_flag|= CLIENT_CONNECT_WITH_DB; + + /* Remove options that server doesn't support */ + mysql->client_flag= mysql->client_flag & + (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41) + | mysql->server_capabilities); + +#ifndef HAVE_COMPRESS + mysql->client_flag&= ~CLIENT_COMPRESS; +#endif + + if (mysql->client_flag & CLIENT_PROTOCOL_41) + { + /* 4.1 server and 4.1 client has a 32 byte option flag */ + int4store(buff,mysql->client_flag); + int4store(buff+4, net->max_packet_size); + buff[8]= (char) mysql->charset->number; + bzero(buff+9, 32-9); + end= buff+32; + } + else + { + int2store(buff, mysql->client_flag); + int3store(buff+2, net->max_packet_size); + end= buff+5; + } +#ifdef HAVE_OPENSSL + if (mysql->client_flag & CLIENT_SSL) + { + /* Do the SSL layering. */ + struct st_mysql_options *options= &mysql->options; + struct st_VioSSLFd *ssl_fd; + char error_string[1024]; + + /* + Send mysql->client_flag, max_packet_size - unencrypted otherwise + the server does not know we want to do SSL + */ + if (my_net_write(net, (uchar*)buff, (size_t) (end-buff)) || net_flush(net)) + { + set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, + ER(CR_SERVER_LOST_EXTENDED), + "sending connection information to server", + errno); + goto error; + } + + /* Create the VioSSLConnectorFd - init SSL and load certs */ + if (!(ssl_fd= new_VioSSLConnectorFd(options->ssl_key, + options->ssl_cert, + options->ssl_ca, + options->ssl_capath, + options->ssl_cipher))) + { + set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); + goto error; + } + mysql->connector_fd= (void*)ssl_fd; + + /* Connect to the server */ + DBUG_PRINT("info", ("IO layer change in progress...")); + if (sslconnect(ssl_fd, net->vio, + (long) (mysql->options.connect_timeout), + error_string)) + { + set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, + unknown_sqlstate, "SSL error: %s", + error_string[0] ? error_string : + ER(CR_SSL_CONNECTION_ERROR)); + goto error; + } + DBUG_PRINT("info", ("IO layer change done!")); + + /* Verify server cert */ + if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && + ssl_verify_server_cert(net->vio, mysql->host)) + { + set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); + goto error; + } + } +#endif /* HAVE_OPENSSL */ + + DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu", + mysql->server_version, mysql->server_capabilities, + mysql->server_status, mysql->client_flag)); + + compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH); + + /* This needs to be changed as it's not useful with big packets */ + if (mysql->user[0]) + strmake(end, mysql->user, USERNAME_LENGTH); + else + read_user_name(end); + + /* We have to handle different version of handshake here */ + DBUG_PRINT("info",("user: %s",end)); + end= strend(end) + 1; + if (data_len) + { + if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) + { + *end++= data_len; + memcpy(end, data, data_len); + end+= data_len; + } + else + { + DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); /* incl. \0 at the end */ + memcpy(end, data, data_len); + end+= data_len; + } + } + else + *end++= 0; + + /* Add database if needed */ + if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) + { + end= strmake(end, mpvio->db, NAME_LEN) + 1; + mysql->db= my_strdup(mpvio->db, MYF(MY_WME)); + } + + if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) + end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1; + + /* Write authentication package */ + if (my_net_write(net, (uchar*) buff, (size_t) (end-buff)) || net_flush(net)) + { + set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, + ER(CR_SERVER_LOST_EXTENDED), + "sending authentication information", + errno); + goto error; + } + my_afree(buff); + return 0; + +error: + my_afree(buff); + return 1; +} + + +/** + vio->read_packet() callback method for client authentication plugins + + This function is called by a client authentication plugin, when it wants + to read data from the server. +*/ + +static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf) +{ + MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv; + MYSQL *mysql= mpvio->mysql; + ulong pkt_len; + + /* there are cached data left, feed it to a plugin */ + if (mpvio->cached_server_reply.pkt) + { + *buf= mpvio->cached_server_reply.pkt; + mpvio->cached_server_reply.pkt= 0; + mpvio->packets_read++; + return mpvio->cached_server_reply.pkt_len; + } + + if (mpvio->packets_read == 0) + { + /* + the server handshake packet came from the wrong plugin, + or it's mysql_change_user(). Either way, there is no data + for a plugin to read. send a dummy packet to the server + to initiate a dialog. + */ + if (client_mpvio_write_packet(mpv, 0, 0)) + return (int)packet_error; + } + + /* otherwise read the data */ + pkt_len= (*mysql->methods->read_change_user_result)(mysql); + mpvio->last_read_packet_len= pkt_len; + *buf= mysql->net.read_pos; + + /* was it a request to change plugins ? */ + if (**buf == 254) + return (int)packet_error; /* if yes, this plugin shan't continue */ + + /* + the server sends \1\255 or \1\254 instead of just \255 or \254 - + for us to not confuse it with an error or "change plugin" packets. + We remove this escaping \1 here. + + See also server_mpvio_write_packet() where the escaping is done. + */ + if (pkt_len && **buf == 1) + { + (*buf)++; + pkt_len--; + } + mpvio->packets_read++; + return pkt_len; +} + + +/** + vio->write_packet() callback method for client authentication plugins + + This function is called by a client authentication plugin, when it wants + to send data to the server. + + It transparently wraps the data into a change user or authentication + handshake packet, if neccessary. +*/ + +static int client_mpvio_write_packet(struct st_plugin_vio *mpv, + const uchar *pkt, int pkt_len) +{ + int res; + MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv; + + if (mpvio->packets_written == 0) + { + if (mpvio->mysql_change_user) + res= send_change_user_packet(mpvio, pkt, pkt_len); + else + res= send_client_reply_packet(mpvio, pkt, pkt_len); + } + else + { + NET *net= &mpvio->mysql->net; + if (mpvio->mysql->thd) + res= 1; /* no chit-chat in embedded */ + else + res= my_net_write(net, pkt, pkt_len) || net_flush(net); + if (res) + set_mysql_extended_error(mpvio->mysql, CR_SERVER_LOST, unknown_sqlstate, + ER(CR_SERVER_LOST_EXTENDED), + "sending authentication information", + errno); + } + mpvio->packets_written++; + return res; +} + + +/** + fills MYSQL_PLUGIN_VIO_INFO structure with the information about the + connection +*/ + +void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info) +{ + bzero(info, sizeof(*info)); + switch (vio->type) { + case VIO_TYPE_TCPIP: + info->protocol= MYSQL_VIO_TCP; + info->socket= vio->sd; + return; + case VIO_TYPE_SOCKET: + info->protocol= MYSQL_VIO_SOCKET; + info->socket= vio->sd; + return; + case VIO_TYPE_SSL: + { + struct sockaddr addr; + socklen_t addrlen= sizeof(addr); + if (getsockname(vio->sd, &addr, &addrlen)) + return; + info->protocol= addr.sa_family == AF_UNIX ? + MYSQL_VIO_SOCKET : MYSQL_VIO_TCP; + info->socket= vio->sd; + return; + } +#ifdef _WIN32 + case VIO_TYPE_NAMEDPIPE: + info->protocol= MYSQL_VIO_PIPE; + info->handle= vio->hPipe; + return; + case VIO_TYPE_SHARED_MEMORY: + info->protocol= MYSQL_VIO_MEMORY; + info->handle= vio->handle_client_file_map; /* or what ? */ + return; +#endif + default: DBUG_ASSERT(0); + } +} + + +static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio, + MYSQL_PLUGIN_VIO_INFO *info) +{ + MCPVIO_EXT *mpvio= (MCPVIO_EXT*)vio; + mpvio_info(mpvio->mysql->net.vio, info); +} + + +/** + Client side of the plugin driver authentication. + + @note this is used by both the mysql_real_connect and mysql_change_user + + @param mysql mysql + @param data pointer to the plugin auth data (scramble) in the + handshake packet + @param data_len the length of the data + @param data_plugin a plugin that data were prepared for + or 0 if it's mysql_change_user() + @param db initial db to use, can be 0 + + @retval 0 ok + @retval 1 error +*/ + +int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, + char *data_plugin, const char *db) +{ + const char *auth_plugin_name; + auth_plugin_t *auth_plugin; + MCPVIO_EXT mpvio; + ulong pkt_length; + int res; + + /* determine the default/initial plugin to use */ + if (mysql->options.extension && mysql->options.extension->default_auth && + mysql->server_capabilities & CLIENT_PLUGIN_AUTH) + { + auth_plugin_name= mysql->options.extension->default_auth; + if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql, + auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) + return 1; /* oops, not found */ + } + else + { + auth_plugin= mysql->server_capabilities & CLIENT_PROTOCOL_41 ? + &native_password_client_plugin : &old_password_client_plugin; + auth_plugin_name= auth_plugin->name; + } + + mysql->net.last_errno= 0; /* just in case */ + + if (data_plugin && strcmp(data_plugin, auth_plugin_name)) + { + /* data was prepared for a different plugin, don't show it to this one */ + data= 0; + data_len= 0; + } + + mpvio.mysql_change_user= data_plugin == 0; + mpvio.cached_server_reply.pkt= (uchar*)data; + mpvio.cached_server_reply.pkt_len= data_len; + mpvio.read_packet= client_mpvio_read_packet; + mpvio.write_packet= client_mpvio_write_packet; + mpvio.info= client_mpvio_info; + mpvio.mysql= mysql; + mpvio.packets_read= mpvio.packets_written= 0; + mpvio.db= db; + mpvio.plugin= auth_plugin; + + res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql); + + compile_time_assert(CR_OK == -1); + compile_time_assert(CR_ERROR == 0); + if (res > CR_OK && mysql->net.read_pos[0] != 254) + { + /* + the plugin returned an error. write it down in mysql, + unless the error code is CR_ERROR and mysql->net.last_errno + is already set (the plugin has done it) + */ + if (res > CR_ERROR) + set_mysql_error(mysql, res, unknown_sqlstate); + else + if (!mysql->net.last_errno) + set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); + return 1; + } + + /* read the OK packet (or use the cached value in mysql->net.read_pos */ + if (res == CR_OK) + pkt_length= (*mysql->methods->read_change_user_result)(mysql); + else /* res == CR_OK_HANDSHAKE_COMPLETE */ + pkt_length= mpvio.last_read_packet_len; + + if (pkt_length == packet_error) + { + if (mysql->net.last_errno == CR_SERVER_LOST) + set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, + ER(CR_SERVER_LOST_EXTENDED), + "reading authorization packet", + errno); + return 1; + } + + if (mysql->net.read_pos[0] == 254) + { + /* The server asked to use a different authentication plugin */ + if (pkt_length == 1) + { + /* old "use short scramble" packet */ + auth_plugin_name= old_password_plugin_name; + mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble; + mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1; + } + else + { + /* new "use different plugin" packet */ + uint len; + auth_plugin_name= (char*)mysql->net.read_pos + 1; + len= strlen(auth_plugin_name); /* safe as my_net_read always appends \0 */ + mpvio.cached_server_reply.pkt_len= pkt_length - len - 2; + mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2; + } + + if (!(auth_plugin= (auth_plugin_t *) mysql_client_find_plugin(mysql, + auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) + return 1; + + mpvio.plugin= auth_plugin; + res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql); + + if (res > CR_OK) + { + if (res > CR_ERROR) + set_mysql_error(mysql, res, unknown_sqlstate); + else + if (!mysql->net.last_errno) + set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); + return 1; + } + + if (res != CR_OK_HANDSHAKE_COMPLETE) + { + /* Read what server thinks about out new auth message report */ + if (cli_safe_read(mysql) == packet_error) + { + if (mysql->net.last_errno == CR_SERVER_LOST) + set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, + ER(CR_SERVER_LOST_EXTENDED), + "reading final connect information", + errno); + return 1; + } + } + } + /* + net->read_pos[0] should always be 0 here if the server implements + the protocol correctly + */ + return mysql->net.read_pos[0] != 0; +} + MYSQL * STDCALL CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, @@ -1863,8 +2538,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, uint port, const char *unix_socket,ulong client_flag) { char buff[NAME_LEN+USERNAME_LENGTH+100]; - char error_string[1024]; - char *end,*host_info= NULL; + int scramble_data_len, pkt_scramble_len; + char *end, *host_info=0, *server_version_end, *pkt_end; + char *scramble_data, *scramble_plugin; my_socket sock; in_addr_t ip_addr; struct sockaddr_in sock_addr; @@ -2180,8 +2856,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, errno); goto error; } + pkt_end= (char*)net->read_pos + pkt_length; /* Check if version of protocol matches current one */ - mysql->protocol_version= net->read_pos[0]; DBUG_DUMP("packet",(uchar*) net->read_pos,10); DBUG_PRINT("info",("mysql protocol version %d, server=%d", @@ -2193,31 +2869,29 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, PROTOCOL_VERSION); goto error; } - end=strend((char*) net->read_pos+1); + server_version_end= end= strend((char*) net->read_pos+1); mysql->thread_id=uint4korr(end+1); end+=5; /* - Scramble is split into two parts because old clients does not understand + Scramble is split into two parts because old clients do not understand long scrambles; here goes the first part. */ - strmake(mysql->scramble, end, SCRAMBLE_LENGTH_323); - end+= SCRAMBLE_LENGTH_323+1; + scramble_data= end; + scramble_data_len= SCRAMBLE_LENGTH_323 + 1; + scramble_plugin= old_password_plugin_name; + end+= scramble_data_len; - if (pkt_length >= (uint) (end+1 - (char*) net->read_pos)) + if (pkt_end >= end + 1) mysql->server_capabilities=uint2korr(end); - if (pkt_length >= (uint) (end+18 - (char*) net->read_pos)) + if (pkt_end >= end + 18) { /* New protocol with 16 bytes to describe server characteristics */ mysql->server_language=end[2]; mysql->server_status=uint2korr(end+3); + mysql->server_capabilities|= uint2korr(end+5) << 16; + pkt_scramble_len= end[7]; } end+= 18; - if (pkt_length >= (uint) (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 - - (char *) net->read_pos)) - strmake(mysql->scramble+SCRAMBLE_LENGTH_323, end, - SCRAMBLE_LENGTH-SCRAMBLE_LENGTH_323); - else - mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION; if (mysql->options.secure_auth && passwd[0] && !(mysql->server_capabilities & CLIENT_SECURE_CONNECTION)) @@ -2236,7 +2910,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, &mysql->unix_socket,unix_socket ? (uint) strlen(unix_socket)+1 : (uint) 1, &mysql->server_version, - (uint) (end - (char*) net->read_pos), + (uint) (server_version_end - (char*) net->read_pos + 1), NullS) || !(mysql->user=my_strdup(user,MYF(0))) || !(mysql->passwd=my_strdup(passwd,MYF(0)))) @@ -2253,203 +2927,47 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, strmov(mysql->server_version,(char*) net->read_pos+1); mysql->port=port; - /* - Part 2: format and send client info to the server for access check - */ - - client_flag|=mysql->options.client_flag; - client_flag|=CLIENT_CAPABILITIES; - if (client_flag & CLIENT_MULTI_STATEMENTS) - client_flag|= CLIENT_MULTI_RESULTS; - -#ifdef HAVE_OPENSSL - if (mysql->options.ssl_key || mysql->options.ssl_cert || - mysql->options.ssl_ca || mysql->options.ssl_capath || - mysql->options.ssl_cipher) - mysql->options.use_ssl= 1; - if (mysql->options.use_ssl) - client_flag|=CLIENT_SSL; -#endif /* HAVE_OPENSSL */ - if (db) - client_flag|=CLIENT_CONNECT_WITH_DB; - - /* Remove options that server doesn't support */ - client_flag= ((client_flag & - ~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)) | - (client_flag & mysql->server_capabilities)); -#ifndef HAVE_COMPRESS - client_flag&= ~CLIENT_COMPRESS; -#endif - - if (client_flag & CLIENT_PROTOCOL_41) + if (pkt_end >= end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1) { - /* 4.1 server and 4.1 client has a 32 byte option flag */ - int4store(buff,client_flag); - int4store(buff+4, net->max_packet_size); - buff[8]= (char) mysql->charset->number; - bzero(buff+9, 32-9); - end= buff+32; - } - else - { - int2store(buff,client_flag); - int3store(buff+2,net->max_packet_size); - end= buff+5; - } - mysql->client_flag=client_flag; - -#ifdef HAVE_OPENSSL - if (client_flag & CLIENT_SSL) - { - /* Do the SSL layering. */ - struct st_mysql_options *options= &mysql->options; - struct st_VioSSLFd *ssl_fd; - /* - Send client_flag, max_packet_size - unencrypted otherwise - the server does not know we want to do SSL + move the first scramble part - directly in the NET buffer - + to get a full continuous scramble. We've read all the header, + and can overwrite it now. */ - if (my_net_write(net, (uchar*) buff, (uint) (end-buff)) || net_flush(net)) + memmove(end - SCRAMBLE_LENGTH_323, scramble_data, + SCRAMBLE_LENGTH_323); + scramble_data= end - SCRAMBLE_LENGTH_323; + if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) { - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "sending connection information to server", - errno); - goto error; - } - - /* Create the VioSSLConnectorFd - init SSL and load certs */ - if (!(ssl_fd= new_VioSSLConnectorFd(options->ssl_key, - options->ssl_cert, - options->ssl_ca, - options->ssl_capath, - options->ssl_cipher))) - { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); - goto error; - } - mysql->connector_fd= (void*)ssl_fd; - - /* Connect to the server */ - DBUG_PRINT("info", ("IO layer change in progress...")); - if (sslconnect(ssl_fd, mysql->net.vio, - (long) (mysql->options.connect_timeout), - error_string)) - { - set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, - unknown_sqlstate, - "SSL error: %s", - error_string[0] ? error_string : - ER(CR_SSL_CONNECTION_ERROR)); - goto error; - } - DBUG_PRINT("info", ("IO layer change done!")); - - /* Verify server cert */ - if ((client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && - ssl_verify_server_cert(mysql->net.vio, mysql->host)) - { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); - goto error; - } - - } -#endif /* HAVE_OPENSSL */ - - DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu", - mysql->server_version,mysql->server_capabilities, - mysql->server_status, client_flag)); - /* This needs to be changed as it's not useful with big packets */ - if (user && user[0]) - strmake(end,user,USERNAME_LENGTH); /* Max user name */ - else - read_user_name((char*) end); - - /* We have to handle different version of handshake here */ -#ifdef _CUSTOMCONFIG_ -#include "_cust_libmysql.h" -#endif - DBUG_PRINT("info",("user: %s",end)); - end= strend(end) + 1; - if (passwd[0]) - { - if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) - { - *end++= SCRAMBLE_LENGTH; - scramble(end, mysql->scramble, passwd); - end+= SCRAMBLE_LENGTH; + scramble_data_len= pkt_scramble_len; + scramble_plugin= scramble_data + scramble_data_len; + if (scramble_data + scramble_data_len > pkt_end) + scramble_data_len= pkt_end - scramble_data; } else { - scramble_323(end, mysql->scramble, passwd); - end+= SCRAMBLE_LENGTH_323 + 1; + scramble_data_len= pkt_end - scramble_data; + scramble_plugin= native_password_plugin_name; } } else - *end++= '\0'; /* empty password */ + mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION; + + mysql->client_flag= client_flag; - /* Add database if needed */ - if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) - { - end= strmake(end, db, NAME_LEN) + 1; - mysql->db= my_strdup(db,MYF(MY_WME)); - db= 0; - } - /* Write authentication package */ - if (my_net_write(net, (uchar*) buff, (size_t) (end-buff)) || net_flush(net)) - { - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "sending authentication information", - errno); - goto error; - } - /* - Part 3: Authorization data's been sent. Now server can reply with - OK-packet, or re-request scrambled password. + Part 2: invoke the plugin to send the authentication data to the server */ - if ((pkt_length=cli_safe_read(mysql)) == packet_error) - { - if (mysql->net.last_errno == CR_SERVER_LOST) - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "reading authorization packet", - errno); + if (run_plugin_auth(mysql, scramble_data, scramble_data_len, + scramble_plugin, db)) goto error; - } - if (pkt_length == 1 && net->read_pos[0] == 254 && - mysql->server_capabilities & CLIENT_SECURE_CONNECTION) - { - /* - By sending this very specific reply server asks us to send scrambled - password in old format. - */ - scramble_323(buff, mysql->scramble, passwd); - if (my_net_write(net, (uchar*) buff, SCRAMBLE_LENGTH_323 + 1) || - net_flush(net)) - { - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "sending password information", - errno); - goto error; - } - /* Read what server thinks about out new auth message report */ - if (cli_safe_read(mysql) == packet_error) - { - if (mysql->net.last_errno == CR_SERVER_LOST) - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "reading final connect information", - errno); - goto error; - } - } + /* + Part 3: authenticated, finish the initialization of the connection + */ - if (client_flag & CLIENT_COMPRESS) /* We will use compression */ + if (mysql->client_flag & CLIENT_COMPRESS) /* We will use compression */ net->compress=1; #ifdef CHECK_LICENSE @@ -2457,7 +2975,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, goto error; #endif - if (db && mysql_select_db(mysql, db)) + if (db && !mysql->db && mysql_select_db(mysql, db)) { if (mysql->net.last_errno == CR_SERVER_LOST) set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, @@ -2510,7 +3028,7 @@ error: /* Free alloced memory */ end_server(mysql); mysql_close_free(mysql); - if (!(((ulong) client_flag) & CLIENT_REMEMBER_OPTIONS)) + if (!(client_flag & CLIENT_REMEMBER_OPTIONS)) mysql_close_free_options(mysql); } DBUG_RETURN(0); @@ -2655,6 +3173,12 @@ static void mysql_close_free_options(MYSQL *mysql) if (mysql->options.shared_memory_base_name != def_shared_memory_base_name) my_free(mysql->options.shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); #endif /* HAVE_SMEM */ + if (mysql->options.extension) + { + my_free(mysql->options.extension->plugin_dir,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.extension->default_auth,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.extension,MYF(0)); + } bzero((char*) &mysql->options,sizeof(mysql->options)); DBUG_VOID_RETURN; } @@ -3185,6 +3709,12 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) else mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT; break; + case MYSQL_PLUGIN_DIR: + extension_set_string(&mysql->options, plugin_dir, arg); + break; + case MYSQL_DEFAULT_AUTH: + extension_set_string(&mysql->options, default_auth, arg); + break; default: DBUG_RETURN(1); } @@ -3293,3 +3823,99 @@ int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name) } +/** + client authentication plugin that does native MySQL authentication + using a 20-byte (4.1+) scramble +*/ + +static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) +{ + int pkt_len; + uchar *pkt; + + if (((MCPVIO_EXT *)vio)->mysql_change_user) + { + /* + in mysql_change_user() the client sends the first packet. + we use the old scramble. + */ + pkt= (uchar*)mysql->scramble; + pkt_len= SCRAMBLE_LENGTH + 1; + } + else + { + /* read the scramble */ + if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) + return CR_ERROR; + + if (pkt_len != SCRAMBLE_LENGTH + 1) + return CR_SERVER_HANDSHAKE_ERR; + + /* save it in MYSQL */ + memcpy(mysql->scramble, pkt, SCRAMBLE_LENGTH); + mysql->scramble[SCRAMBLE_LENGTH] = 0; + } + + if (mysql->passwd[0]) + { + char scrambled[SCRAMBLE_LENGTH + 1]; + scramble(scrambled, (char*)pkt, mysql->passwd); + if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH)) + return CR_ERROR; + } + else + if (vio->write_packet(vio, 0, 0)) /* no password */ + return CR_ERROR; + + return CR_OK; +} + + +/** + client authentication plugin that does old MySQL authentication + using an 8-byte (4.0-) scramble +*/ + +static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) +{ + uchar *pkt; + int pkt_len; + + if (((MCPVIO_EXT *)vio)->mysql_change_user) + { + /* + in mysql_change_user() the client sends the first packet. + we use the old scramble. + */ + pkt= (uchar*)mysql->scramble; + pkt_len= SCRAMBLE_LENGTH_323 + 1; + } + else + { + /* read the scramble */ + if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) + return CR_ERROR; + + if (pkt_len != SCRAMBLE_LENGTH_323 + 1 && + pkt_len != SCRAMBLE_LENGTH + 1) + return CR_SERVER_HANDSHAKE_ERR; + + /* save it in MYSQL */ + memcpy(mysql->scramble, pkt, pkt_len); + mysql->scramble[pkt_len] = 0; + } + + if (mysql->passwd[0]) + { + char scrambled[SCRAMBLE_LENGTH_323 + 1]; + scramble_323(scrambled, (char*)pkt, mysql->passwd); + if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH_323 + 1)) + return CR_ERROR; + } + else + if (vio->write_packet(vio, 0, 0)) /* no password */ + return CR_ERROR; + + return CR_OK; +} + -- cgit v1.2.1 From 3b03f5d97e0f80da74cb0789f513ce0319fc9c8a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 2 Apr 2010 11:20:09 +0200 Subject: fixes for windows builds --- sql-common/client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql-common/client.c') diff --git a/sql-common/client.c b/sql-common/client.c index 447518c9e5d..18f01661c0a 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2345,7 +2345,7 @@ void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info) case VIO_TYPE_SSL: { struct sockaddr addr; - socklen_t addrlen= sizeof(addr); + SOCKET_SIZE_TYPE addrlen= sizeof(addr); if (getsockname(vio->sd, &addr, &addrlen)) return; info->protocol= addr.sa_family == AF_UNIX ? @@ -2360,7 +2360,7 @@ void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info) return; case VIO_TYPE_SHARED_MEMORY: info->protocol= MYSQL_VIO_MEMORY; - info->handle= vio->handle_client_file_map; /* or what ? */ + info->handle= vio->handle_file_map; /* or what ? */ return; #endif default: DBUG_ASSERT(0); -- cgit v1.2.1 From 13141c9842c055406730daead25337e46a57f4d8 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 6 Aug 2010 11:05:44 +0300 Subject: Fixed compiler warnings and test failures --- sql-common/client.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sql-common/client.c') diff --git a/sql-common/client.c b/sql-common/client.c index 2cad8df1f9b..3788ca9829b 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2559,6 +2559,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, #endif init_sigpipe_variables DBUG_ENTER("mysql_real_connect"); + LINT_INIT(pkt_scramble_len); DBUG_PRINT("enter",("host: %s db: %s user: %s", host ? host : "(Null)", -- cgit v1.2.1