Browse Source

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
pull/843/head
Sergei Golubchik 16 years ago
parent
commit
291fd96983
  1. 3
      .bzrignore
  2. 11
      Makefile.am
  3. 2
      client/CMakeLists.txt
  4. 4
      client/Makefile.am
  5. 4
      client/client_priv.h
  6. 65
      client/mysql.cc
  7. 3
      configure.in
  8. 4
      include/Makefile.am
  9. 3
      include/errmsg.h
  10. 14
      include/my_global.h
  11. 1
      include/my_no_pthread.h
  12. 6
      include/my_sys.h
  13. 54
      include/mysql.h
  14. 37
      include/mysql.h.pp
  15. 164
      include/mysql/client_plugin.h
  16. 41
      include/mysql/client_plugin.h.pp
  17. 5
      include/mysql/plugin.h
  18. 83
      include/mysql/plugin_auth.h
  19. 30
      include/mysql/plugin_auth.h.pp
  20. 105
      include/mysql/plugin_auth_common.h
  21. 15
      include/mysql_com.h
  22. 65
      include/sql_common.h
  23. 3
      libmysql/CMakeLists.txt
  24. 14
      libmysql/Makefile.shared
  25. 5
      libmysql/client_settings.h
  26. 3
      libmysql/errmsg.c
  27. 103
      libmysql/libmysql.c
  28. 10
      libmysqld/Makefile.am
  29. 2
      libmysqld/embedded_priv.h
  30. 79
      libmysqld/lib_sql.cc
  31. 14
      libmysqld/libmysqld.c
  32. 33
      mysql-test/r/change_user.result
  33. 13
      mysql-test/r/grant.result
  34. 2
      mysql-test/r/grant2.result
  35. 6
      mysql-test/r/ps.result
  36. 2
      mysql-test/r/sp_notembedded.result
  37. 2
      mysql-test/r/system_mysql_db.result
  38. 5
      mysql-test/suite/funcs_1/r/is_columns_mysql.result
  39. 88
      mysql-test/suite/funcs_1/r/is_user_privileges.result
  40. 13
      mysql-test/suite/pbxt/r/grant.result
  41. 1
      mysql-test/suite/rpl/r/rpl_ignore_table.result
  42. 1
      mysql-test/suite/rpl/r/rpl_stm_000001.result
  43. 46
      mysql-test/t/change_user.test
  44. 10
      mysys/Makefile.am
  45. 15
      plugin/auth/Makefile.am
  46. 102
      plugin/auth/auth_socket.c
  47. 302
      plugin/auth/dialog.c
  48. 15
      plugin/auth/plug.in
  49. 2
      scripts/mysql_system_tables.sql
  50. 6
      scripts/mysql_system_tables_data.sql
  51. 3
      scripts/mysql_system_tables_fix.sql
  52. 5
      server-tools/instance-manager/Makefile.am
  53. 2
      server-tools/instance-manager/user_map.cc
  54. 2
      sql-common/Makefile.am
  55. 1108
      sql-common/client.c
  56. 436
      sql-common/client_plugin.c
  57. 2
      sql/CMakeLists.txt
  58. 12
      sql/Makefile.am
  59. 4
      sql/client_settings.h
  60. 2
      sql/ha_ndbcluster.cc
  61. 2
      sql/ha_ndbcluster_binlog.cc
  62. 1
      sql/lex.h
  63. 6
      sql/mysql_priv.h
  64. 3
      sql/mysqld.cc
  65. 12
      sql/password.c
  66. 18
      sql/protocol.cc
  67. 1
      sql/protocol.h
  68. 1993
      sql/sql_acl.cc
  69. 54
      sql/sql_acl.h
  70. 4
      sql/sql_builtin.cc.in
  71. 20
      sql/sql_class.cc
  72. 3
      sql/sql_class.h
  73. 458
      sql/sql_connect.cc
  74. 4
      sql/sql_insert.cc
  75. 2
      sql/sql_lex.h
  76. 116
      sql/sql_parse.cc
  77. 23
      sql/sql_plugin.cc
  78. 22
      sql/sql_yacc.yy
  79. 2
      sql/structs.h
  80. 7
      sql/table.cc
  81. 1
      tests/mysql_client_test.c

3
.bzrignore

@ -1931,3 +1931,6 @@ client/rpl_filter.cc
client/rpl_filter.h
client/sql_list.cc
client/sql_list.h
libmysqld/client_plugin.c
sql/client_plugin.c
*.dgcov

11
Makefile.am

@ -271,12 +271,13 @@ test-full-qa:
# after which TEST_PREPROCESSOR_HEADER will be used.
#
API_PREPROCESSOR_HEADER = $(top_srcdir)/include/mysql/plugin.h \
$(top_srcdir)/include/mysql.h
API_PREPROCESSOR_HEADER = $(top_srcdir)/include/mysql.h \
$(top_srcdir)/include/mysql/client_plugin.h \
$(top_srcdir)/include/mysql/plugin_auth.h
TEST_PREPROCESSOR_HEADER = $(top_srcdir)/include/mysql/plugin.h \
$(top_srcdir)/sql/mysql_priv.h \
$(top_srcdir)/include/mysql.h
TEST_PREPROCESSOR_HEADER = $(API_PREPROCESSOR_HEADER) \
$(top_srcdir)/sql/mysql_priv.h
#
# Rules for checking that the abi/api has not changed.

2
client/CMakeLists.txt

@ -83,3 +83,5 @@ IF(EMBED_MANIFESTS)
MYSQL_EMBED_MANIFEST("echo" "asInvoker")
ENDIF(EMBED_MANIFESTS)
ADD_DEFINITIONS(-DHAVE_DLOPEN)

4
client/Makefile.am

@ -100,8 +100,8 @@ mysql_upgrade_SOURCES= mysql_upgrade.c \
# Fix for mit-threads
DEFS = -DMYSQL_CLIENT_NO_THREADS \
-DDEFAULT_MYSQL_HOME="\"$(prefix)\"" \
-DMYSQL_DATADIR="\"$(localstatedir)\""
-DDEFAULT_MYSQL_HOME='"$(prefix)"' \
-DMYSQL_DATADIR='"$(localstatedir)"'
sql_src=log_event.h mysql_priv.h rpl_constants.h \
rpl_utility.h rpl_tblmap.h rpl_tblmap.cc \

4
client/client_priv.h

@ -93,5 +93,7 @@ enum options_client
OPT_FIRST_SLAVE,
OPT_ALL,
OPT_REWRITE_DB,
OPT_MAX_CLIENT_OPTION
OPT_PLUGIN_DIR,
OPT_DEFAULT_PLUGIN,
OPT_MAX_CLIENT_OPTION /* should be always the last */
};

65
client/mysql.cc

@ -167,6 +167,7 @@ static int wait_time = 5;
static STATUS status;
static ulong select_limit,max_join_size,opt_connect_timeout=0;
static char mysql_charsets_dir[FN_REFLEN+1];
static char *opt_plugin_dir= 0, *opt_default_auth;
static const char *xmlmeta[] = {
"&", "&",
"<", "&lt;",
@ -1542,6 +1543,13 @@ static struct my_option my_long_options[] =
{"show-warnings", OPT_SHOW_WARNINGS, "Show warnings after every statement.",
(uchar**) &show_warnings, (uchar**) &show_warnings, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
{"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
(uchar**) &opt_plugin_dir, (uchar**) &opt_plugin_dir, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"default_auth", OPT_PLUGIN_DIR,
"Default authentication client-side plugin to use.",
(uchar**) &opt_default_auth, (uchar**) &opt_default_auth, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@ -4238,6 +4246,56 @@ char *get_arg(char *line, my_bool get_next_arg)
}
/**
An example of mysql_authentication_dialog_ask callback.
The C function with the name "mysql_authentication_dialog_ask", if exists,
will be used by the "dialog" client authentication plugin when user
input is needed. This function should be of mysql_authentication_dialog_ask_t
type. If the function does not exists, a built-in implementation will be
used.
@param mysql mysql
@param type type of the input
1 - normal string input
2 - password string
@param prompt prompt
@param buf a buffer to store the use input
@param buf_len the length of the buffer
@retval a pointer to the user input string.
It may be equal to 'buf' or to 'mysql->password'.
In all other cases it is assumed to be an allocated
string, and the "dialog" plugin will free() it.
*/
extern "C" char *mysql_authentication_dialog_ask(MYSQL *mysql, int type,
const char *prompt,
char *buf, int buf_len)
{
char *s=buf;
fputs("[mariadb] ", stdout);
fputs(prompt, stdout);
fputs(" ", stdout);
if (type == 2) /* password */
{
s= get_tty_password("");
strnmov(buf, s, buf_len);
buf[buf_len-1]= 0;
my_free(s, MYF(0));
}
else
{
fgets(buf, buf_len-1, stdin);
if (buf[0] && (s= strend(buf))[-1] == '\n')
s[-1]= 0;
}
return buf;
}
static int
sql_real_connect(char *host,char *database,char *user,char *password,
uint silent)
@ -4283,6 +4341,13 @@ sql_real_connect(char *host,char *database,char *user,char *password,
}
if (default_charset_used)
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
if (opt_plugin_dir && *opt_plugin_dir)
mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
if (!mysql_real_connect(&mysql, host, user, password,
database, opt_mysql_port, opt_mysql_unix_port,
connect_flag | CLIENT_MULTI_STATEMENTS))

3
configure.in

@ -1605,9 +1605,8 @@ case "$with_mysqld_ldflags " in
;;
*)
# Check for dlopen, needed for user definable functions
# Check for dlopen, needed for user definable functions and plugins
# This must be checked after threads on AIX
# We only need this for mysqld, not for the clients.
my_save_LIBS="$LIBS"
LIBS=""

4
include/Makefile.am

@ -24,6 +24,8 @@ pkginclude_HEADERS = $(HEADERS_ABI) my_dbug.h m_string.h my_sys.h \
my_xml.h mysql_embed.h mysql/services.h \
mysql/service_my_snprintf.h mysql/service_thd_alloc.h \
my_pthread.h my_no_pthread.h \
mysql/plugin_auth.h mysql/client_plugin.h \
mysql/plugin_auth_common.h \
decimal.h errmsg.h my_global.h my_net.h \
my_getopt.h sslopt-longopts.h my_dir.h \
sslopt-vars.h sslopt-case.h sql_common.h keycache.h \
@ -42,7 +44,7 @@ noinst_HEADERS = config-win.h config-netware.h lf.h my_bit.h \
atomic/rwlock.h atomic/x86-gcc.h atomic/generic-msvc.h \
atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h \
wqueue.h waiting_threads.h
EXTRA_DIST = mysql.h.pp mysql/plugin.h.pp
EXTRA_DIST = mysql.h.pp mysql/plugin_auth.h.pp mysql/client_plugin.h.pp
# Remove built files and the symlinked directories
CLEANFILES = $(BUILT_SOURCES) readline openssl

3
include/errmsg.h

@ -97,6 +97,7 @@ extern const char *client_errors[]; /* Error messages */
#define CR_SERVER_LOST_EXTENDED 2055
#define CR_STMT_CLOSED 2056
#define CR_NEW_STMT_METADATA 2057
#define CR_ERROR_LAST /*Copy last error nr:*/ 2057
#define CR_AUTH_PLUGIN_CANNOT_LOAD 2058
#define CR_ERROR_LAST /*Copy last error nr:*/ 2058
/* Add error numbers before CR_ERROR_LAST and change it accordingly. */

14
include/my_global.h

@ -578,6 +578,14 @@ int __void__;
#define IF_VALGRIND(A,B) (B)
#endif
#ifdef _WIN32
#define SO_EXT ".dll"
#elif defined(__APPLE__)
#define SO_EXT ".dylib"
#else
#define SO_EXT ".so"
#endif
/*
Suppress uninitialized variable warning without generating code.
@ -1522,10 +1530,12 @@ do { doubleget_union _tmp; \
#endif
#ifndef HAVE_DLERROR
#define dlerror() ""
#define dlerror() "No support for dynamic loading (static build?)"
#define dlopen(A,B) 0
#define dlsym(A,B) 0
#define dlclose(A) 0
#endif
#ifndef __NETWARE__
/*
* Include standard definitions of operator new and delete.

1
include/my_no_pthread.h

@ -46,6 +46,7 @@
#define rw_wrlock(A)
#define rw_unlock(A)
#define rwlock_destroy(A)
#define safe_mutex_assert_owner(mp)
typedef int my_pthread_once_t;
#define MY_PTHREAD_ONCE_INIT 0

6
include/my_sys.h

@ -210,7 +210,7 @@ extern void my_large_free(uchar * ptr, myf my_flags);
#define my_alloca(SZ) alloca((size_t) (SZ))
#define my_afree(PTR) {}
#else
#define my_alloca(SZ) my_malloc(SZ,MYF(0))
#define my_alloca(SZ) my_malloc(SZ,MYF(MY_FAE))
#define my_afree(PTR) my_free(PTR,MYF(MY_WME))
#endif /* HAVE_ALLOCA */
@ -870,6 +870,10 @@ extern void set_prealloc_root(MEM_ROOT *root, char *ptr);
extern void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
size_t prealloc_size);
extern char *strdup_root(MEM_ROOT *root,const char *str);
static inline char *safe_strdup_root(MEM_ROOT *root, const char *str)
{
return str ? strdup_root(root, str) : 0;
}
extern char *strmake_root(MEM_ROOT *root,const char *str,size_t len);
extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len);
extern int get_defaults_options(int argc, char **argv,

54
include/mysql.h

@ -167,9 +167,15 @@ enum mysql_option
MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
MYSQL_OPT_SSL_VERIFY_SERVER_CERT
MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH
};
/**
@todo remove the "extension", move st_mysql_options completely
out of mysql.h
*/
struct st_mysql_options_extention;
struct st_mysql_options {
unsigned int connect_timeout, read_timeout, write_timeout;
unsigned int port, protocol;
@ -217,7 +223,7 @@ struct st_mysql_options {
void (*local_infile_end)(void *);
int (*local_infile_error)(void *, char *, unsigned int);
void *local_infile_userdata;
void *extension;
struct st_mysql_options_extention *extension;
};
enum mysql_status
@ -752,38 +758,6 @@ enum enum_stmt_attr_type
};
typedef struct st_mysql_methods
{
my_bool (*read_query_result)(MYSQL *mysql);
my_bool (*advanced_command)(MYSQL *mysql,
enum enum_server_command command,
const unsigned char *header,
unsigned long header_length,
const unsigned char *arg,
unsigned long arg_length,
my_bool skip_check,
MYSQL_STMT *stmt);
MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
unsigned int fields);
MYSQL_RES * (*use_result)(MYSQL *mysql);
void (*fetch_lengths)(unsigned long *to,
MYSQL_ROW column, unsigned int field_count);
void (*flush_use_result)(MYSQL *mysql);
#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
MYSQL_FIELD * (*list_fields)(MYSQL *mysql);
my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt);
int (*stmt_execute)(MYSQL_STMT *stmt);
int (*read_binary_rows)(MYSQL_STMT *stmt);
int (*unbuffered_fetch)(MYSQL *mysql, char **row);
void (*free_embedded_thd)(MYSQL *mysql);
const char *(*read_statistics)(MYSQL *mysql);
my_bool (*next_result)(MYSQL *mysql);
int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd);
int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
#endif
} MYSQL_METHODS;
MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql);
int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query,
unsigned long length);
@ -846,18 +820,6 @@ int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
#endif
#define HAVE_MYSQL_REAL_CONNECT
/*
The following functions are mainly exported because of mysqlbinlog;
They are not for general usage
*/
#define simple_command(mysql, command, arg, length, skip_check) \
(*(mysql)->methods->advanced_command)(mysql, command, 0, \
0, arg, length, skip_check, NULL)
#define stmt_command(mysql, command, arg, length, stmt) \
(*(mysql)->methods->advanced_command)(mysql, command, 0, \
0, arg, length, 1, stmt)
#ifdef __NETWARE__
#pragma pack(pop) /* restore alignment */
#endif

37
include/mysql.h.pp

@ -128,13 +128,13 @@ void create_random_string(char *to, unsigned int length,
void hash_password(unsigned long *to, const char *password, unsigned int password_len);
void make_scrambled_password_323(char *to, const char *password);
void scramble_323(char *to, const char *message, const char *password);
my_bool check_scramble_323(const char *, const char *message,
my_bool check_scramble_323(const unsigned char *reply, const char *message,
unsigned long *salt);
void get_salt_from_password_323(unsigned long *res, const char *password);
void make_password_from_salt_323(char *to, const unsigned long *salt);
void make_scrambled_password(char *to, const char *password);
void scramble(char *to, const char *message, const char *password);
my_bool check_scramble(const char *reply, const char *message,
my_bool check_scramble(const unsigned char *reply, const char *message,
const unsigned char *hash_stage2);
void get_salt_from_password(unsigned char *res, const char *password);
void make_password_from_salt(char *to, const unsigned char *hash_stage2);
@ -258,8 +258,9 @@ enum mysql_option
MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
MYSQL_OPT_SSL_VERIFY_SERVER_CERT
MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH
};
struct st_mysql_options_extention;
struct st_mysql_options {
unsigned int connect_timeout, read_timeout, write_timeout;
unsigned int port, protocol;
@ -289,7 +290,7 @@ struct st_mysql_options {
void (*local_infile_end)(void *);
int (*local_infile_error)(void *, char *, unsigned int);
void *local_infile_userdata;
void *extension;
struct st_mysql_options_extention *extension;
};
enum mysql_status
{
@ -601,34 +602,6 @@ enum enum_stmt_attr_type
STMT_ATTR_CURSOR_TYPE,
STMT_ATTR_PREFETCH_ROWS
};
typedef struct st_mysql_methods
{
my_bool (*read_query_result)(MYSQL *mysql);
my_bool (*advanced_command)(MYSQL *mysql,
enum enum_server_command command,
const unsigned char *header,
unsigned long header_length,
const unsigned char *arg,
unsigned long arg_length,
my_bool skip_check,
MYSQL_STMT *stmt);
MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
unsigned int fields);
MYSQL_RES * (*use_result)(MYSQL *mysql);
void (*fetch_lengths)(unsigned long *to,
MYSQL_ROW column, unsigned int field_count);
void (*flush_use_result)(MYSQL *mysql);
MYSQL_FIELD * (*list_fields)(MYSQL *mysql);
my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt);
int (*stmt_execute)(MYSQL_STMT *stmt);
int (*read_binary_rows)(MYSQL_STMT *stmt);
int (*unbuffered_fetch)(MYSQL *mysql, char **row);
void (*free_embedded_thd)(MYSQL *mysql);
const char *(*read_statistics)(MYSQL *mysql);
my_bool (*next_result)(MYSQL *mysql);
int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd);
int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
} MYSQL_METHODS;
MYSQL_STMT * mysql_stmt_init(MYSQL *mysql);
int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query,
unsigned long length);

164
include/mysql/client_plugin.h

@ -0,0 +1,164 @@
#ifndef MYSQL_CLIENT_PLUGIN_INCLUDED
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**
@file
MySQL Client Plugin API
This file defines the API for plugins that work on the client side
*/
#define MYSQL_CLIENT_PLUGIN_INCLUDED
#include <stdarg.h>
#include <stdlib.h>
/* known plugin types */
#define MYSQL_CLIENT_reserved1 0
#define MYSQL_CLIENT_reserved2 1
#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2
#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100
#define MYSQL_CLIENT_MAX_PLUGINS 3
#define mysql_declare_client_plugin(X) \
struct st_mysql_client_plugin_ ## X \
_mysql_client_plugin_declaration_ = { \
MYSQL_CLIENT_ ## X ## _PLUGIN, \
MYSQL_CLIENT_ ## X ## _PLUGIN_INTERFACE_VERSION,
#define mysql_end_client_plugin }
/* generic plugin header structure */
#define MYSQL_CLIENT_PLUGIN_HEADER \
int type; \
unsigned int interface_version; \
const char *name; \
const char *author; \
const char *desc; \
unsigned int version[3]; \
int (*init)(char *, size_t, int, va_list); \
int (*deinit)();
struct st_mysql_client_plugin
{
MYSQL_CLIENT_PLUGIN_HEADER
};
struct st_mysql;
/******** authentication plugin specific declarations *********/
#include <mysql/plugin_auth_common.h>
struct st_mysql_client_plugin_AUTHENTICATION
{
MYSQL_CLIENT_PLUGIN_HEADER
int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql);
};
/**
type of the mysql_authentication_dialog_ask function
@param mysql mysql
@param type type of the input
1 - ordinary string input
2 - password string
@param prompt prompt
@param buf a buffer to store the use input
@param buf_len the length of the buffer
@retval a pointer to the user input string.
It may be equal to 'buf' or to 'mysql->password'.
In all other cases it is assumed to be an allocated
string, and the "dialog" plugin will free() it.
*/
typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql,
int type, const char *prompt, char *buf, int buf_len);
/******** using plugins ************/
/**
loads a plugin and initializes it
@param mysql MYSQL structure. only MYSQL_PLUGIN_DIR option value is used,
and last_errno/last_error, for error reporting
@param name a name of the plugin to load
@param type type of plugin that should be loaded, -1 to disable type check
@param argc number of arguments to pass to the plugin initialization
function
@param ... arguments for the plugin initialization function
@retval
a pointer to the loaded plugin, or NULL in case of a failure
*/
struct st_mysql_client_plugin *
mysql_load_plugin(struct st_mysql *mysql, const char *name, int type,
int argc, ...);
/**
loads a plugin and initializes it, taking va_list as an argument
This is the same as mysql_load_plugin, but take va_list instead of
a list of arguments.
@param mysql MYSQL structure. only MYSQL_PLUGIN_DIR option value is used,
and last_errno/last_error, for error reporting
@param name a name of the plugin to load
@param type type of plugin that should be loaded, -1 to disable type check
@param argc number of arguments to pass to the plugin initialization
function
@param args arguments for the plugin initialization function
@retval
a pointer to the loaded plugin, or NULL in case of a failure
*/
struct st_mysql_client_plugin *
mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type,
int argc, va_list args);
/**
finds an already loaded plugin by name, or loads it, if necessary
@param mysql MYSQL structure. only MYSQL_PLUGIN_DIR option value is used,
and last_errno/last_error, for error reporting
@param name a name of the plugin to load
@param type type of plugin that should be loaded
@retval
a pointer to the plugin, or NULL in case of a failure
*/
struct st_mysql_client_plugin *
mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type);
/**
adds a plugin structure to the list of loaded plugins
This is useful if an application has the necessary functionality
(for example, a special load data handler) statically linked into
the application binary. It can use this function to register the plugin
directly, avoiding the need to factor it out into a shared object.
@param mysql MYSQL structure. It is only used for error reporting
@param plugin an st_mysql_client_plugin structure to register
@retval
a pointer to the plugin, or NULL in case of a failure
*/
struct st_mysql_client_plugin *
mysql_client_register_plugin(struct st_mysql *mysql,
struct st_mysql_client_plugin *plugin);
#endif

41
include/mysql/client_plugin.h.pp

@ -0,0 +1,41 @@
#include <stdarg.h>
#include <stdlib.h>
struct st_mysql_client_plugin
{
int type; unsigned int interface_version; const char *name; const char *author; const char *desc; unsigned int version[3]; int (*init)(char *, size_t, int, va_list); int (*deinit)();
};
struct st_mysql;
#include <mysql/plugin_auth_common.h>
typedef struct st_plugin_vio_info
{
enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET,
MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol;
int socket;
} MYSQL_PLUGIN_VIO_INFO;
typedef struct st_plugin_vio
{
int (*read_packet)(struct st_plugin_vio *vio,
unsigned char **buf);
int (*write_packet)(struct st_plugin_vio *vio,
const unsigned char *packet,
int packet_len);
void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
} MYSQL_PLUGIN_VIO;
struct st_mysql_client_plugin_AUTHENTICATION
{
int type; unsigned int interface_version; const char *name; const char *author; const char *desc; unsigned int version[3]; int (*init)(char *, size_t, int, va_list); int (*deinit)();
int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql);
};
typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql,
int type, const char *prompt, char *buf, int buf_len);
struct st_mysql_client_plugin *
mysql_load_plugin(struct st_mysql *mysql, const char *name, int type,
int argc, ...);
struct st_mysql_client_plugin *
mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type,
int argc, va_list args);
struct st_mysql_client_plugin *
mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type);
struct st_mysql_client_plugin *
mysql_client_register_plugin(struct st_mysql *mysql,
struct st_mysql_client_plugin *plugin);

5
include/mysql/plugin.h

@ -67,7 +67,10 @@ typedef struct st_mysql_xid MYSQL_XID;
#define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */
#define MYSQL_DAEMON_PLUGIN 3 /* The daemon/raw plugin type */
#define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 /* The I_S plugin type */
#define MYSQL_MAX_PLUGIN_TYPE_NUM 5 /* The number of plugin types */
#define MYSQL_AUDIT_PLUGIN 5 /* The Audit plugin type */
#define MYSQL_REPLICATION_PLUGIN 6 /* The replication plugin type */
#define MYSQL_AUTHENTICATION_PLUGIN 7 /* The authentication plugin type */
#define MYSQL_MAX_PLUGIN_TYPE_NUM 8 /* The number of plugin types */
/* We use the following strings to define licenses for plugins */
#define PLUGIN_LICENSE_PROPRIETARY 0

83
include/mysql/plugin_auth.h

@ -0,0 +1,83 @@
#ifndef MYSQL_PLUGIN_AUTH_INCLUDED
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**
@file
Authentication Plugin API.
This file defines the API for server authentication plugins.
*/
#define MYSQL_PLUGIN_AUTH_INCLUDED
#include <mysql/plugin.h>
#define MYSQL_AUTHENTICATION_INTERFACE_VERSION 0x0100
#include <mysql/plugin_auth_common.h>
/**
Provides server plugin access to authentication information
*/
typedef struct st_mysql_server_auth_info
{
/**
User name as sent by the client and shown in USER().
NULL if the client packet with the user name was not received yet.
*/
const char *user_name;
/**
A corresponding column value from the mysql.user table for the
matching account name
*/
const char *auth_string;
/**
Matching account name as found in the mysql.user table.
A plugin can override it with another name that will be
used by MySQL for authorization, and shown in CURRENT_USER()
*/
char authenticated_as[MYSQL_USERNAME_LENGTH+1];
/**
This only affects the "Authentication failed. Password used: %s"
error message. If set, %s will be YES, otherwise - NO.
Set it as appropriate or ignore at will.
*/
int password_used;
} MYSQL_SERVER_AUTH_INFO;
/**
Server authentication plugin descriptor
*/
struct st_mysql_auth
{
int interface_version; /**< version plugin uses */
/**
A plugin that a client must use for authentication with this server
plugin. Can be NULL to mean "any plugin".
*/
const char *client_auth_plugin;
/**
Function provided by the plugin which should perform authentication (using
the vio functions if necessary) and return 0 if successful. The plugin can
also fill the info.authenticated_as field if a different username should be
used for authorization.
*/
int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info);
};
#endif

30
include/mysql/plugin.h.pp → include/mysql/plugin_auth.h.pp

@ -1,3 +1,4 @@
#include <mysql/plugin.h>
#include <mysql/services.h>
#include <mysql/service_my_snprintf.h>
#include <stdarg.h>
@ -161,3 +162,32 @@ void thd_get_xid(const void* thd, MYSQL_XID *xid);
void mysql_query_cache_invalidate4(void* thd,
const char *key, unsigned int key_length,
int using_trx);
#include <mysql/plugin_auth_common.h>
typedef struct st_plugin_vio_info
{
enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET,
MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol;
int socket;
} MYSQL_PLUGIN_VIO_INFO;
typedef struct st_plugin_vio
{
int (*read_packet)(struct st_plugin_vio *vio,
unsigned char **buf);
int (*write_packet)(struct st_plugin_vio *vio,
const unsigned char *packet,
int packet_len);
void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
} MYSQL_PLUGIN_VIO;
typedef struct st_mysql_server_auth_info
{
const char *user_name;
const char *auth_string;
char authenticated_as[48 +1];
int password_used;
} MYSQL_SERVER_AUTH_INFO;
struct st_mysql_auth
{
int interface_version;
const char *client_auth_plugin;
int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info);
};

105
include/mysql/plugin_auth_common.h

@ -0,0 +1,105 @@
#ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**
@file
This file defines constants and data structures that are the same for
both client- and server-side authentication plugins.
*/
#define MYSQL_PLUGIN_AUTH_COMMON_INCLUDED
/** the max allowed length for a user name */
#define MYSQL_USERNAME_LENGTH 48
/**
return values of the plugin authenticate_user() method.
*/
/**
Authentication failed. Additionally, all other CR_xxx values
(libmysql error code) can be used too.
The client plugin may set the error code and the error message directly
in the MYSQL structure and return CR_ERROR. If a CR_xxx specific error
code was returned, an error message in the MYSQL structure will be
overwritten. If CR_ERROR is returned without setting the error in MYSQL,
CR_UNKNOWN_ERROR will be user.
*/
#define CR_ERROR 0
/**
Authentication (client part) was successful. It does not mean that the
authentication as a whole was successful, usually it only means
that the client was able to send the user name and the password to the
server. If CR_OK is returned, the libmysql reads the next packet expecting
it to be one of OK, ERROR, or CHANGE_PLUGIN packets.
*/
#define CR_OK -1
/**
Authentication was successful.
It means that the client has done its part successfully and also that
a plugin has read the last packet (one of OK, ERROR, CHANGE_PLUGIN).
In this case, libmysql will not read a packet from the server,
but it will use the data at mysql->net.read_pos.
A plugin may return this value if the number of roundtrips in the
authentication protocol is not known in advance, and the client plugin
needs to read one packet more to determine if the authentication is finished
or not.
*/
#define CR_OK_HANDSHAKE_COMPLETE -2
typedef struct st_plugin_vio_info
{
enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET,
MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol;
int socket; /**< it's set, if the protocol is SOCKET or TCP */
#ifdef _WIN32
HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */
#endif
} MYSQL_PLUGIN_VIO_INFO;
/**
Provides plugin access to communication channel
*/
typedef struct st_plugin_vio
{
/**
Plugin provides a pointer reference and this function sets it to the
contents of any incoming packet. Returns the packet length, or -1 if
the plugin should terminate.
*/
int (*read_packet)(struct st_plugin_vio *vio,
unsigned char **buf);
/**
Plugin provides a buffer with data and the length and this
function sends it as a packet. Returns 0 on success, 1 on failure.
*/
int (*write_packet)(struct st_plugin_vio *vio,
const unsigned char *packet,
int packet_len);
/**
Fills in a st_plugin_vio_info structure, providing the information
about the connection.
*/
void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
} MYSQL_PLUGIN_VIO;
#endif

15
include/mysql_com.h

@ -152,9 +152,17 @@ enum enum_server_command
#define CLIENT_MULTI_STATEMENTS (1UL << 16) /* Enable/disable multi-stmt support */
#define CLIENT_MULTI_RESULTS (1UL << 17) /* Enable/disable multi-results */
#define CLIENT_PLUGIN_AUTH (1UL << 19) /* Client supports plugin authentication */
#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
#define CLIENT_REMEMBER_OPTIONS (1UL << 31)
#ifdef HAVE_COMPRESS
#define CAN_CLIENT_COMPRESS CLIENT_COMPRESS
#else
#define CAN_CLIENT_COMPRESS 0
#endif
/* Gather all possible capabilites (flags) supported by the server */
#define CLIENT_ALL_FLAGS (CLIENT_LONG_PASSWORD | \
CLIENT_FOUND_ROWS | \
@ -175,7 +183,8 @@ enum enum_server_command
CLIENT_MULTI_STATEMENTS | \
CLIENT_MULTI_RESULTS | \
CLIENT_SSL_VERIFY_SERVER_CERT | \
CLIENT_REMEMBER_OPTIONS)
CLIENT_REMEMBER_OPTIONS | \
CLIENT_PLUGIN_AUTH)
/*
Switch off the flags that are optional and depending on build flags
@ -488,14 +497,14 @@ void create_random_string(char *to, unsigned int length,
void hash_password(unsigned long *to, const char *password, unsigned int password_len);
void make_scrambled_password_323(char *to, const char *password);
void scramble_323(char *to, const char *message, const char *password);
my_bool check_scramble_323(const char *, const char *message,
my_bool check_scramble_323(const unsigned char *reply, const char *message,
unsigned long *salt);
void get_salt_from_password_323(unsigned long *res, const char *password);
void make_password_from_salt_323(char *to, const unsigned long *salt);
void make_scrambled_password(char *to, const char *password);
void scramble(char *to, const char *message, const char *password);
my_bool check_scramble(const char *reply, const char *message,
my_bool check_scramble(const unsigned char *reply, const char *message,
const unsigned char *hash_stage2);
void get_salt_from_password(unsigned char *res, const char *password);
void make_password_from_salt(char *to, const unsigned char *hash_stage2);

65
include/sql_common.h

@ -1,3 +1,4 @@
#ifndef SQL_COMMON_INCLUDED
/* Copyright (C) 2003-2004, 2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@ -13,14 +14,60 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define SQL_COMMON_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include <mysql.h>
extern const char *unknown_sqlstate;
extern const char *cant_connect_sqlstate;
extern const char *not_error_sqlstate;
#ifdef __cplusplus
extern "C" {
struct st_mysql_options_extention {
char *plugin_dir;
char *default_auth;
};
typedef struct st_mysql_methods
{
my_bool (*read_query_result)(MYSQL *mysql);
my_bool (*advanced_command)(MYSQL *mysql,
enum enum_server_command command,
const unsigned char *header,
unsigned long header_length,
const unsigned char *arg,
unsigned long arg_length,
my_bool skip_check,
MYSQL_STMT *stmt);
MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
unsigned int fields);
MYSQL_RES * (*use_result)(MYSQL *mysql);
void (*fetch_lengths)(unsigned long *to,
MYSQL_ROW column, unsigned int field_count);
void (*flush_use_result)(MYSQL *mysql);
int (*read_change_user_result)(MYSQL *mysql);
#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
MYSQL_FIELD * (*list_fields)(MYSQL *mysql);
my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt);
int (*stmt_execute)(MYSQL_STMT *stmt);
int (*read_binary_rows)(MYSQL_STMT *stmt);
int (*unbuffered_fetch)(MYSQL *mysql, char **row);
void (*free_embedded_thd)(MYSQL *mysql);
const char *(*read_statistics)(MYSQL *mysql);
my_bool (*next_result)(MYSQL *mysql);
int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
#endif
} MYSQL_METHODS;
#define simple_command(mysql, command, arg, length, skip_check) \
(*(mysql)->methods->advanced_command)(mysql, command, 0, \
0, arg, length, skip_check, NULL)
#define stmt_command(mysql, command, arg, length, stmt) \
(*(mysql)->methods->advanced_command)(mysql, command, 0, \
0, arg, length, 1, stmt)
extern CHARSET_INFO *default_client_charset_info;
MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
@ -42,9 +89,23 @@ void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net);
void set_stmt_error(MYSQL_STMT *stmt, int errcode, const char *sqlstate,
const char *err);
void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate);
void set_mysql_extended_error(MYSQL *mysql, int errcode, const char *sqlstate,
const char *format, ...);
/* client side of the pluggable authentication */
struct st_plugin_vio_info;
void mpvio_info(Vio *vio, struct st_plugin_vio_info *info);
int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
char *data_plugin, const char *db);
int mysql_client_plugin_init();
void mysql_client_plugin_deinit();
struct st_mysql_client_plugin;
extern struct st_mysql_client_plugin *mysql_client_builtins[];
#ifdef __cplusplus
}
#endif
#define protocol_41(A) ((A)->server_capabilities & CLIENT_PROTOCOL_41)
#endif

3
libmysql/CMakeLists.txt

@ -98,7 +98,7 @@ SET(CLIENT_SOURCES ../mysys/array.c ../strings/bchange.c ../strings/bmove.c
../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c
../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c
../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c ../mysys/mf_qsort.c
../mysys/my_getsystime.c ../mysys/my_sync.c ${LIB_SOURCES})
../mysys/my_getsystime.c ../mysys/my_sync.c ../sql-common/client_plugin.c ${LIB_SOURCES})
# Need to set USE_TLS for building the DLL, since __declspec(thread)
# approach to thread local storage does not work properly in DLLs.
@ -125,6 +125,7 @@ IF(WIN32)
ENDIF(WIN32)
ADD_DEPENDENCIES(libmysql GenError)
TARGET_LINK_LIBRARIES(libmysql wsock32)
ADD_DEFINITIONS(-DHAVE_DLOPEN)
IF(EMBED_MANIFESTS)
MYSQL_EMBED_MANIFEST("myTest" "asInvoker")

14
libmysql/Makefile.shared

@ -23,6 +23,7 @@
MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
pkgplugindir = $(pkglibdir)/plugin
## We'll use CLIENT_EXTRA_LDFLAGS for threaded and non-threaded
## until someone complains that they need separate options.
LDADD = @CLIENT_EXTRA_LDFLAGS@ $(target)
@ -71,26 +72,27 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
my_getopt.lo my_gethostbyname.lo my_port.lo \
my_rename.lo my_chsize.lo my_sync.lo my_getsystime.lo
sqlobjects = net.lo
sql_cmn_objects = pack.lo client.lo my_time.lo
sql_cmn_objects = pack.lo client.lo my_time.lo client_plugin.lo
# Not needed in the minimum library
mysysobjects2 = my_lib.lo mf_qsort.lo
mysysobjects = $(mysysobjects1) $(mysysobjects2)
target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) \
$(sql_cmn_objects) $(vio_objects) $(sqlobjects)
target_ldflags = -version-info @SHARED_LIB_VERSION@ @LD_VERSION_SCRIPT@
target_ldflags = -version-info @SHARED_LIB_VERSION@ @LD_VERSION_SCRIPT@ @LIBDL@
vio_objects= vio.lo viosocket.lo viossl.lo viosslfactories.lo
BUILT_SOURCES = link_sources
CLEANFILES = $(target_libadd) $(SHLIBOBJS) \
$(target) $(BUILT_SOURCES)
DEFS = -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
-DMYSQL_DATADIR="\"$(MYSQLDATAdir)\"" \
DEFS = -DDEFAULT_CHARSET_HOME='"$(MYSQLBASEdir)"' \
-DMYSQL_DATADIR='"$(MYSQLDATAdir)"' \
-DDEFAULT_HOME_ENV=MYSQL_HOME \
-DPLUGINDIR='"$(pkgplugindir)"' \
-DDEFAULT_GROUP_SUFFIX_ENV=MYSQL_GROUP_SUFFIX \
-DDEFAULT_SYSCONFDIR="\"$(sysconfdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" $(target_defs)
-DDEFAULT_SYSCONFDIR='"$(sysconfdir)"' \
-DSHAREDIR='"$(MYSQLSHAREdir)"' $(target_defs)
if HAVE_YASSL
yassl_las = $(top_builddir)/extra/yassl/src/libyassl.la \

5
libmysql/client_settings.h

@ -18,7 +18,8 @@ extern char * mysql_unix_port;
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \
CLIENT_TRANSACTIONS | \
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION)
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION | \
CLIENT_PLUGIN_AUTH)
sig_handler my_pipe_sig_handler(int sig);
void read_user_name(char *name);
@ -57,7 +58,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt);
int cli_read_binary_rows(MYSQL_STMT *stmt);
int cli_unbuffered_fetch(MYSQL *mysql, char **row);
const char * cli_read_statistics(MYSQL *mysql);
int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd);
int cli_read_change_user_result(MYSQL *mysql);
#ifdef EMBEDDED_LIBRARY
int init_embedded_server(int argc, char **argv, char **groups);

3
libmysql/errmsg.c

@ -85,6 +85,7 @@ const char *client_errors[]=
"Lost connection to MySQL server at '%s', system error: %d",
"Statement closed indirectly because of a preceeding %s() call",
"The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again",
"Authentication plugin '%s' cannot be loaded: %s",
""
};
@ -151,6 +152,7 @@ const char *client_errors[]=
"Lost connection to MySQL server at '%s', system error: %d",
"Statement closed indirectly because of a preceeding %s() call",
"The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again",
"Authentication plugin '%s' cannot be loaded: %s",
""
};
@ -215,6 +217,7 @@ const char *client_errors[]=
"Lost connection to MySQL server at '%s', system error: %d",
"Statement closed indirectly because of a preceeding %s() call",
"The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again",
"Authentication plugin '%s' cannot be loaded: %s",
""
};
#endif

103
libmysql/libmysql.c

@ -126,12 +126,13 @@ int STDCALL mysql_server_init(int argc __attribute__((unused)),
if (my_init()) /* Will init threads */
return 1;
init_client_errs();
if (mysql_client_plugin_init())
return 1;
if (!mysql_port)
{
mysql_port = MYSQL_PORT;
#ifndef MSDOS
{
struct servent *serv_ptr;
char *env;
/*
@ -145,6 +146,7 @@ int STDCALL mysql_server_init(int argc __attribute__((unused)),
*/
#if MYSQL_PORT_DEFAULT == 0
struct servent *serv_ptr;
if ((serv_ptr = getservbyname("mysql", "tcp")))
mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
#endif
@ -198,6 +200,8 @@ void STDCALL mysql_server_end()
if (!mysql_client_init)
return;
mysql_client_plugin_deinit();
#ifdef EMBEDDED_LIBRARY
end_embedded_server();
#endif
@ -662,44 +666,14 @@ mysql_connect(MYSQL *mysql,const char *host,
Change user and database
**************************************************************************/
int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
{
NET *net= &mysql->net;
ulong pkt_length;
pkt_length= cli_safe_read(mysql);
if (pkt_length == packet_error)
return 1;
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. The reply contains scramble_323.
*/
scramble_323(buff, mysql->scramble, passwd);
if (my_net_write(net, (uchar*) buff, SCRAMBLE_LENGTH_323 + 1) ||
net_flush(net))
{
set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
return 1;
}
/* Read what server thinks about out new auth message report */
if (cli_safe_read(mysql) == packet_error)
return 1;
}
return 0;
}
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const char *passwd, const char *db)
{
char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2];
char *end= buff;
int rc;
CHARSET_INFO *saved_cs= mysql->charset;
char *saved_user= mysql->user;
char *saved_passwd= mysql->passwd;
char *saved_db= mysql->db;
DBUG_ENTER("mysql_change_user");
@ -713,49 +687,11 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
/* Use an empty string instead of NULL. */
if (!user)
user="";
if (!passwd)
passwd="";
/*
Store user into the buffer.
Advance position as strmake returns a pointer to the closing NUL.
*/
end= strmake(end, user, USERNAME_LENGTH) + 1;
/* write scrambled password according to server capabilities */
if (passwd[0])
{
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
*end++= SCRAMBLE_LENGTH;
scramble(end, mysql->scramble, passwd);
end+= SCRAMBLE_LENGTH;
}
else
{
scramble_323(end, mysql->scramble, passwd);
end+= SCRAMBLE_LENGTH_323 + 1;
}
}
else
*end++= '\0'; /* empty password */
/* Add database if needed */
end= strmake(end, db ? db : "", NAME_LEN) + 1;
/* Add character set number. */
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
int2store(end, (ushort) mysql->charset->number);
end+= 2;
}
/* Write authentication package */
simple_command(mysql,COM_CHANGE_USER, (uchar*) buff, (ulong) (end-buff), 1);
mysql->user= (char*)(user ? user : "");
mysql->passwd= (char*)(passwd ? passwd : "");
mysql->db= 0;
rc= (*mysql->methods->read_change_user_result)(mysql, buff, passwd);
rc= run_plugin_auth(mysql, 0, 0, 0, db);
/*
The server will close all statements no matter was the attempt
@ -765,18 +701,21 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
if (rc == 0)
{
/* Free old connect information */
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
my_free(saved_user, MYF(MY_ALLOW_ZERO_PTR));
my_free(saved_passwd, MYF(MY_ALLOW_ZERO_PTR));
my_free(saved_db, MYF(MY_ALLOW_ZERO_PTR));
/* alloc new connect information */
mysql->user= my_strdup(user,MYF(MY_WME));
mysql->passwd=my_strdup(passwd,MYF(MY_WME));
mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
mysql->user= my_strdup(mysql->user, MYF(MY_WME));
mysql->passwd= my_strdup(mysql->passwd, MYF(MY_WME));
mysql->db= db ? my_strdup(db, MYF(MY_WME)) : 0;
}
else
{
mysql->charset= saved_cs;
mysql->user= saved_user;
mysql->passwd= saved_passwd;
mysql->db= saved_db;
}
DBUG_RETURN(rc);

10
libmysqld/Makefile.am

@ -25,10 +25,10 @@ pkgplugindir = $(pkglibdir)/plugin
EXTRA_DIST = libmysqld.def CMakeLists.txt
DEFS = -DEMBEDDED_LIBRARY -DMYSQL_SERVER \
-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
-DMYSQL_DATADIR="\"$(MYSQLDATAdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
-DPLUGINDIR="\"$(pkgplugindir)\""
-DDEFAULT_MYSQL_HOME='"$(MYSQLBASEdir)"' \
-DMYSQL_DATADIR='"$(MYSQLDATAdir)"' \
-DSHAREDIR='"$(MYSQLSHAREdir)"' \
-DPLUGINDIR='"$(pkgplugindir)"'
INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include \
-I$(top_builddir)/sql -I$(top_srcdir)/sql \
-I$(top_srcdir)/sql/examples \
@ -41,7 +41,7 @@ pkglib_LIBRARIES = libmysqld.a
SUBDIRS = . examples
libmysqld_sources= libmysqld.c lib_sql.cc emb_qcache.cc
libmysqlsources = errmsg.c get_password.c libmysql.c client.c pack.c \
my_time.c
my_time.c client_plugin.c
noinst_HEADERS = embedded_priv.h emb_qcache.h

2
libmysqld/embedded_priv.h

@ -15,6 +15,8 @@
/* Prototypes for the embedded version of MySQL */
#include <sql_common.h>
C_MODE_START
void lib_connection_phase(NET *net, int phase);
void init_embedded_mysql(MYSQL *mysql, int client_flag);

79
libmysqld/lib_sql.cc

@ -35,7 +35,6 @@ C_MODE_START
#include <mysql.h>
#undef ER
#include "errmsg.h"
#include <sql_common.h>
#include "embedded_priv.h"
extern unsigned int mysql_server_last_errno;
@ -413,11 +412,10 @@ static MYSQL_RES * emb_store_result(MYSQL *mysql)
return mysql_store_result(mysql);
}
int emb_read_change_user_result(MYSQL *mysql,
char *buff __attribute__((unused)),
const char *passwd __attribute__((unused)))
int emb_read_change_user_result(MYSQL *mysql)
{
return mysql_errno(mysql);
mysql->net.read_pos= (uchar*)""; // fake an OK packet
return mysql_errno(mysql) ? packet_error : 1 /* length of the OK packet */;
}
MYSQL_METHODS embedded_methods=
@ -428,6 +426,7 @@ MYSQL_METHODS embedded_methods=
emb_store_result,
emb_fetch_lengths,
emb_flush_use_result,
emb_read_change_user_result,
emb_list_fields,
emb_read_prepare_result,
emb_stmt_execute,
@ -436,7 +435,6 @@ MYSQL_METHODS embedded_methods=
emb_free_embedded_thd,
emb_read_statistics,
emb_read_query_result,
emb_read_change_user_result,
emb_read_rows_from_cursor
};
@ -584,6 +582,7 @@ void init_embedded_mysql(MYSQL *mysql, int client_flag)
THD *thd = (THD *)mysql->thd;
thd->mysql= mysql;
mysql->server_version= server_version;
mysql->client_flag= client_flag;
init_alloc_root(&mysql->field_alloc, 8192, 0);
}
@ -648,14 +647,19 @@ err:
int check_embedded_connection(MYSQL *mysql, const char *db)
{
int result;
LEX_STRING db_str = { (char*)db, db ? strlen(db) : 0 };
THD *thd= (THD*)mysql->thd;
thd_init_client_charset(thd, mysql->charset->number);
thd->update_charset();
Security_context *sctx= thd->security_ctx;
sctx->host_or_ip= sctx->host= (char*) my_localhost;
strmake(sctx->priv_host, (char*) my_localhost, MAX_HOSTNAME-1);
sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0));
result= check_user(thd, COM_CONNECT, NULL, 0, db, true);
strmake(sctx->priv_user, mysql->user, USERNAME_LENGTH-1);
sctx->user= my_strdup(mysql->user, MYF(0));
sctx->master_access= GLOBAL_ACLS; // Full rights
/* Change database if necessary */
if (!(result= (db && db[0] && mysql_change_db(thd, &db_str, FALSE))))
my_ok(thd);
net_end_statement(thd);
emb_read_query_result(mysql);
return result;
@ -664,14 +668,15 @@ int check_embedded_connection(MYSQL *mysql, const char *db)
#else
int check_embedded_connection(MYSQL *mysql, const char *db)
{
/*
we emulate a COM_CHANGE_USER user here,
it's easier than to emulate the complete 3-way handshake
*/
char buf[USERNAME_LENGTH + SCRAMBLE_LENGTH + 1 + 2*NAME_LEN + 2], *end;
NET *net= &mysql->net;
THD *thd= (THD*)mysql->thd;
Security_context *sctx= thd->security_ctx;
int result;
char scramble_buff[SCRAMBLE_LENGTH];
int passwd_len;
thd_init_client_charset(thd, mysql->charset->number);
thd->update_charset();
if (mysql->options.client_ip)
{
sctx->host= my_strdup(mysql->options.client_ip, MYF(0));
@ -682,36 +687,44 @@ int check_embedded_connection(MYSQL *mysql, const char *db)
sctx->host_or_ip= sctx->host;
if (acl_check_host(sctx->host, sctx->ip))
{
result= ER_HOST_NOT_PRIVILEGED;
goto err;
}
sctx->user= my_strdup(mysql->user, MYF(0));
/* construct a COM_CHANGE_USER packet */
end= strmake(buf, mysql->user, USERNAME_LENGTH) + 1;
memset(thd->scramble, 55, SCRAMBLE_LENGTH); // dummy scramble
thd->scramble[SCRAMBLE_LENGTH]= 0;
if (mysql->passwd && mysql->passwd[0])
{
memset(thd->scramble, 55, SCRAMBLE_LENGTH); // dummy scramble
thd->scramble[SCRAMBLE_LENGTH]= 0;
scramble(scramble_buff, thd->scramble, mysql->passwd);
passwd_len= SCRAMBLE_LENGTH;
*end++= SCRAMBLE_LENGTH;
scramble(end, thd->scramble, mysql->passwd);
end+= SCRAMBLE_LENGTH;
}
else
passwd_len= 0;
*end++= 0;
if((result= check_user(thd, COM_CONNECT,
scramble_buff, passwd_len, db, true)))
goto err;
end= strmake(end, db ? db : "", NAME_LEN) + 1;
return 0;
err:
int2store(end, (ushort) mysql->charset->number);
end+= 2;
/* acl_authenticate() takes the data from thd->net->read_pos */
thd->net.read_pos= (uchar*)buf;
if (acl_authenticate(thd, 0, end - buf))
{
NET *net= &mysql->net;
strmake(net->last_error, thd->main_da.message(), sizeof(net->last_error)-1);
memcpy(net->sqlstate,
mysql_errno_to_sqlstate(thd->main_da.sql_errno()),
sizeof(net->sqlstate)-1);
x_free(thd->security_ctx->user);
goto err;
}
return result;
return 0;
err:
strmake(net->last_error, thd->main_da.message(), sizeof(net->last_error)-1);
memcpy(net->sqlstate,
mysql_errno_to_sqlstate(thd->main_da.sql_errno()),
sizeof(net->sqlstate)-1);
return 1;
}
#endif

14
libmysqld/libmysqld.c

@ -18,7 +18,6 @@
#include <mysql_embed.h>
#include <mysqld_error.h>
#include <my_pthread.h>
#include "embedded_priv.h"
#include <my_sys.h>
#include <mysys_err.h>
#include <m_string.h>
@ -28,6 +27,7 @@
#include <sys/stat.h>
#include <signal.h>
#include <time.h>
#include "embedded_priv.h"
#include "client_settings.h"
#ifdef HAVE_PWD_H
#include <pwd.h>
@ -81,9 +81,9 @@ static my_bool is_NT(void)
** Shut down connection
**************************************************************************/
static void end_server(MYSQL *mysql)
void embedded_end_server(MYSQL *mysql)
{
DBUG_ENTER("end_server");
DBUG_ENTER("embedded_end_server");
free_old_query(mysql);
DBUG_VOID_RETURN;
}
@ -169,7 +169,11 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
client_flag|=CLIENT_CAPABILITIES;
if (client_flag & CLIENT_MULTI_STATEMENTS)
client_flag|= CLIENT_MULTI_RESULTS;
client_flag&= ~CLIENT_COMPRESS;
/*
no compression in embedded as we don't send any data,
and no pluggable auth, as we cannot do a client-server dialog
*/
client_flag&= ~(CLIENT_COMPRESS | CLIENT_PLUGIN_AUTH);
if (db)
client_flag|=CLIENT_CONNECT_WITH_DB;
@ -216,7 +220,7 @@ error:
{
/* Free alloced memory */
my_bool free_me=mysql->free_me;
end_server(mysql);
embedded_end_server(mysql);
mysql->free_me=0;
mysql_close(mysql);
mysql->free_me=free_me;

33
mysql-test/r/change_user.result

@ -1,3 +1,36 @@
grant select on test.* to test_nopw;
grant select on test.* to test_oldpw identified by password "09301740536db389";
grant select on test.* to test_newpw identified by "newpw";
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
concat('<', user(), '>') concat('<', current_user(), '>') database()
<root@localhost> <root@localhost> test
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
concat('<', user(), '>') concat('<', current_user(), '>') database()
<test_nopw@localhost> <test_nopw@%> NULL
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
concat('<', user(), '>') concat('<', current_user(), '>') database()
<test_oldpw@localhost> <test_oldpw@%> NULL
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
concat('<', user(), '>') concat('<', current_user(), '>') database()
<test_newpw@localhost> <test_newpw@%> NULL
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
concat('<', user(), '>') concat('<', current_user(), '>') database()
<root@localhost> <root@localhost> NULL
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
concat('<', user(), '>') concat('<', current_user(), '>') database()
<test_nopw@localhost> <test_nopw@%> test
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
concat('<', user(), '>') concat('<', current_user(), '>') database()
<test_oldpw@localhost> <test_oldpw@%> test
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
concat('<', user(), '>') concat('<', current_user(), '>') database()
<test_newpw@localhost> <test_newpw@%> test
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
concat('<', user(), '>') concat('<', current_user(), '>') database()
<root@localhost> <root@localhost> test
drop user test_nopw;
drop user test_oldpw;
drop user test_newpw;
Bug#20023
SELECT @@session.sql_big_selects;
@@session.sql_big_selects

13
mysql-test/r/grant.result

@ -13,8 +13,8 @@ GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3
GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost'
grant delete on mysqltest.* to mysqltest_1@localhost;
select * from mysql.user where user="mysqltest_1";
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA'
@ -44,15 +44,15 @@ delete from mysql.user where user='mysqltest_1';
flush privileges;
grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10;
select * from mysql.user where user="mysqltest_1";
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 0 0 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10
grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30;
select * from mysql.user where user="mysqltest_1";
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30
@ -164,6 +164,7 @@ Warnings:
Warning 1364 Field 'ssl_cipher' doesn't have a default value
Warning 1364 Field 'x509_issuer' doesn't have a default value
Warning 1364 Field 'x509_subject' doesn't have a default value
Warning 1364 Field 'auth_string' doesn't have a default value
insert into mysql.db (host, db, user, select_priv) values
('localhost', 'a%', 'test11', 'Y'), ('localhost', 'ab%', 'test11', 'Y');
alter table mysql.db order by db asc;

2
mysql-test/r/grant2.result

@ -287,6 +287,7 @@ Warnings:
Warning 1364 Field 'ssl_cipher' doesn't have a default value
Warning 1364 Field 'x509_issuer' doesn't have a default value
Warning 1364 Field 'x509_subject' doesn't have a default value
Warning 1364 Field 'auth_string' doesn't have a default value
create user mysqltest_A@'%';
rename user mysqltest_B@'%' to mysqltest_C@'%';
drop user mysqltest_C@'%';
@ -354,6 +355,7 @@ Warnings:
Warning 1364 Field 'ssl_cipher' doesn't have a default value
Warning 1364 Field 'x509_issuer' doesn't have a default value
Warning 1364 Field 'x509_subject' doesn't have a default value
Warning 1364 Field 'auth_string' doesn't have a default value
INSERT INTO mysql.db (host, db, user, select_priv) VALUES
('%','TESTDB','mysqltest_1','Y');
FLUSH PRIVILEGES;

6
mysql-test/r/ps.result

@ -1194,13 +1194,13 @@ SET @aux= "SELECT COUNT(*)
prepare my_stmt from @aux;
execute my_stmt;
COUNT(*)
39
41
execute my_stmt;
COUNT(*)
39
41
execute my_stmt;
COUNT(*)
39
41
deallocate prepare my_stmt;
drop procedure if exists p1|
drop table if exists t1|

2
mysql-test/r/sp_notembedded.result

@ -191,6 +191,8 @@ max_updates, max_connections, max_user_connections)
VALUES('%', 'mysqltest_1', password(''), 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'N', 'N',
'N', 'N', 'N', 'Y', 'Y', 'N', 'N', 'Y', 'Y', 'N', 'N', 'N', 'N', 'N', 'Y', 'Y', 'N', '',
'', '', '', '0', '0', '0', '0');
Warnings:
Warning 1364 Field 'auth_string' doesn't have a default value
FLUSH PRIVILEGES;
CREATE PROCEDURE p1(i INT) BEGIN END;
DROP PROCEDURE p1;

2
mysql-test/r/system_mysql_db.result

@ -118,6 +118,8 @@ user CREATE TABLE `user` (
`max_updates` int(11) unsigned NOT NULL DEFAULT '0',
`max_connections` int(11) unsigned NOT NULL DEFAULT '0',
`max_user_connections` int(11) unsigned NOT NULL DEFAULT '0',
`plugin` char(60) CHARACTER SET latin1 NOT NULL DEFAULT '',
`auth_string` text COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`Host`,`User`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges'
show create table func;

5
mysql-test/suite/funcs_1/r/is_columns_mysql.result

@ -178,6 +178,7 @@ NULL mysql time_zone_transition_type Time_zone_id 1 NULL NO int NULL NULL 10 0 N
NULL mysql time_zone_transition_type Transition_type_id 2 NULL NO int NULL NULL 10 0 NULL NULL int(10) unsigned PRI select,insert,update,references
NULL mysql user Alter_priv 17 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references
NULL mysql user Alter_routine_priv 28 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references
NULL mysql user auth_string 41 NULL NO text 65535 65535 NULL NULL utf8 utf8_bin text select,insert,update,references
NULL mysql user Create_priv 8 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references
NULL mysql user Create_routine_priv 27 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references
NULL mysql user Create_tmp_table_priv 20 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references
@ -198,6 +199,7 @@ NULL mysql user max_questions 36 0 NO int NULL NULL 10 0 NULL NULL int(11) unsig
NULL mysql user max_updates 37 0 NO int NULL NULL 10 0 NULL NULL int(11) unsigned select,insert,update,references
NULL mysql user max_user_connections 39 0 NO int NULL NULL 10 0 NULL NULL int(11) unsigned select,insert,update,references
NULL mysql user Password 3 NO char 41 41 NULL NULL latin1 latin1_bin char(41) select,insert,update,references
NULL mysql user plugin 40 NO char 60 60 NULL NULL latin1 latin1_swedish_ci char(60) select,insert,update,references
NULL mysql user Process_priv 12 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references
NULL mysql user References_priv 15 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references
NULL mysql user Reload_priv 10 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references
@ -233,6 +235,7 @@ COL_CML DATA_TYPE CHARACTER_SET_NAME COLLATION_NAME
1.0000 char latin1 latin1_bin
1.0000 char latin1 latin1_swedish_ci
1.0000 varchar latin1 latin1_swedish_ci
1.0000 text utf8 utf8_bin
1.0000 mediumtext utf8 utf8_general_ci
1.0000 text utf8 utf8_general_ci
SELECT DISTINCT
@ -497,3 +500,5 @@ NULL mysql user max_questions int NULL NULL NULL NULL int(11) unsigned
NULL mysql user max_updates int NULL NULL NULL NULL int(11) unsigned
NULL mysql user max_connections int NULL NULL NULL NULL int(11) unsigned
NULL mysql user max_user_connections int NULL NULL NULL NULL int(11) unsigned
1.0000 mysql user plugin char 60 60 latin1 latin1_swedish_ci char(60)
1.0000 mysql user auth_string text 65535 65535 utf8 utf8_bin text

88
mysql-test/suite/funcs_1/r/is_user_privileges.result

@ -76,10 +76,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser3'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
#
# Add GRANT OPTION db_datadict.* to testuser1;
GRANT UPDATE ON db_datadict.* TO 'testuser1'@'localhost' WITH GRANT OPTION;
@ -93,10 +93,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser3'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
# Establish connection testuser1 (user=testuser1)
SELECT * FROM information_schema.user_privileges
WHERE grantee LIKE '''testuser%'''
@ -105,10 +105,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser1'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
SHOW GRANTS;
Grants for testuser1@localhost
GRANT USAGE ON *.* TO 'testuser1'@'localhost'
@ -130,10 +130,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser3'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 Y N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 Y N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
GRANT SELECT ON *.* TO 'testuser1'@'localhost' WITH GRANT OPTION;
#
# Here <SELECT YES> is shown correctly for testuser1;
@ -147,10 +147,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser3'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 Y N N N N N N N N N Y N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 Y N N N N N N N N N Y N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
# Switch to connection testuser1
SELECT * FROM information_schema.user_privileges
WHERE grantee LIKE '''testuser%'''
@ -159,10 +159,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser1'@'localhost' NULL SELECT YES
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 Y N N N N N N N N N Y N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 Y N N N N N N N N N Y N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
SHOW GRANTS;
Grants for testuser1@localhost
GRANT SELECT ON *.* TO 'testuser1'@'localhost' WITH GRANT OPTION
@ -207,10 +207,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser3'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
# Switch to connection testuser1
SELECT * FROM information_schema.user_privileges
WHERE grantee LIKE '''testuser%'''
@ -253,10 +253,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser3'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
# Switch to connection testuser1
SELECT * FROM information_schema.user_privileges
WHERE grantee LIKE '''testuser%'''
@ -265,10 +265,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser1'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
SHOW GRANTS;
Grants for testuser1@localhost
GRANT USAGE ON *.* TO 'testuser1'@'localhost'
@ -284,10 +284,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser1'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
SHOW GRANTS;
Grants for testuser1@localhost
GRANT USAGE ON *.* TO 'testuser1'@'localhost'
@ -309,10 +309,10 @@ GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
'testuser3'@'localhost' NULL USAGE NO
SELECT * FROM mysql.user
WHERE user LIKE 'testuser%' ORDER BY host, user;
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost testuser1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser2 N Y Y N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
localhost testuser3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0
# Switch to connection testuser1
SELECT * FROM information_schema.user_privileges
WHERE grantee LIKE '''testuser%'''

13
mysql-test/suite/pbxt/r/grant.result

@ -11,8 +11,8 @@ GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3
GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost'
grant delete on mysqltest.* to mysqltest_1@localhost;
select * from mysql.user where user="mysqltest_1";
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA'
@ -42,15 +42,15 @@ delete from mysql.user where user='mysqltest_1';
flush privileges;
grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10;
select * from mysql.user where user="mysqltest_1";
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 0 0 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 0 0 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10
grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30;
select * from mysql.user where user="mysqltest_1";
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 0
Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin auth_string
localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30
@ -162,6 +162,7 @@ Warnings:
Warning 1364 Field 'ssl_cipher' doesn't have a default value
Warning 1364 Field 'x509_issuer' doesn't have a default value
Warning 1364 Field 'x509_subject' doesn't have a default value
Warning 1364 Field 'auth_string' doesn't have a default value
insert into mysql.db (host, db, user, select_priv) values
('localhost', 'a%', 'test11', 'Y'), ('localhost', 'ab%', 'test11', 'Y');
alter table mysql.db order by db asc;

1
mysql-test/suite/rpl/r/rpl_ignore_table.result

@ -34,6 +34,7 @@ Warnings:
Warning 1364 Field 'ssl_cipher' doesn't have a default value
Warning 1364 Field 'x509_issuer' doesn't have a default value
Warning 1364 Field 'x509_subject' doesn't have a default value
Warning 1364 Field 'auth_string' doesn't have a default value
GRANT SELECT ON *.* TO mysqltest6@localhost;
GRANT INSERT ON *.* TO mysqltest6@localhost;
GRANT INSERT ON test.* TO mysqltest6@localhost;

1
mysql-test/suite/rpl/r/rpl_stm_000001.result

@ -66,6 +66,7 @@ Warnings:
Warning 1364 Field 'ssl_cipher' doesn't have a default value
Warning 1364 Field 'x509_issuer' doesn't have a default value
Warning 1364 Field 'x509_subject' doesn't have a default value
Warning 1364 Field 'auth_string' doesn't have a default value
select select_priv,user from mysql.user where user = _binary'blafasel2';
select_priv user
N blafasel2

46
mysql-test/t/change_user.test

@ -1,3 +1,49 @@
#
# functional change user tests
#
grant select on test.* to test_nopw;
grant select on test.* to test_oldpw identified by password "09301740536db389";
grant select on test.* to test_newpw identified by "newpw";
#
# massaging the data for tests to pass in the embedded server,
# that has authentication completely disabled.
#
--replace_result <@> <test_nopw@%> @> @localhost>
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
change_user test_nopw;
--replace_result <@> <test_nopw@%> @> @localhost>
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
change_user test_oldpw, oldpw;
--replace_result <@> <test_oldpw@%> @> @localhost>
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
change_user test_newpw, newpw;
--replace_result <@> <test_newpw@%> @> @localhost>
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
change_user root;
--replace_result <@> <root@localhost> @> @localhost>
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
change_user test_nopw,,test;
--replace_result <@> <test_nopw@%> @> @localhost>
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
change_user test_oldpw,oldpw,test;
--replace_result <@> <test_oldpw@%> @> @localhost>
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
change_user test_newpw,newpw,test;
--replace_result <@> <test_newpw@%> @> @localhost>
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
change_user root,,test;
--replace_result <@> <root@localhost> @> @localhost>
select concat('<', user(), '>'), concat('<', current_user(), '>'), database();
drop user test_nopw;
drop user test_oldpw;
drop user test_newpw;
#
# Bug#20023 mysql_change_user() resets the value of SQL_BIG_SELECTS
# The replace's are here to fix things for 32 bit systems

10
mysys/Makefile.am

@ -74,13 +74,13 @@ libmysys_a_LIBADD = @THREAD_LOBJECTS@
# testhash_DEPENDENCIES= $(LIBRARIES)
# test_charset_DEPENDENCIES= $(LIBRARIES)
# charset2html_DEPENDENCIES= $(LIBRARIES)
DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" \
-DMYSQL_DATADIR="\"$(MYSQLDATAdir)\"" \
-DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
DEFS = -DDEFAULT_BASEDIR='"$(prefix)"' \
-DMYSQL_DATADIR='"$(MYSQLDATAdir)"' \
-DDEFAULT_CHARSET_HOME='"$(MYSQLBASEdir)"' \
-DSHAREDIR'="$(MYSQLSHAREdir)"' \
-DDEFAULT_HOME_ENV=MYSQL_HOME \
-DDEFAULT_GROUP_SUFFIX_ENV=MYSQL_GROUP_SUFFIX \
-DDEFAULT_SYSCONFDIR="\"$(sysconfdir)\"" \
-DDEFAULT_SYSCONFDIR='"$(sysconfdir)"' \
@DEFS@
libmysys_a_DEPENDENCIES= @THREAD_LOBJECTS@

15
plugin/auth/Makefile.am

@ -0,0 +1,15 @@
pkgplugindir=$(pkglibdir)/plugin
AM_LDFLAGS=-module -rpath $(pkgplugindir)
AM_CPPFLAGS=-DMYSQL_DYNAMIC_PLUGIN -I$(top_srcdir)/include
pkgplugin_LTLIBRARIES= dialog.la
dialog_la_SOURCES= dialog.c
if HAVE_PEERCRED
pkgplugin_LTLIBRARIES+= auth_socket.la
auth_socket_la_SOURCES= auth_socket.c
endif
EXTRA_DIST= plug.in

102
plugin/auth/auth_socket.c

@ -0,0 +1,102 @@
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**
@file
socket_peercred authentication plugin.
Authentication is successful if the connection is done via a unix socket and
the owner of the client process matches the user name that was used when
connecting to mysqld.
*/
#define _GNU_SOURCE /* for struct ucred */
#include <mysql/plugin_auth.h>
#include <sys/socket.h>
#include <pwd.h>
#include <string.h>
/**
perform the unix socket based authentication
This authentication callback performs a unix socket based authentication -
it gets the uid of the client process and considers the user authenticated
if it uses username of this uid. That is - if the user is already
authenticated to the OS (if she is logged in) - she can use MySQL as herself
*/
static int socket_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
{
unsigned char *pkt;
MYSQL_PLUGIN_VIO_INFO vio_info;
struct ucred cred;
socklen_t cred_len= sizeof(cred);
struct passwd pwd_buf, *pwd;
char buf[1024];
/* no user name yet ? read the client handshake packet with the user name */
if (info->user_name == 0)
{
if (vio->read_packet(vio, &pkt) < 0)
return CR_ERROR;
}
info->password_used = 0;
vio->info(vio, &vio_info);
if (vio_info.protocol != MYSQL_VIO_SOCKET)
return CR_ERROR;
/* get the UID of the client process */
if (getsockopt(vio_info.socket, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len))
return CR_ERROR;
if (cred_len != sizeof(cred))
return CR_ERROR;
/* and find the username for this uid */
getpwuid_r(cred.uid, &pwd_buf, buf, sizeof(buf), &pwd);
if (pwd == NULL)
return CR_ERROR;
/* now it's simple as that */
return strcmp(pwd->pw_name, info->user_name) ? CR_ERROR : CR_OK;
}
static struct st_mysql_auth socket_auth_handler=
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
0,
socket_auth
};
mysql_declare_plugin(socket_auth)
{
MYSQL_AUTHENTICATION_PLUGIN,
&socket_auth_handler,
"socket_peercred",
"Sergei Golubchik",
"Unix Socket based authentication",
PLUGIN_LICENSE_GPL,
NULL,
NULL,
0x0100,
NULL,
NULL,
NULL
}
mysql_declare_plugin_end;

302
plugin/auth/dialog.c

@ -0,0 +1,302 @@
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**
@file
dialog client authentication plugin with examples
dialog is a general purpose client authentication plugin, it simply
asks the user the question, as provided by the server and reports
the answer back to the server. No encryption is involved,
the answers are sent in clear text.
Two examples are provided: two_questions server plugin, that asks
the password and an "Are you sure?" question with a reply "yes, of course".
It demonstrates the usage of "password" (input is hidden) and "ordinary"
(input can be echoed) questions, and how to mark the last question,
to avoid an extra roundtrip.
And three_attempts plugin that gives the user three attempts to enter
a correct password. It shows the situation when a number of questions
is not known in advance.
*/
#define _GNU_SOURCE /* for RTLD_DEFAULT */
#include <mysql/plugin_auth.h>
#include <mysql/client_plugin.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/**
first byte of the question string is the question "type".
It can be a "ordinary" or a "password" question.
The last bit set marks a last question in the authentication exchange.
*/
#define ORDINARY_QUESTION "\2"
#define LAST_QUESTION "\3"
#define PASSWORD_QUESTION "\4"
#define LAST_PASSWORD "\5"
/********************* SERVER SIDE ****************************************/
/**
dialog demo with two questions, one password and one ordinary.
*/
static int two_questions(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
{
unsigned char *pkt;
int pkt_len;
/* send a password question */
if (vio->write_packet(vio, PASSWORD_QUESTION "Password, please:", 18))
return CR_ERROR;
/* read the answer */
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
return CR_ERROR;
info->password_used = 1;
/* fail if the password is wrong */
if (strcmp(pkt, info->auth_string))
return CR_ERROR;
/* send the last, ordinary, question */
if (vio->write_packet(vio, LAST_QUESTION "Are you sure ?", 15))
return CR_ERROR;
/* read the answer */
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
return CR_ERROR;
/* check the reply */
return strcmp(pkt, "yes, of course") ? CR_ERROR : CR_OK;
}
static struct st_mysql_auth two_handler=
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
"dialog", /* requires dialog client plugin */
two_questions
};
/**
dialog demo where the number of questions is not known in advance
*/
static int three_attempts(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
{
unsigned char *pkt;
int pkt_len, i;
for (i= 0; i < 3; i++)
{
/* send the prompt */
if (vio->write_packet(vio, PASSWORD_QUESTION "Password, please:", 18))
return CR_ERROR;
/* read the password */
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
return CR_ERROR;
info->password_used = 1;
/*
finish, if the password is correct.
note, that we did not mark the prompt packet as "last"
*/
if (strcmp(pkt, info->auth_string) == 0)
return CR_OK;
}
return CR_ERROR;
}
static struct st_mysql_auth three_handler=
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
"dialog", /* requires dialog client plugin */
three_attempts
};
mysql_declare_plugin(dialog)
{
MYSQL_AUTHENTICATION_PLUGIN,
&two_handler,
"two_questions",
"Sergei Golubchik",
"Dialog plugin demo 1",
PLUGIN_LICENSE_GPL,
NULL,
NULL,
0x0100,
NULL,
NULL,
NULL
},
{
MYSQL_AUTHENTICATION_PLUGIN,
&three_handler,
"three_attempts",
"Sergei Golubchik",
"Dialog plugin demo 2",
PLUGIN_LICENSE_GPL,
NULL,
NULL,
0x0100,
NULL,
NULL,
NULL
}
mysql_declare_plugin_end;
/********************* CLIENT SIDE ***************************************/
/*
This plugin performs a dialog with the user, asking questions and
reading answers. Depending on the client it may be desirable to do it
using GUI, or console, with or without curses, or read answers
from a smardcard, for example.
To support all this variety, the dialog plugin has a callback function
"authentication_dialog_ask". If the client has a function of this name
dialog plugin will use it for communication with the user. Otherwise
a default gets() based implementation will be used.
*/
#include <mysql.h>
#include <dlfcn.h>
static mysql_authentication_dialog_ask_t ask;
static char *builtin_ask(MYSQL *mysql __attribute__((unused)),
int type __attribute__((unused)),
const char *prompt,
char *buf, int buf_len __attribute__((unused)))
{
fputs(prompt, stdout);
fputc(' ', stdout);
if (gets(buf) == 0)
return 0;
return buf;
}
/**
The main function of the dialog plugin.
Read the prompt, ask the question, send the reply, repeat until
the server is satisfied.
@note
1. this plugin shows how a client authentication plugin
may read a MySQL protocol OK packet internally - which is important
where a number of packets is not known in advance.
2. the first byte of the prompt is special. it is not
shown to the user, but signals whether it is the last question
(prompt[0] & 1 == 1) or not last (prompt[0] & 1 == 0),
and whether the input is a password (not echoed).
3. the prompt is expected to be sent zero-terminated
*/
static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
{
unsigned char *pkt, cmd= 0;
int pkt_len, res;
char reply_buf[1024], *reply;
do
{
/* read the prompt */
pkt_len= vio->read_packet(vio, &pkt);
if (pkt_len < 0)
return CR_ERROR;
if (pkt == 0)
{
/*
in mysql_change_user() the client sends the first packet, so
the first vio->read_packet() does nothing (pkt == 0).
We send the "password", assuming the client knows what its doing.
(in other words, the dialog plugin should be only set as a default
authentication plugin on the client if the first question
asks for a password - which will be sent in clear text, by the way)
*/
reply= mysql->passwd;
}
else
{
cmd= *pkt++;
/* is it MySQL protocol packet ? */
if (cmd == 0 || cmd == 254)
return CR_OK_HANDSHAKE_COMPLETE; /* yes. we're done */
/*
asking for a password with an empty prompt means mysql->password
otherwise we ask the user and read the reply
*/
if ((cmd >> 1) == 2 && *pkt == 0)
reply= mysql->passwd;
else
reply= ask(mysql, cmd >> 1, pkt, reply_buf, sizeof(reply_buf));
if (!reply)
return CR_ERROR;
}
/* send the reply to the server */
res= vio->write_packet(vio, reply, strlen(reply)+1);
if (reply != mysql->passwd && reply != reply_buf)
free(reply);
if (res)
return CR_ERROR;
/* repeat unless it was the last question */
} while ((cmd & 1) != 1);
/* the job of reading the ok/error packet is left to the server */
return CR_OK;
}
/**
initialization function of the dialog plugin
Pick up the client's authentication_dialog_ask() function, if exists,
or fall back to the default implementation.
*/
static int init_dialog()
{
void *sym= dlsym(RTLD_DEFAULT, "mysql_authentication_dialog_ask");
ask= sym ? (mysql_authentication_dialog_ask_t)sym : builtin_ask;
return 0;
}
mysql_declare_client_plugin(AUTHENTICATION)
"dialog",
"Sergei Golubchik",
"Dialog Client Authentication Plugin",
{0,1,0},
init_dialog,
NULL,
perform_dialog
mysql_end_client_plugin;

15
plugin/auth/plug.in

@ -0,0 +1,15 @@
MYSQL_PLUGIN(auth, [Collection of Authentication Plugins],
[Collection of Authentication Plugins])
MYSQL_PLUGIN_DYNAMIC(auth, [dialog.la])
MYSQL_PLUGIN_ACTIONS(auth,[
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[
#define _GNU_SOURCE
#include <sys/socket.h>
]],[[
struct ucred cred;
getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, 0);
]])],have_peercred=yes)
AM_CONDITIONAL(HAVE_PEERCRED, test x$have_peercred = xyes)
])
AM_CONDITIONAL(HAVE_PEERCRED, false)

2
scripts/mysql_system_tables.sql

@ -13,7 +13,7 @@ set @had_db_table= @@warning_count != 0;
CREATE TABLE IF NOT EXISTS host ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY Host (Host,Db) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Host privileges; Merged with database privileges';
CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) unsigned DEFAULT 0 NOT NULL, PRIMARY KEY Host (Host,User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges';
CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) unsigned DEFAULT 0 NOT NULL, plugin char(60) CHARACTER SET latin1 DEFAULT '' NOT NULL, auth_string TEXT NOT NULL, PRIMARY KEY Host (Host,User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges';
-- Remember for later if user table already existed
set @had_user_table= @@warning_count != 0;

6
scripts/mysql_system_tables_data.sql

@ -21,9 +21,9 @@ DROP TABLE tmp_db;
-- from local machine if "users" table didn't exist before
CREATE TEMPORARY TABLE tmp_user LIKE user;
set @current_hostname= @@hostname;
INSERT INTO tmp_user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0 FROM dual WHERE LOWER( @current_hostname) != 'localhost';
REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
INSERT INTO tmp_user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','');
REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','' FROM dual WHERE LOWER( @current_hostname) != 'localhost';
REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','');
INSERT INTO tmp_user (host,user) VALUES ('localhost','');
INSERT INTO tmp_user (host,user) SELECT @current_hostname,'' FROM dual WHERE LOWER(@current_hostname ) != 'localhost';
INSERT INTO user SELECT * FROM tmp_user WHERE @had_user_table=0;

3
scripts/mysql_system_tables_fix.sql

@ -571,6 +571,9 @@ ALTER TABLE tables_priv MODIFY Table_priv set('Select','Insert','Update','Delete
UPDATE user SET Trigger_priv=Super_priv WHERE @hadTriggerPriv = 0;
ALTER TABLE user ADD plugin char(60) CHARACTER SET latin1 DEFAULT '' NOT NULL, ADD auth_string TEXT NOT NULL;
ALTER TABLE user MODIFY plugin char(60) CHARACTER SET latin1 DEFAULT '' NOT NULL;
# Activate the new, possible modified privilege tables
# This should not be needed, but gives us some extra testing that the above
# changes was correct

5
server-tools/instance-manager/Makefile.am

@ -46,7 +46,8 @@ libnet_a_LIBADD= $(top_builddir)/sql/password.$(OBJEXT) \
$(top_builddir)/sql/pack.$(OBJEXT) \
$(top_builddir)/sql/sql_state.$(OBJEXT) \
$(top_builddir)/sql/mini_client_errors.$(OBJEXT)\
$(top_builddir)/sql/client.$(OBJEXT)
$(top_builddir)/sql/client.$(OBJEXT) \
$(top_builddir)/sql/client_plugin.$(OBJEXT)
CLEANFILES= net_serv.cc client_settings.h
@ -91,7 +92,7 @@ mysqlmanager_LDADD= @CLIENT_EXTRA_LDFLAGS@ \
$(top_builddir)/mysys/libmysys.a \
$(top_builddir)/strings/libmystrings.a \
$(top_builddir)/dbug/libdbug.a \
@openssl_libs@ @yassl_libs@ @ZLIB_LIBS@
@openssl_libs@ @yassl_libs@ @ZLIB_LIBS@ @LIBDL@
EXTRA_DIST = WindowsService.cpp WindowsService.h IMService.cpp \
IMService.h CMakeLists.txt

2
server-tools/instance-manager/user_map.cc

@ -368,7 +368,7 @@ int User_map::authenticate(const LEX_STRING *user_name,
const char *scramble) const
{
const User *user= find_user(user_name);
return user ? check_scramble(scrambled_password, scramble, user->salt) : 2;
return user ? check_scramble((uchar*)scrambled_password, scramble, user->salt) : 2;
}

2
sql-common/Makefile.am

@ -14,7 +14,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## Process this file with automake to create Makefile.in
EXTRA_DIST = client.c pack.c my_time.c my_user.c
EXTRA_DIST = client.c pack.c my_time.c my_user.c client_plugin.c
# Don't update the files from bitkeeper
%::SCCS/s.%

1108
sql-common/client.c
File diff suppressed because it is too large
View File

436
sql-common/client_plugin.c

@ -0,0 +1,436 @@
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**
@file
Support code for the client side (libmysql) plugins
Client plugins are somewhat different from server plugins, they are simpler.
They do not need to be installed or in any way explicitly loaded on the
client, they are loaded automatically on demand.
One client plugin per shared object, soname *must* match the plugin name.
There is no reference counting and no unloading either.
*/
#include <my_global.h>
#include "mysql.h"
#include <my_sys.h>
#include <m_string.h>
#ifdef THREAD
#include <my_pthread.h>
#else
#include <my_no_pthread.h>
#endif
#include <sql_common.h>
#include "errmsg.h"
#include <mysql/client_plugin.h>
struct st_client_plugin_int {
struct st_client_plugin_int *next;
void *dlhandle;
struct st_mysql_client_plugin *plugin;
};
static my_bool initialized= 0;
static MEM_ROOT mem_root;
static const char *plugin_declarations_sym= "_mysql_client_plugin_declaration_";
static uint plugin_version[MYSQL_CLIENT_MAX_PLUGINS]=
{
0, /* these two are taken by Connector/C */
0, /* these two are taken by Connector/C */
MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION
};
/*
Loaded plugins are stored in a linked list.
The list is append-only, the elements are added to the head (like in a stack).
The elements are added under a mutex, but the list can be read and traversed
without any mutex because once an element is added to the list, it stays
there. The main purpose of a mutex is to prevent two threads from
loading the same plugin twice in parallel.
*/
struct st_client_plugin_int *plugin_list[MYSQL_CLIENT_MAX_PLUGINS];
#ifdef THREAD
static pthread_mutex_t LOCK_load_client_plugin;
#endif
static int is_not_initialized(MYSQL *mysql, const char *name)
{
if (initialized)
return 0;
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
unknown_sqlstate, ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
name, "not initialized");
return 1;
}
/**
finds a plugin in the list
@param name plugin name to search for
@param type plugin type
@note this does NOT necessarily need a mutex, take care!
@retval a pointer to a found plugin or 0
*/
static struct st_mysql_client_plugin *find_plugin(const char *name, int type)
{
struct st_client_plugin_int *p;
DBUG_ASSERT(initialized);
DBUG_ASSERT(type >= 0 && type < MYSQL_CLIENT_MAX_PLUGINS);
if (type < 0 || type >= MYSQL_CLIENT_MAX_PLUGINS)
return 0;
for (p= plugin_list[type]; p; p= p->next)
{
if (strcmp(p->plugin->name, name) == 0)
return p->plugin;
}
return NULL;
}
/**
verifies the plugin and adds it to the list
@param mysql MYSQL structure (for error reporting)
@param plugin plugin to install
@param dlhandle a handle to the shared object (returned by dlopen)
or 0 if the plugin was not dynamically loaded
@param argc number of arguments in the 'va_list args'
@param args arguments passed to the plugin initialization function
@retval a pointer to an installed plugin or 0
*/
static struct st_mysql_client_plugin *
add_plugin(MYSQL *mysql, struct st_mysql_client_plugin *plugin, void *dlhandle,
int argc, va_list args)
{
const char *errmsg;
struct st_client_plugin_int plugin_int, *p;
char errbuf[1024];
DBUG_ASSERT(initialized);
plugin_int.plugin= plugin;
plugin_int.dlhandle= dlhandle;
if (plugin->type >= MYSQL_CLIENT_MAX_PLUGINS)
{
errmsg= "Unknown client plugin type";
goto err1;
}
if (plugin->interface_version < plugin_version[plugin->type] ||
(plugin->interface_version >> 8) >
(plugin_version[plugin->type] >> 8))
{
errmsg= "Incompatible client plugin interface";
goto err1;
}
/* Call the plugin initialization function, if any */
if (plugin->init && plugin->init(errbuf, sizeof(errbuf), argc, args))
{
errmsg= errbuf;
goto err1;
}
p= (struct st_client_plugin_int *)
memdup_root(&mem_root, &plugin_int, sizeof(plugin_int));
if (!p)
{
errmsg= "Out of memory";
goto err2;
}
safe_mutex_assert_owner(&LOCK_load_client_plugin);
p->next= plugin_list[plugin->type];
plugin_list[plugin->type]= p;
return plugin;
err2:
if (plugin->deinit)
plugin->deinit();
err1:
if (dlhandle)
dlclose(dlhandle);
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate,
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), plugin->name,
errmsg);
return NULL;
}
/**
Loads plugins which are specified in the environment variable
LIBMYSQL_PLUGINS.
Multiple plugins must be separated by semicolon. This function doesn't
return or log an error.
The function is be called by mysql_client_plugin_init
@todo
Support extended syntax, passing parameters to plugins, for example
LIBMYSQL_PLUGINS="plugin1(param1,param2);plugin2;..."
or
LIBMYSQL_PLUGINS="plugin1=int:param1,str:param2;plugin2;..."
*/
static void load_env_plugins(MYSQL *mysql)
{
char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS");
/* no plugins to load */
if (!s)
return;
free_env= plugs= my_strdup(s, MYF(MY_WME));
do {
if ((s= strchr(plugs, ';')))
*s= '\0';
mysql_load_plugin(mysql, plugs, -1, 0);
plugs= s + 1;
} while (s);
my_free(free_env, MYF(0));
}
/********** extern functions to be used by libmysql *********************/
/**
Initializes the client plugin layer.
This function must be called before any other client plugin function.
@retval 0 successful
@retval != 0 error occured
*/
int mysql_client_plugin_init()
{
MYSQL mysql;
struct st_mysql_client_plugin **builtin;
if (initialized)
return 0;
bzero(&mysql, sizeof(mysql)); /* dummy mysql for set_mysql_extended_error */
pthread_mutex_init(&LOCK_load_client_plugin, MY_MUTEX_INIT_SLOW);
init_alloc_root(&mem_root, 128, 128);
bzero(&plugin_list, sizeof(plugin_list));
initialized= 1;
pthread_mutex_lock(&LOCK_load_client_plugin);
for (builtin= mysql_client_builtins; *builtin; builtin++)
add_plugin(&mysql, *builtin, 0, 0, 0);
pthread_mutex_unlock(&LOCK_load_client_plugin);
load_env_plugins(&mysql);
return 0;
}
/**
Deinitializes the client plugin layer.
Unloades all client plugins and frees any associated resources.
*/
void mysql_client_plugin_deinit()
{
int i;
struct st_client_plugin_int *p;
if (!initialized)
return;
for (i=0; i < MYSQL_CLIENT_MAX_PLUGINS; i++)
for (p= plugin_list[i]; p; p= p->next)
{
if (p->plugin->deinit)
p->plugin->deinit();
if (p->dlhandle)
dlclose(p->dlhandle);
}
bzero(&plugin_list, sizeof(plugin_list));
initialized= 0;
free_root(&mem_root, MYF(0));
pthread_mutex_destroy(&LOCK_load_client_plugin);
}
/************* public facing functions, for client consumption *********/
/* see <mysql/client_plugin.h> for a full description */
struct st_mysql_client_plugin *
mysql_client_register_plugin(MYSQL *mysql,
struct st_mysql_client_plugin *plugin)
{
if (is_not_initialized(mysql, plugin->name))
return NULL;
pthread_mutex_lock(&LOCK_load_client_plugin);
/* make sure the plugin wasn't loaded meanwhile */
if (find_plugin(plugin->name, plugin->type))
{
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
unknown_sqlstate, ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
plugin->name, "it is already loaded");
plugin= NULL;
}
else
plugin= add_plugin(mysql, plugin, 0, 0, 0);
pthread_mutex_unlock(&LOCK_load_client_plugin);
return plugin;
}
/* see <mysql/client_plugin.h> for a full description */
struct st_mysql_client_plugin *
mysql_load_plugin_v(MYSQL *mysql, const char *name, int type,
int argc, va_list args)
{
const char *errmsg;
char dlpath[FN_REFLEN+1];
void *sym, *dlhandle;
struct st_mysql_client_plugin *plugin;
if (is_not_initialized(mysql, name))
return NULL;
pthread_mutex_lock(&LOCK_load_client_plugin);
/* make sure the plugin wasn't loaded meanwhile */
if (type >= 0 && find_plugin(name, type))
{
errmsg= "it is already loaded";
goto err;
}
/* Compile dll path */
strxnmov(dlpath, sizeof(dlpath) - 1,
mysql->options.extension && mysql->options.extension->plugin_dir ?
mysql->options.extension->plugin_dir : PLUGINDIR, "/",
name, SO_EXT, NullS);
/* Open new dll handle */
if (!(dlhandle= dlopen(dlpath, RTLD_NOW)))
{
errmsg= dlerror();
goto err;
}
if (!(sym= dlsym(dlhandle, plugin_declarations_sym)))
{
errmsg= "not a plugin";
dlclose(dlhandle);
goto err;
}
plugin= (struct st_mysql_client_plugin*)sym;
if (type >=0 && type != plugin->type)
{
errmsg= "type mismatch";
goto err;
}
if (strcmp(name, plugin->name))
{
errmsg= "name mismatch";
goto err;
}
if (type < 0 && find_plugin(name, plugin->type))
{
errmsg= "it is already loaded";
goto err;
}
plugin= add_plugin(mysql, plugin, dlhandle, argc, args);
pthread_mutex_unlock(&LOCK_load_client_plugin);
return plugin;
err:
pthread_mutex_unlock(&LOCK_load_client_plugin);
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate,
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, errmsg);
return NULL;
}
/* see <mysql/client_plugin.h> for a full description */
struct st_mysql_client_plugin *
mysql_load_plugin(MYSQL *mysql, const char *name, int type, int argc, ...)
{
struct st_mysql_client_plugin *p;
va_list args;
va_start(args, argc);
p= mysql_load_plugin_v(mysql, name, type, argc, args);
va_end(args);
return p;
}
/* see <mysql/client_plugin.h> for a full description */
struct st_mysql_client_plugin *
mysql_client_find_plugin(MYSQL *mysql, const char *name, int type)
{
struct st_mysql_client_plugin *p;
if (is_not_initialized(mysql, name))
return NULL;
if (type < 0 || type >= MYSQL_CLIENT_MAX_PLUGINS)
{
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate,
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name,
"invalid type");
}
if ((p= find_plugin(name, type)))
return p;
/* not found, load it */
return mysql_load_plugin(mysql, name, type, 0);
}

2
sql/CMakeLists.txt

@ -54,7 +54,7 @@ SET (SQL_SOURCE
log_event.cc rpl_record.cc rpl_reporting.cc
log_event_old.cc rpl_record_old.cc
message.h mf_iocache.cc my_decimal.cc ../sql-common/my_time.c
mysqld.cc net_serv.cc
mysqld.cc net_serv.cc ../sql-common/client_plugin.c
nt_servc.cc nt_servc.h opt_range.cc opt_range.h opt_sum.cc
../sql-common/pack.c parse_file.cc password.c procedure.cc
protocol.cc records.cc repl_failsafe.cc rpl_filter.cc set_var.cc

12
sql/Makefile.am

@ -126,7 +126,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
sql_servers.cc event_parse_data.cc \
opt_table_elimination.cc
nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c
nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c client_plugin.c
libndb_la_CPPFLAGS= @ndbcluster_includes@
libndb_la_SOURCES= ha_ndbcluster.cc \
@ -140,10 +140,10 @@ mysql_tzinfo_to_sql_SOURCES = tztime.cc
mysql_tzinfo_to_sql_CXXFLAGS= -DTZINFO2SQL
DEFS = -DMYSQL_SERVER \
-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
-DMYSQL_DATADIR="\"$(MYSQLDATAdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
-DPLUGINDIR="\"$(pkgplugindir)\"" \
-DDEFAULT_MYSQL_HOME='"$(MYSQLBASEdir)"' \
-DMYSQL_DATADIR='"$(MYSQLDATAdir)"' \
-DSHAREDIR='"$(MYSQLSHAREdir)"' \
-DPLUGINDIR='"$(pkgplugindir)"' \
-DHAVE_EVENT_SCHEDULER \
@DEFS@
@ -167,6 +167,8 @@ link_sources:
@LN_CP_F@ $(top_srcdir)/sql-common/pack.c pack.c
rm -f client.c
@LN_CP_F@ $(top_srcdir)/sql-common/client.c client.c
rm -f client_plugin.c
@LN_CP_F@ $(top_srcdir)/sql-common/client_plugin.c client_plugin.c
rm -f my_time.c
@LN_CP_F@ $(top_srcdir)/sql-common/my_time.c my_time.c
rm -f my_user.c

4
sql/client_settings.h

@ -15,6 +15,7 @@
#include <thr_alarm.h>
#include <sql_common.h>
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \
CLIENT_SECURE_CONNECTION | CLIENT_TRANSACTIONS | \
@ -31,7 +32,8 @@
#undef HAVE_SMEM
#undef _CUSTOMCONFIG_
#define mysql_server_init(a,b,c) 0
#define mysql_server_init(a,b,c) mysql_client_plugin_init()
#define mysql_server_end() mysql_client_plugin_deinit()
#ifdef HAVE_REPLICATION
C_MODE_START

2
sql/ha_ndbcluster.cc

@ -9185,7 +9185,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
thd->main_security_ctx.master_access= ~0;
thd->main_security_ctx.priv_user = 0;
thd->main_security_ctx.priv_user[0] = 0;
CHARSET_INFO *charset_connection;
charset_connection= get_charset_by_csname("utf8",

2
sql/ha_ndbcluster_binlog.cc

@ -3681,7 +3681,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
thd->client_capabilities= 0;
my_net_init(&thd->net, 0);
thd->main_security_ctx.master_access= ~0;
thd->main_security_ctx.priv_user= 0;
thd->main_security_ctx.priv_user[0]= 0;
/*
Set up ndb binlog

1
sql/lex.h

@ -590,6 +590,7 @@ static SYMBOL symbols[] = {
{ "VARCHARACTER", SYM(VARCHAR)},
{ "VARIABLES", SYM(VARIABLES)},
{ "VARYING", SYM(VARYING)},
{ "VIA", SYM(VIA_SYM)},
{ "VIEW", SYM(VIEW_SYM)},
{ "VIRTUAL", SYM(VIRTUAL_SYM)},
{ "WAIT", SYM(WAIT_SYM)},

6
sql/mysql_priv.h

@ -1067,9 +1067,6 @@ int write_bin_log(THD *thd, bool clear_error,
char const *query, ulong query_length);
/* sql_connect.cc */
int check_user(THD *thd, enum enum_server_command command,
const char *passwd, uint passwd_len, const char *db,
bool check_count);
pthread_handler_t handle_one_connection(void *arg);
bool init_new_connection_handler_thread();
void reset_mqh(LEX_USER *lu, bool get_them);
@ -1082,6 +1079,9 @@ bool login_connection(THD *thd);
void end_connection(THD *thd);
void prepare_new_connection_state(THD* thd);
void update_global_user_stats(THD* thd, bool create_user, time_t now);
int get_or_create_user_conn(THD *thd, const char *user,
const char *host, USER_RESOURCES *mqh);
int check_for_max_user_connections(THD *thd, USER_CONN *uc);
int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);

3
sql/mysqld.cc

@ -22,6 +22,7 @@
#include "rpl_mi.h"
#include "sql_repl.h"
#include "rpl_filter.h"
#include "client_settings.h"
#include "repl_failsafe.h"
#include <my_stacktrace.h>
#include "mysqld_suffix.h"
@ -1394,6 +1395,7 @@ void clean_up(bool print_message)
if (print_message && errmesg && server_start_time)
sql_print_information(ER(ER_SHUTDOWN_COMPLETE),my_progname);
thread_scheduler.end();
mysql_library_end();
finish_client_errs();
my_free((uchar*) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST),
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
@ -3489,6 +3491,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
if (init_errmessage()) /* Read error messages from file */
return 1;
init_client_errs();
mysql_library_init(never,never,never); /* for replication */
lex_init();
if (item_create_init())
return 1;

12
sql/password.c

@ -193,13 +193,13 @@ void scramble_323(char *to, const char *message, const char *password)
*/
my_bool
check_scramble_323(const char *scrambled, const char *message,
check_scramble_323(const unsigned char *scrambled, const char *message,
ulong *hash_pass)
{
struct my_rnd_struct rand_st;
ulong hash_message[2];
char buff[16],*to,extra; /* Big enough for check */
const char *pos;
uchar buff[16],*to,extra; /* Big enough for check */
const uchar *pos;
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
my_rnd_init(&rand_st,hash_pass[0] ^ hash_message[0],
@ -214,7 +214,7 @@ check_scramble_323(const char *scrambled, const char *message,
to=buff;
while (*scrambled)
{
if (*scrambled++ != (char) (*to++ ^ extra))
if (*scrambled++ != (uchar) (*to++ ^ extra))
return 1; /* Wrong password */
}
return 0;
@ -481,7 +481,7 @@ scramble(char *to, const char *message, const char *password)
*/
my_bool
check_scramble(const char *scramble_arg, const char *message,
check_scramble(const uchar *scramble_arg, const char *message,
const uint8 *hash_stage2)
{
SHA1_CONTEXT sha1_context;
@ -494,7 +494,7 @@ check_scramble(const char *scramble_arg, const char *message,
mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
mysql_sha1_result(&sha1_context, buf);
/* encrypt scramble */
my_crypt((char *) buf, buf, (const uchar *) scramble_arg, SCRAMBLE_LENGTH);
my_crypt((char *) buf, buf, scramble_arg, SCRAMBLE_LENGTH);
/* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
mysql_sha1_reset(&sha1_context);
mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);

18
sql/protocol.cc

@ -340,24 +340,6 @@ static bool write_eof_packet(THD *thd, NET *net,
return error;
}
/**
Please client to send scrambled_password in old format.
@param thd thread handle
@retval
0 ok
@retval
!0 error
*/
bool send_old_password_request(THD *thd)
{
NET *net= &thd->net;
return my_net_write(net, eof_buff, 1) || net_flush(net);
}
/**
@param thd Thread handler
@param sql_errno The error code to send

1
sql/protocol.h

@ -177,7 +177,6 @@ public:
void send_warning(THD *thd, uint sql_errno, const char *err=0);
bool net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
void net_end_statement(THD *thd);
bool send_old_password_request(THD *thd);
uchar *net_store_data(uchar *to,const uchar *from, size_t length);
uchar *net_store_data(uchar *to,int32 from);
uchar *net_store_data(uchar *to,longlong from);

1993
sql/sql_acl.cc
File diff suppressed because it is too large
View File

54
sql/sql_acl.h

@ -161,53 +161,6 @@ enum mysql_db_table_field
extern const TABLE_FIELD_DEF mysql_db_table_def;
/* Classes */
struct acl_host_and_ip
{
char *hostname;
long ip,ip_mask; // Used with masked ip:s
};
class ACL_ACCESS {
public:
ulong sort;
ulong access;
};
/* ACL_HOST is used if no host is specified */
class ACL_HOST :public ACL_ACCESS
{
public:
acl_host_and_ip host;
char *db;
};
class ACL_USER :public ACL_ACCESS
{
public:
acl_host_and_ip host;
uint hostname_length;
USER_RESOURCES user_resource;
char *user;
uint8 salt[SCRAMBLE_LENGTH+1]; // scrambled password in binary form
uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 3.23, 20 - 4.1.1
enum SSL_type ssl_type;
const char *ssl_cipher, *x509_issuer, *x509_subject;
};
class ACL_DB :public ACL_ACCESS
{
public:
acl_host_and_ip host;
char *user,*db;
};
/* prototypes */
bool hostname_requires_resolving(const char *hostname);
@ -216,10 +169,9 @@ my_bool acl_reload(THD *thd);
void acl_free(bool end=0);
ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern);
int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
uint passwd_len);
bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
char *ip, char *db);
bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len);
bool acl_getroot(Security_context *sctx, char *user, char *host,
char *ip, char *db);
bool acl_check_host(const char *host, const char *ip);
int check_change_password(THD *thd, const char *host, const char *user,
char *password, uint password_len);

4
sql/sql_builtin.cc.in

@ -19,10 +19,10 @@
typedef struct st_mysql_plugin builtin_plugin[];
extern builtin_plugin
builtin_binlog_plugin@mysql_plugin_defs@;
builtin_binlog_plugin, builtin_mysql_password_plugin@mysql_plugin_defs@;
struct st_mysql_plugin *mysqld_builtins[]=
{
builtin_binlog_plugin@mysql_plugin_defs@,(struct st_mysql_plugin *)0
builtin_binlog_plugin, builtin_mysql_password_plugin@mysql_plugin_defs@,(struct st_mysql_plugin *)0
};

20
sql/sql_class.cc

@ -2984,9 +2984,9 @@ void THD::set_status_var_init()
void Security_context::init()
{
host= user= priv_user= ip= 0;
host= user= ip= 0;
host_or_ip= "connecting host";
priv_host[0]= '\0';
priv_user[0]= priv_host[0]= '\0';
master_access= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access= NO_ACCESS;
@ -3010,8 +3010,7 @@ void Security_context::skip_grants()
/* privileges for the user are unknown everything is allowed */
host_or_ip= (char *)"";
master_access= ~NO_ACCESS;
priv_user= (char *)"";
*priv_host= '\0';
*priv_user= *priv_host= '\0';
}
@ -3053,7 +3052,7 @@ bool Security_context::set_user(char *user_arg)
of a statement under credentials of a different user, e.g.
definer of a procedure, we authenticate this user in a local
instance of Security_context by means of this method (and
ultimately by means of acl_getroot_no_password), and make the
ultimately by means of acl_getroot), and make the
local instance active in the thread by re-setting
thd->security_ctx pointer.
@ -3087,19 +3086,12 @@ change_security_context(THD *thd,
DBUG_ASSERT(definer_user->str && definer_host->str);
*backup= NULL;
/*
The current security context may have NULL members
if we have just started the thread and not authenticated
any user. This use case is currently in events worker thread.
*/
needs_change= (thd->security_ctx->priv_user == NULL ||
strcmp(definer_user->str, thd->security_ctx->priv_user) ||
thd->security_ctx->priv_host == NULL ||
needs_change= (strcmp(definer_user->str, thd->security_ctx->priv_user) ||
my_strcasecmp(system_charset_info, definer_host->str,
thd->security_ctx->priv_host));
if (needs_change)
{
if (acl_getroot_no_password(this, definer_user->str, definer_host->str,
if (acl_getroot(this, definer_user->str, definer_host->str,
definer_host->str, db->str))
{
my_error(ER_NO_SUCH_USER, MYF(0), definer_user->str,

3
sql/sql_class.h

@ -805,7 +805,8 @@ public:
priv_user - The user privilege we are using. May be "" for anonymous user.
ip - client IP
*/
char *host, *user, *priv_user, *ip;
char *host, *user, *ip;
char priv_user[USERNAME_LENGTH];
/* The host privilege we are using */
char priv_host[MAX_HOSTNAME];
/* points to host if host is available, otherwise points to ip */

458
sql/sql_connect.cc

@ -27,24 +27,6 @@ extern pthread_mutex_t LOCK_global_user_client_stats;
extern pthread_mutex_t LOCK_global_table_stats;
extern pthread_mutex_t LOCK_global_index_stats;
#ifdef HAVE_OPENSSL
/*
Without SSL the handshake consists of one packet. This packet
has both client capabilites and scrambled password.
With SSL the handshake might consist of two packets. If the first
packet (client capabilities) has CLIENT_SSL flag set, we have to
switch to SSL and read the second packet. The scrambled password
is in the second packet and client_capabilites field will be ignored.
Maybe it is better to accept flags other than CLIENT_SSL from the
second packet?
*/
#define SSL_HANDSHAKE_SIZE 2
#define NORMAL_HANDSHAKE_SIZE 6
#define MIN_HANDSHAKE_SIZE 2
#else
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL */
#ifdef __WIN__
extern void win_install_sigabrt_handler();
#endif
@ -56,9 +38,9 @@ extern void win_install_sigabrt_handler();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
static HASH hash_user_connections;
static int get_or_create_user_conn(THD *thd, const char *user,
const char *host,
USER_RESOURCES *mqh)
int get_or_create_user_conn(THD *thd, const char *user,
const char *host,
USER_RESOURCES *mqh)
{
int return_val= 0;
size_t temp_len, user_len;
@ -124,7 +106,6 @@ end:
1 error
*/
static
int check_for_max_user_connections(THD *thd, USER_CONN *uc)
{
int error=0;
@ -276,240 +257,6 @@ end:
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
/**
Check if user exist and password supplied is correct.
@param thd thread handle, thd->security_ctx->{host,user,ip} are used
@param command originator of the check: now check_user is called
during connect and change user procedures; used for
logging.
@param passwd scrambled password received from client
@param passwd_len length of scrambled password
@param db database name to connect to, may be NULL
@param check_count TRUE if establishing a new connection. In this case
check that we have not exceeded the global
max_connections limist
@note Host, user and passwd may point to communication buffer.
Current implementation does not depend on that, but future changes
should be done with this in mind; 'thd' is INOUT, all other params
are 'IN'.
@retval 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
thd->db are updated; OK is sent to the client.
@retval 1 error, e.g. access denied or handshake error, not sent to
the client. A message is pushed into the error stack.
*/
int
check_user(THD *thd, enum enum_server_command command,
const char *passwd, uint passwd_len, const char *db,
bool check_count)
{
DBUG_ENTER("check_user");
LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
/*
Clear thd->db as it points to something, that will be freed when
connection is closed. We don't want to accidentally free a wrong
pointer if connect failed. Also in case of 'CHANGE USER' failure,
current database will be switched to 'no database selected'.
*/
thd->reset_db(NULL, 0);
#ifdef NO_EMBEDDED_ACCESS_CHECKS
thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
/* Change database if necessary */
if (db && db[0])
{
if (mysql_change_db(thd, &db_str, FALSE))
DBUG_RETURN(1);
}
my_ok(thd);
DBUG_RETURN(0);
#else
my_bool opt_secure_auth_local;
pthread_mutex_lock(&LOCK_global_system_variables);
opt_secure_auth_local= opt_secure_auth;
pthread_mutex_unlock(&LOCK_global_system_variables);
/*
If the server is running in secure auth mode, short scrambles are
forbidden.
*/
if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
{
my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
DBUG_RETURN(1);
}
if (passwd_len != 0 &&
passwd_len != SCRAMBLE_LENGTH &&
passwd_len != SCRAMBLE_LENGTH_323)
{
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
DBUG_RETURN(1);
}
USER_RESOURCES ur;
int res= acl_getroot(thd, &ur, passwd, passwd_len);
#ifndef EMBEDDED_LIBRARY
if (res == -1)
{
/*
This happens when client (new) sends password scrambled with
scramble(), but database holds old value (scrambled with
scramble_323()). Here we please client to send scrambled_password
in old format.
*/
NET *net= &thd->net;
if (opt_secure_auth_local)
{
my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip);
general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip);
DBUG_RETURN(1);
}
/* We have to read very specific packet size */
if (send_old_password_request(thd) ||
my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
{
inc_host_errors(&thd->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
DBUG_RETURN(1);
}
/* Final attempt to check the user based on reply */
/* So as passwd is short, errcode is always >= 0 */
res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
}
#endif /*EMBEDDED_LIBRARY*/
/* here res is always >= 0 */
if (res == 0)
{
if (!(thd->main_security_ctx.master_access &
NO_ACCESS)) // authentication is OK
{
DBUG_PRINT("info",
("Capabilities: %lu packet_length: %ld Host: '%s' "
"Login user: '%s' Priv_user: '%s' Using password: %s "
"Access: %lu db: '%s'",
thd->client_capabilities,
thd->max_client_packet_length,
thd->main_security_ctx.host_or_ip,
thd->main_security_ctx.user,
thd->main_security_ctx.priv_user,
passwd_len ? "yes": "no",
thd->main_security_ctx.master_access,
(thd->db ? thd->db : "*none*")));
if (check_count)
{
bool count_ok= 1;
if (!(thd->main_security_ctx.master_access & SUPER_ACL))
{
pthread_mutex_lock(&LOCK_connection_count);
count_ok= (*thd->scheduler->connection_count <=
*thd->scheduler->max_connections);
VOID(pthread_mutex_unlock(&LOCK_connection_count));
}
if (!count_ok)
{ // too many connections
my_error(ER_CON_COUNT_ERROR, MYF(0));
DBUG_RETURN(1);
}
}
/*
Log the command before authentication checks, so that the user can
check the log for the tried login tried and also to detect
break-in attempts.
*/
general_log_print(thd, command,
(thd->main_security_ctx.priv_user ==
thd->main_security_ctx.user ?
(char*) "%s@%s on %s" :
(char*) "%s@%s as anonymous on %s"),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip,
db ? db : (char*) "");
/*
This is the default access rights for the current database. It's
set to 0 here because we don't have an active database yet (and we
may not have an active database to set.
*/
thd->main_security_ctx.db_access=0;
/* Don't allow user to connect if he has done too many queries */
if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
max_user_connections) &&
get_or_create_user_conn(thd,
(opt_old_style_user_limits ? thd->main_security_ctx.user :
thd->main_security_ctx.priv_user),
(opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
thd->main_security_ctx.priv_host),
&ur))
{
/* The error is set by get_or_create_user_conn(). */
DBUG_RETURN(1);
}
if (thd->user_connect &&
(thd->user_connect->user_resources.conn_per_hour ||
thd->user_connect->user_resources.user_conn ||
max_user_connections) &&
check_for_max_user_connections(thd, thd->user_connect))
{
/* The error is set in check_for_max_user_connections(). */
status_var_increment(denied_connections);
DBUG_RETURN(1);
}
/* Change database if necessary */
if (db && db[0])
{
if (mysql_change_db(thd, &db_str, FALSE))
{
/* mysql_change_db() has pushed the error message. */
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
status_var_increment(thd->status_var.access_denied_errors);
DBUG_RETURN(1);
}
}
my_ok(thd);
thd->net.net_skip_rest_factor= 2; // skip at most 2*max_packet_size
thd->password= test(passwd_len); // remember for error messages
/* Ready to handle queries */
DBUG_RETURN(0);
}
}
else if (res == 2) // client gave short hash, server has long hash
{
my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
DBUG_RETURN(1);
}
my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip,
passwd_len ? ER(ER_YES) : ER(ER_NO));
general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip,
passwd_len ? ER(ER_YES) : ER(ER_NO));
status_var_increment(thd->status_var.access_denied_errors);
DBUG_RETURN(1);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
/*
Check for maximum allowable user connections, if the mysqld server is
started with corresponding variable that is greater then 0.
@ -1088,9 +835,8 @@ bool init_new_connection_handler_thread()
thd thread handle
RETURN
0 success, OK is sent to user, thd is updated.
-1 error, which is sent to user
> 0 error code (not sent to user)
0 success, thd is updated.
1 error
*/
#ifndef EMBEDDED_LIBRARY
@ -1098,8 +844,6 @@ static int check_connection(THD *thd)
{
uint connect_errors= 0;
NET *net= &thd->net;
ulong pkt_len= 0;
char *end;
DBUG_PRINT("info",
("New connection received on %s", vio_description(net->vio)));
@ -1161,200 +905,10 @@ static int check_connection(THD *thd)
}
vio_keepalive(net->vio, TRUE);
ulong server_capabilites;
{
/* buff[] needs to big enough to hold the server_version variable */
char buff[SERVER_VERSION_LENGTH + 1 + SCRAMBLE_LENGTH + 1 + 64];
server_capabilites= CLIENT_BASIC_FLAGS;
if (opt_using_transactions)
server_capabilites|= CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
server_capabilites|= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
#ifdef HAVE_OPENSSL
if (ssl_acceptor_fd)
{
server_capabilites |= CLIENT_SSL; /* Wow, SSL is available! */
server_capabilites |= CLIENT_SSL_VERIFY_SERVER_CERT;
}
#endif /* HAVE_OPENSSL */
end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
int4store((uchar*) end, thd->thread_id);
end+= 4;
/*
So as check_connection is the only entry point to authorization
procedure, scramble is set here. This gives us new scramble for
each handshake.
*/
create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
/*
Old clients does not understand long scrambles, but can ignore packet
tail: that's why first part of the scramble is placed here, and second
part at the end of packet.
*/
end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
int2store(end, server_capabilites);
/* write server characteristics: up to 16 bytes allowed */
end[2]=(char) default_charset_info->number;
int2store(end+3, thd->server_status);
bzero(end+5, 13);
end+= 18;
/* write scramble tail */
end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
/* At this point we write connection message and read reply */
if (net_write_command(net, (uchar) protocol_version, (uchar*) "", 0,
(uchar*) buff, (size_t) (end-buff)) ||
(pkt_len= my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
{
inc_host_errors(&thd->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0),
thd->main_security_ctx.host_or_ip);
return 1;
}
}
#ifdef _CUSTOMCONFIG_
#include "_cust_sql_parse.h"
#endif
if (connect_errors)
reset_host_errors(&thd->remote.sin_addr);
if (thd->packet.alloc(thd->variables.net_buffer_length))
return 1; /* The error is set by alloc(). */
thd->client_capabilities= uint2korr(net->read_pos);
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
thd->max_client_packet_length= uint4korr(net->read_pos+4);
DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
thd_init_client_charset(thd, (uint) net->read_pos[8]);
thd->update_charset();
end= (char*) net->read_pos+32;
}
else
{
thd->max_client_packet_length= uint3korr(net->read_pos+2);
end= (char*) net->read_pos+5;
}
/*
Disable those bits which are not supported by the server.
This is a precautionary measure, if the client lies. See Bug#27944.
*/
thd->client_capabilities&= server_capabilites;
if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
thd->variables.sql_mode|= MODE_IGNORE_SPACE;
#ifdef HAVE_OPENSSL
DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
if (thd->client_capabilities & CLIENT_SSL)
{
char error_string[1024];
/* Do the SSL layering. */
if (!ssl_acceptor_fd)
{
inc_host_errors(&thd->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
DBUG_PRINT("info", ("IO layer change in progress..."));
if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout, error_string))
{
DBUG_PRINT("error", ("Failed to accept new SSL connection"));
inc_host_errors(&thd->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
DBUG_PRINT("info", ("Reading user information over SSL layer"));
if ((pkt_len= my_net_read(net)) == packet_error ||
pkt_len < NORMAL_HANDSHAKE_SIZE)
{
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
pkt_len));
inc_host_errors(&thd->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
}
#endif /* HAVE_OPENSSL */
if (end >= (char*) net->read_pos+ pkt_len +2)
{
inc_host_errors(&thd->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions)
net->return_status= &thd->server_status;
char *user= end;
char *passwd= strend(user)+1;
uint user_len= passwd - user - 1;
char *db= passwd;
char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
uint dummy_errors;
/*
Old clients send null-terminated string as password; new clients send
the size (1 byte) + string (not null-terminated). Hence in case of empty
password both send '\0'.
This strlen() can't be easily deleted without changing protocol.
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
*passwd > 127 and become 2**32-127+ after casting to uint.
*/
uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
(uchar)(*passwd++) : strlen(passwd);
db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
db + passwd_len + 1 : 0;
/* strlen() can't be easily deleted without changing protocol */
uint db_len= db ? strlen(db) : 0;
if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
{
inc_host_errors(&thd->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
/* Since 4.1 all database names are stored in utf8 */
if (db)
{
db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
system_charset_info,
db, db_len,
thd->charset(), &dummy_errors)]= 0;
db= db_buff;
}
user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
system_charset_info, user, user_len,
thd->charset(), &dummy_errors)]= '\0';
user= user_buff;
/* If username starts and ends in "'", chop them off */
if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
{
user[user_len-1]= 0;
user++;
user_len-= 2;
}
if (thd->main_security_ctx.user)
x_free(thd->main_security_ctx.user);
if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME))))
return 1; /* The error is set by my_strdup(). */
return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
return acl_authenticate(thd, connect_errors, 0);
}

4
sql/sql_insert.cc

@ -1778,8 +1778,10 @@ public:
table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
group_count(0)
{
thd.security_ctx->user=thd.security_ctx->priv_user=(char*) delayed_user;
thd.security_ctx->user=(char*) delayed_user;
thd.security_ctx->host=(char*) my_localhost;
strmake(thd.security_ctx->priv_user, thd.security_ctx->user,
USERNAME_LENGTH);
thd.current_tablenr=0;
thd.version=refresh_version;
thd.command=COM_DELAYED_INSERT;

2
sql/sql_lex.h

@ -952,6 +952,8 @@ extern sys_var *trg_new_row_fake_var;
enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE,
XA_SUSPEND, XA_FOR_MIGRATE};
extern const LEX_STRING null_lex_str;
extern const LEX_STRING empty_lex_str;
/*
Class representing list of all tables used by statement.

116
sql/sql_parse.cc

@ -444,9 +444,8 @@ static void handle_bootstrap_impl(THD *thd)
thd_proc_info(thd, 0);
thd->version=refresh_version;
thd->security_ctx->priv_user=
thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
thd->security_ctx->priv_host[0]=0;
thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
thd->security_ctx->priv_user[0]= thd->security_ctx->priv_host[0]=0;
/*
Make the "client" handle multiple results. This is necessary
to enable stored procedures with SELECTs and Dynamic SQL
@ -1093,96 +1092,34 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_CHANGE_USER:
{
status_var_increment(thd->status_var.com_other);
char *user= (char*) packet, *packet_end= packet + packet_length;
/* Safe because there is always a trailing \0 at the end of the packet */
char *passwd= strend(user)+1;
thd->change_user();
thd->clear_error(); // if errors from rollback
/*
Old clients send null-terminated string ('\0' for empty string) for
password. New clients send the size (1 byte) + string (not null
terminated, so also '\0' for empty string).
/* acl_authenticate() takes the data from net->read_pos */
net->read_pos= (uchar*)packet;
Cast *passwd to an unsigned char, so that it doesn't extend the sign
for *passwd > 127 and become 2**32-127 after casting to uint.
*/
char db_buff[NAME_LEN+1]; // buffer to store db in utf8
char *db= passwd;
char *save_db;
/*
If there is no password supplied, the packet must contain '\0',
in any type of handshake (4.1 or pre-4.1).
*/
if (passwd >= packet_end)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
(uchar)(*passwd++) : strlen(passwd));
uint dummy_errors, save_db_length, db_length;
int res;
uint save_db_length= thd->db_length;
char *save_db= thd->db;
USER_CONN *save_user_connect= thd->user_connect;
Security_context save_security_ctx= *thd->security_ctx;
USER_CONN *save_user_connect;
db+= passwd_len + 1;
/*
Database name is always NUL-terminated, so in case of empty database
the packet must contain at least the trailing '\0'.
*/
if (db >= packet_end)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
db_length= strlen(db);
char *ptr= db + db_length + 1;
uint cs_number= 0;
if (ptr < packet_end)
{
if (ptr + 2 > packet_end)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
cs_number= uint2korr(ptr);
}
CHARSET_INFO *save_character_set_client=
thd->variables.character_set_client;
CHARSET_INFO *save_collation_connection=
thd->variables.collation_connection;
CHARSET_INFO *save_character_set_results=
thd->variables.character_set_results;
/* Convert database name to utf8 */
db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
system_charset_info, db, db_length,
thd->charset(), &dummy_errors)]= 0;
db= db_buff;
/* Save user and privileges */
save_db_length= thd->db_length;
save_db= thd->db;
save_user_connect= thd->user_connect;
if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
{
thd->security_ctx->user= save_security_ctx.user;
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
break;
}
/* Clear variables that are allocated */
thd->user_connect= 0;
thd->security_ctx->priv_user= thd->security_ctx->user;
res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
if (res)
if (acl_authenticate(thd, 0, packet_length))
{
x_free(thd->security_ctx->user);
*thd->security_ctx= save_security_ctx;
thd->user_connect= save_user_connect;
thd->db= save_db;
thd->db_length= save_db_length;
thd->reset_db(save_db, save_db_length);
thd->variables.character_set_client= save_character_set_client;
thd->variables.collation_connection= save_collation_connection;
thd->variables.character_set_results= save_character_set_results;
thd->update_charset();
}
else
{
@ -1193,12 +1130,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
x_free(save_db);
x_free(save_security_ctx.user);
if (cs_number)
{
thd_init_client_charset(thd, cs_number);
thd->update_charset();
}
}
break;
}
@ -4348,8 +4279,8 @@ end_with_restore_list:
if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
lex->sql_command == SQLCOM_CREATE_PROCEDURE))
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_PROC_AUTO_GRANT_FAIL,
ER(ER_PROC_AUTO_GRANT_FAIL));
ER_PROC_AUTO_GRANT_FAIL, ER(ER_PROC_AUTO_GRANT_FAIL));
thd->clear_error();
}
/*
@ -7727,8 +7658,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;
definer->password= null_lex_str;
definer->plugin= empty_lex_str;
definer->auth= empty_lex_str;
}

23
sql/sql_plugin.cc

@ -16,6 +16,7 @@
#include "mysql_priv.h"
#include <my_pthread.h>
#include <my_getopt.h>
#include <mysql/plugin_auth.h>
#define REPORT_TO_LOG 1
#define REPORT_TO_USER 2
@ -46,7 +47,10 @@ const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{ C_STRING_WITH_LEN("STORAGE ENGINE") },
{ C_STRING_WITH_LEN("FTPARSER") },
{ C_STRING_WITH_LEN("DAEMON") },
{ C_STRING_WITH_LEN("INFORMATION SCHEMA") }
{ C_STRING_WITH_LEN("INFORMATION SCHEMA") },
{ C_STRING_WITH_LEN("AUDIT") },
{ C_STRING_WITH_LEN("REPLICATION") },
{ C_STRING_WITH_LEN("AUTHENTICATION") }
};
extern int initialize_schema_table(st_plugin_int *plugin);
@ -59,12 +63,12 @@ extern int finalize_schema_table(st_plugin_int *plugin);
*/
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0,ha_initialize_handlerton,0,0,initialize_schema_table
0,ha_initialize_handlerton,0,0,initialize_schema_table, 0, 0, 0
};
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0,ha_finalize_handlerton,0,0,finalize_schema_table
0,ha_finalize_handlerton,0,0,finalize_schema_table, 0, 0, 0
};
#ifdef HAVE_DLOPEN
@ -85,7 +89,10 @@ static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
MYSQL_DAEMON_INTERFACE_VERSION,
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
0xff00, /* audit plugins are supported in a later versions */
0xff00, /* replication plugins are supported in a later versions */
MYSQL_AUTHENTICATION_INTERFACE_VERSION
};
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
@ -93,7 +100,10 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
MYSQL_DAEMON_INTERFACE_VERSION,
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
0x0000, /* audit plugins are supported in a later versions */
0x0000, /* replication plugins are supported in a later versions */
MYSQL_AUTHENTICATION_INTERFACE_VERSION
};
/* support for Services */
@ -1013,6 +1023,9 @@ void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
{
LEX *lex= thd ? thd->lex : 0;
DBUG_ENTER("plugin_unlock_list");
if (count == 0)
DBUG_VOID_RETURN;
DBUG_ASSERT(list);
pthread_mutex_lock(&LOCK_plugin);
while (count--)

22
sql/sql_yacc.yy

@ -56,6 +56,7 @@
int yylex(void *yylval, void *yythd);
const LEX_STRING null_lex_str= {0,0};
const LEX_STRING empty_lex_str= { (char*) "", 0 };
#define yyoverflow(A,B,C,D,E,F) \
{ \
@ -1260,8 +1261,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token VARIANCE_SYM
%token VARYING /* SQL-2003-R */
%token VAR_SAMP_SYM
%token VIRTUAL_SYM
%token VIA_SYM
%token VIEW_SYM /* SQL-2003-N */
%token VIRTUAL_SYM
%token WAIT_SYM
%token WARNINGS
%token WEEK_SYM
@ -11673,6 +11675,9 @@ user:
$$->user = $1;
$$->host.str= (char *) "%";
$$->host.length= 1;
$$->password= null_lex_str;
$$->plugin= empty_lex_str;
$$->auth= empty_lex_str;
if (check_string_char_length(&$$->user, ER(ER_USERNAME),
USERNAME_CHAR_LENGTH,
@ -11685,6 +11690,9 @@ user:
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
MYSQL_YYABORT;
$$->user = $1; $$->host=$3;
$$->password= null_lex_str;
$$->plugin= empty_lex_str;
$$->auth= empty_lex_str;
if (check_string_char_length(&$$->user, ER(ER_USERNAME),
USERNAME_CHAR_LENGTH,
@ -12941,6 +12949,18 @@ grant_user:
}
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
{ $$= $1; $1->password= $5; }
| user IDENTIFIED_SYM VIA_SYM ident_or_text
{
$$= $1;
$1->plugin= $4;
$1->auth= empty_lex_str;
}
| user IDENTIFIED_SYM VIA_SYM ident_or_text USING TEXT_STRING_sys
{
$$= $1;
$1->plugin= $4;
$1->auth= $6;
}
| user
{ $$= $1; $1->password= null_lex_str; }
;

2
sql/structs.h

@ -178,7 +178,7 @@ extern const char *show_comp_option_name[];
typedef int *(*update_var)(THD *, struct st_mysql_show_var *);
typedef struct st_lex_user {
LEX_STRING user, host, password;
LEX_STRING user, host, password, plugin, auth;
} LEX_USER;
/*

7
sql/table.cc

@ -4163,11 +4163,8 @@ bool TABLE_LIST::prepare_view_securety_context(THD *thd)
{
DBUG_PRINT("info", ("This table is suid view => load contest"));
DBUG_ASSERT(view && view_sctx);
if (acl_getroot_no_password(view_sctx,
definer.user.str,
definer.host.str,
definer.host.str,
thd->db))
if (acl_getroot(view_sctx, definer.user.str, definer.host.str,
definer.host.str, thd->db))
{
if ((thd->lex->sql_command == SQLCOM_SHOW_CREATE) ||
(thd->lex->sql_command == SQLCOM_SHOW_FIELDS))

1
tests/mysql_client_test.c

@ -34,6 +34,7 @@
#include <m_string.h>
#include <mysqld_error.h>
#include <my_handler.h>
#include <sql_common.h>
#define VER "2.1"
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */

Loading…
Cancel
Save