diff options
Diffstat (limited to 'plugin')
44 files changed, 1040 insertions, 601 deletions
diff --git a/plugin/auth_ed25519/CMakeLists.txt b/plugin/auth_ed25519/CMakeLists.txt index 1a3d5cc4bce..1033dc053c8 100644 --- a/plugin/auth_ed25519/CMakeLists.txt +++ b/plugin/auth_ed25519/CMakeLists.txt @@ -19,6 +19,10 @@ IF(MSVC) SET_SOURCE_FILES_PROPERTIES(${REF10_SOURCES} PROPERTY COMPILE_FLAGS "/wd4244 /wd4146") ENDIF() +IF(CMAKE_C_COMPILER_ID MATCHES "GNU" AND CMAKE_C_COMPILER_VERSION LESS 11 AND CMAKE_C_COMPILER_VERSION GREATER 6) + SET_SOURCE_FILES_PROPERTIES(${REF10_SOURCES} PROPERTY COMPILE_FLAGS -fno-sanitize=shift) +ENDIF() + # server plugin *cannot* link with the library, it needs all sources to be # compiled with MYSQL_DYNAMIC_PLUGIN MYSQL_ADD_PLUGIN(auth_ed25519 server_ed25519.c ${REF10_SOURCES} MODULE_ONLY) diff --git a/plugin/auth_ed25519/server_ed25519.c b/plugin/auth_ed25519/server_ed25519.c index e9678450042..b789bd34ca4 100644 --- a/plugin/auth_ed25519/server_ed25519.c +++ b/plugin/auth_ed25519/server_ed25519.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2017, MariaDB + Copyright (c) 2017, 2021, MariaDB 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 @@ -15,6 +15,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <mysql/plugin_auth.h> +#include <mysqld_error.h> #include "common.h" #if !defined(__attribute__) && !defined(__GNUC__) @@ -36,16 +37,6 @@ static int auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) int pkt_len; unsigned long nonce[CRYPTO_LONGS + NONCE_LONGS]; unsigned char *pkt, *reply= (unsigned char*)nonce; - unsigned char pk[PASSWORD_LEN_BUF/4*3]; - char pw[PASSWORD_LEN_BUF]; - - /* prepare the pk */ - if (info->auth_string_length != PASSWORD_LEN) - return CR_ERROR; // bad password in the user table - memcpy(pw, info->auth_string, PASSWORD_LEN); - pw[PASSWORD_LEN]= '='; - if (my_base64_decode(pw, PASSWORD_LEN_BUF, pk, NULL, 0) != CRYPTO_PUBLICKEYBYTES) - return CR_ERROR; // bad password in the user table info->password_used= PASSWORD_USED_YES; @@ -62,17 +53,52 @@ static int auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) return CR_AUTH_HANDSHAKE; memcpy(reply, pkt, CRYPTO_BYTES); - if (crypto_sign_open(reply, CRYPTO_BYTES + NONCE_BYTES, pk)) + if (crypto_sign_open(reply, CRYPTO_BYTES + NONCE_BYTES, + (unsigned char*)info->auth_string)) return CR_AUTH_USER_CREDENTIALS; // wrong password provided by the user return CR_OK; } +static int compute_password_digest(const char *pw, size_t pwlen, + char *d, size_t *dlen) +{ + unsigned char pk[CRYPTO_PUBLICKEYBYTES]; + if (*dlen < PASSWORD_LEN || pwlen == 0) + return 1; + *dlen= PASSWORD_LEN; + crypto_sign_keypair(pk, (unsigned char*)pw, pwlen); + my_base64_encode(pk, CRYPTO_PUBLICKEYBYTES, d); + return 0; +} + +static int digest_to_binary(const char *d, size_t dlen, + unsigned char *b, size_t *blen) +{ + char pw[PASSWORD_LEN_BUF]; + + if (*blen < CRYPTO_PUBLICKEYBYTES || dlen != PASSWORD_LEN) + { + my_printf_error(ER_PASSWD_LENGTH, "Password hash should be %d characters long", 0, PASSWORD_LEN); + return 1; + } + + *blen= CRYPTO_PUBLICKEYBYTES; + memcpy(pw, d, PASSWORD_LEN); + pw[PASSWORD_LEN]= '='; + if (my_base64_decode(pw, PASSWORD_LEN_BUF, b, 0, 0) == CRYPTO_PUBLICKEYBYTES) + return 0; + my_printf_error(ER_PASSWD_LENGTH, "Password hash should be base64 encoded", 0); + return 1; +} + static struct st_mysql_auth info = { MYSQL_AUTHENTICATION_INTERFACE_VERSION, "client_ed25519", - auth + auth, + compute_password_digest, + digest_to_binary }; static int init(void *p __attribute__((unused))) @@ -97,10 +123,10 @@ maria_declare_plugin(ed25519) PLUGIN_LICENSE_GPL, init, deinit, - 0x0100, + 0x0101, NULL, NULL, - "1.0", + "1.1", MariaDB_PLUGIN_MATURITY_STABLE } maria_declare_plugin_end; diff --git a/plugin/auth_examples/dialog_examples.c b/plugin/auth_examples/dialog_examples.c index 096dc3fca08..834c028ce84 100644 --- a/plugin/auth_examples/dialog_examples.c +++ b/plugin/auth_examples/dialog_examples.c @@ -81,7 +81,8 @@ static struct st_mysql_auth two_handler= { MYSQL_AUTHENTICATION_INTERFACE_VERSION, "dialog", /* requires dialog client plugin */ - two_questions + two_questions, + NULL, NULL /* no PASSWORD() */ }; /* dialog demo where the number of questions is not known in advance */ @@ -118,7 +119,8 @@ static struct st_mysql_auth three_handler= { MYSQL_AUTHENTICATION_INTERFACE_VERSION, "dialog", /* requires dialog client plugin */ - three_attempts + three_attempts, + NULL, NULL /* no PASSWORD() */ }; mysql_declare_plugin(dialog) diff --git a/plugin/auth_examples/qa_auth_interface.c b/plugin/auth_examples/qa_auth_interface.c index a6a7b8456b6..ad1f6fff1b6 100644 --- a/plugin/auth_examples/qa_auth_interface.c +++ b/plugin/auth_examples/qa_auth_interface.c @@ -136,7 +136,8 @@ static struct st_mysql_auth qa_auth_test_handler= { MYSQL_AUTHENTICATION_INTERFACE_VERSION, "qa_auth_interface", /* requires test_plugin client's plugin */ - qa_auth_interface + qa_auth_interface, + NULL, NULL /* no PASSWORD() */ }; mysql_declare_plugin(test_plugin) diff --git a/plugin/auth_examples/qa_auth_server.c b/plugin/auth_examples/qa_auth_server.c index ff4d957a0a8..67b29d26ee8 100644 --- a/plugin/auth_examples/qa_auth_server.c +++ b/plugin/auth_examples/qa_auth_server.c @@ -56,7 +56,8 @@ static struct st_mysql_auth qa_auth_test_handler= { MYSQL_AUTHENTICATION_INTERFACE_VERSION, "qa_auth_interface", /* requires test_plugin client's plugin */ - qa_auth_interface + qa_auth_interface, + NULL, NULL /* no PASSWORD() */ }; mysql_declare_plugin(test_plugin) diff --git a/plugin/auth_examples/test_plugin.c b/plugin/auth_examples/test_plugin.c index 4e3ebf74112..04405a1ccb6 100644 --- a/plugin/auth_examples/test_plugin.c +++ b/plugin/auth_examples/test_plugin.c @@ -69,7 +69,8 @@ static struct st_mysql_auth auth_test_handler= { MYSQL_AUTHENTICATION_INTERFACE_VERSION, "auth_test_plugin", /* requires test_plugin client's plugin */ - auth_test_plugin + auth_test_plugin, + NULL, NULL /* no PASSWORD() */ }; /** @@ -99,7 +100,8 @@ static struct st_mysql_auth auth_cleartext_handler= { MYSQL_AUTHENTICATION_INTERFACE_VERSION, "mysql_clear_password", /* requires the clear text plugin */ - auth_cleartext_plugin + auth_cleartext_plugin, + NULL, NULL /* no PASSWORD() */ }; mysql_declare_plugin(test_plugin) diff --git a/plugin/auth_gssapi/CMakeLists.txt b/plugin/auth_gssapi/CMakeLists.txt index 1110562d9f1..3ac89404302 100644 --- a/plugin/auth_gssapi/CMakeLists.txt +++ b/plugin/auth_gssapi/CMakeLists.txt @@ -25,7 +25,7 @@ ELSE() SET(GSSAPI_SERVER gssapi_server.cc) SET(GSSAPI_ERRMSG gssapi_errmsg.cc) - IF(APPLE) + IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") SET_SOURCE_FILES_PROPERTIES( ${GSSAPI_CLIENT} ${GSSAPI_SERVER} ${GSSAPI_ERRMSG} PROPERTY COMPILE_FLAGS "-Wno-deprecated-declarations") diff --git a/plugin/auth_gssapi/gssapi_server.cc b/plugin/auth_gssapi/gssapi_server.cc index 6a1363854ae..1d3cbb7a130 100644 --- a/plugin/auth_gssapi/gssapi_server.cc +++ b/plugin/auth_gssapi/gssapi_server.cc @@ -145,7 +145,7 @@ int plugin_deinit() } -int auth_server(MYSQL_PLUGIN_VIO *vio,const char *user, size_t userlen, int use_full_name) +int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info) { int rc= CR_ERROR; /* return code */ @@ -157,6 +157,9 @@ int auth_server(MYSQL_PLUGIN_VIO *vio,const char *user, size_t userlen, int use_ gss_name_t client_name; gss_buffer_desc client_name_buf, input, output; char *client_name_str; + const char *user= 0; + size_t userlen; + int use_full_name; /* server acquires credential */ major= gss_acquire_cred(&minor, service_name, GSS_C_INDEFINITE, @@ -180,6 +183,21 @@ int auth_server(MYSQL_PLUGIN_VIO *vio,const char *user, size_t userlen, int use_ log_error(0, 0, "fail to read token from client"); goto cleanup; } + if (!user) + { + if (auth_info->auth_string_length > 0) + { + use_full_name= 1; + user= auth_info->auth_string; + userlen= auth_info->auth_string_length; + } + else + { + use_full_name= 0; + user= auth_info->user_name; + userlen= auth_info->user_name_length; + } + } input.length= len; major= gss_accept_sec_context(&minor, &ctxt, cred, &input, diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.result b/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.result new file mode 100644 index 00000000000..c65eb7a8634 --- /dev/null +++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.result @@ -0,0 +1,34 @@ +INSTALL SONAME 'auth_gssapi'; +Warnings: +Note 1105 SSPI: using principal name 'localhost', mech 'Negotiate' +CREATE USER 'nosuchuser' IDENTIFIED WITH gssapi OR mysql_native_password as password("good"); +connect(localhost,nosuchuser,,test,MASTER_MYPORT,MASTER_MYSOCK); +connect con1,localhost,nosuchuser,,; +ERROR 28000: Access denied for user 'nosuchuser'@'localhost' (using password: NO) +connect con1,localhost,nosuchuser,good,; +SELECT USER(),CURRENT_USER(); +USER() CURRENT_USER() +nosuchuser@localhost nosuchuser@% +disconnect con1; +connection default; +DROP USER nosuchuser; +CREATE USER 'nosuchuser' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi; +connect(localhost,nosuchuser,,test,MASTER_MYPORT,MASTER_MYSOCK); +connect con1,localhost,nosuchuser,,; +ERROR 28000: GSSAPI name mismatch, requested 'nosuchuser', actual name 'GSSAPI_SHORTNAME' +connect con1,localhost,nosuchuser,good,; +SELECT USER(),CURRENT_USER(); +USER() CURRENT_USER() +nosuchuser@localhost nosuchuser@% +disconnect con1; +connection default; +DROP USER nosuchuser; +CREATE USER 'GSSAPI_SHORTNAME' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi; +connect con1,localhost,$GSSAPI_SHORTNAME,,; +SELECT USER(),CURRENT_USER(); +USER() CURRENT_USER() +GSSAPI_SHORTNAME@localhost GSSAPI_SHORTNAME@% +disconnect con1; +connection default; +DROP USER 'GSSAPI_SHORTNAME'; +UNINSTALL SONAME 'auth_gssapi'; diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.test b/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.test new file mode 100644 index 00000000000..10e1e80907e --- /dev/null +++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.test @@ -0,0 +1,36 @@ +--replace_regex /name '[^']+'/name 'localhost'/ +INSTALL SONAME 'auth_gssapi'; + +# gssapi,password +CREATE USER 'nosuchuser' IDENTIFIED WITH gssapi OR mysql_native_password as password("good"); +replace_result $MASTER_MYSOCK MASTER_MYSOCK $MASTER_MYPORT MASTER_MYPORT; +error ER_ACCESS_DENIED_ERROR; +connect (con1,localhost,nosuchuser,,); +connect (con1,localhost,nosuchuser,good,); +SELECT USER(),CURRENT_USER(); +disconnect con1; +connection default; +DROP USER nosuchuser; + +# password,gssapi +CREATE USER 'nosuchuser' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi; +replace_result $MASTER_MYSOCK MASTER_MYSOCK $MASTER_MYPORT MASTER_MYPORT $GSSAPI_SHORTNAME GSSAPI_SHORTNAME; +error ER_ACCESS_DENIED_ERROR; +connect (con1,localhost,nosuchuser,,); +connect (con1,localhost,nosuchuser,good,); +SELECT USER(),CURRENT_USER(); +disconnect con1; +connection default; +DROP USER nosuchuser; + +replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME; +eval CREATE USER '$GSSAPI_SHORTNAME' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi; +connect (con1,localhost,$GSSAPI_SHORTNAME,,); +replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME; +SELECT USER(),CURRENT_USER(); +disconnect con1; +connection default; +replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME; +eval DROP USER '$GSSAPI_SHORTNAME'; + +UNINSTALL SONAME 'auth_gssapi'; diff --git a/plugin/auth_gssapi/server_plugin.cc b/plugin/auth_gssapi/server_plugin.cc index 5db86cffbe4..bce6a812d12 100644 --- a/plugin/auth_gssapi/server_plugin.cc +++ b/plugin/auth_gssapi/server_plugin.cc @@ -64,41 +64,11 @@ unsigned long srv_mech; */ static int gssapi_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info) { - int use_full_name; - const char *user; - int user_len; - - /* No user name yet ? Read the client handshake packet with the user name. */ - if (auth_info->user_name == 0) - { - unsigned char *pkt; - if (vio->read_packet(vio, &pkt) < 0) - return CR_ERROR; - } - /* Send first packet with target name and mech name */ if (vio->write_packet(vio, (unsigned char *)first_packet, first_packet_len)) - { return CR_ERROR; - } - - /* Figure out whether to use full name (as given in IDENTIFIED AS clause) - * or just short username auth_string - */ - if (auth_info->auth_string_length > 0) - { - use_full_name= 1; - user= auth_info->auth_string; - user_len= auth_info->auth_string_length; - } - else - { - use_full_name= 0; - user= auth_info->user_name; - user_len= auth_info->user_name_length; - } - - return auth_server(vio, user, user_len, use_full_name); + + return auth_server(vio, auth_info); } static int initialize_plugin(void *unused) @@ -169,7 +139,7 @@ static struct st_mysql_sys_var *system_variables[]= { static struct st_mysql_auth server_handler= { MYSQL_AUTHENTICATION_INTERFACE_VERSION, "auth_gssapi_client", - gssapi_auth + gssapi_auth, NULL, NULL }; maria_declare_plugin(gssapi_server) diff --git a/plugin/auth_gssapi/server_plugin.h b/plugin/auth_gssapi/server_plugin.h index 6284a319d03..84552d3a263 100644 --- a/plugin/auth_gssapi/server_plugin.h +++ b/plugin/auth_gssapi/server_plugin.h @@ -48,4 +48,4 @@ extern char *srv_keytab_path; int plugin_init(); int plugin_deinit(); -int auth_server(MYSQL_PLUGIN_VIO *vio, const char *username, size_t username_len, int use_full_name); +int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info); diff --git a/plugin/auth_gssapi/sspi_server.cc b/plugin/auth_gssapi/sspi_server.cc index af78829df6e..44aa5051472 100644 --- a/plugin/auth_gssapi/sspi_server.cc +++ b/plugin/auth_gssapi/sspi_server.cc @@ -140,7 +140,7 @@ static int get_client_name_from_context(CtxtHandle *ctxt, } -int auth_server(MYSQL_PLUGIN_VIO *vio, const char *user, size_t user_len, int compare_full_name) +int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info) { int ret; SECURITY_STATUS sspi_ret; @@ -155,6 +155,8 @@ int auth_server(MYSQL_PLUGIN_VIO *vio, const char *user, size_t user_len, int co SecBuffer outbuf; void* out= NULL; char client_name[MYSQL_USERNAME_LENGTH + 1]; + const char *user= 0; + int compare_full_name; ret= CR_ERROR; SecInvalidateHandle(&cred); @@ -207,6 +209,19 @@ int auth_server(MYSQL_PLUGIN_VIO *vio, const char *user, size_t user_len, int co log_error(SEC_E_OK, "communication error(read)"); goto cleanup; } + if (!user) + { + if (auth_info->auth_string_length > 0) + { + compare_full_name= 1; + user= auth_info->auth_string; + } + else + { + compare_full_name= 0; + user= auth_info->user_name; + } + } inbuf.cbBuffer= len; outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE; sspi_ret= AcceptSecurityContext( diff --git a/plugin/auth_pam/CMakeLists.txt b/plugin/auth_pam/CMakeLists.txt index 9fc5a1e3746..6d2dc72b097 100644 --- a/plugin/auth_pam/CMakeLists.txt +++ b/plugin/auth_pam/CMakeLists.txt @@ -36,16 +36,26 @@ SET(CMAKE_REQUIRED_LIBRARIES) IF(HAVE_PAM_APPL_H AND HAVE_GETGROUPLIST) FIND_LIBRARY(PAM_LIBRARY pam) # for srpm build-depends detection - MYSQL_ADD_PLUGIN(auth_pam auth_pam.c LINK_LIBRARIES pam MODULE_ONLY) - - IF(TARGET auth_pam) + ADD_DEFINITIONS(-D_GNU_SOURCE) + MYSQL_ADD_PLUGIN(auth_pam_v1 auth_pam_v1.c LINK_LIBRARIES pam MODULE_ONLY) + MYSQL_ADD_PLUGIN(auth_pam auth_pam.c LINK_LIBRARIES pam ${CMAKE_DL_LIBS} MODULE_ONLY) + IF (TARGET auth_pam) + MYSQL_ADD_EXECUTABLE(auth_pam_tool auth_pam_tool.c DESTINATION ${INSTALL_PLUGINDIR}/auth_pam_tool_dir COMPONENT Server) + TARGET_LINK_LIBRARIES(auth_pam_tool pam) + SET(CPACK_RPM_server_USER_FILELIST ${CPACK_RPM_server_USER_FILELIST} + "%attr(700,-,-) ${INSTALL_PLUGINDIRABS}/auth_pam_tool_dir" + "%attr(4755,-,-) ${INSTALL_PLUGINDIRABS}/auth_pam_tool_dir/auth_pam_tool") + SET(CPACK_RPM_server_USER_FILELIST ${CPACK_RPM_server_USER_FILELIST} PARENT_SCOPE) + ENDIF() + IF(TARGET auth_pam OR TARGET auth_pam_v1) + ADD_SUBDIRECTORY(testing) ADD_LIBRARY(pam_user_map MODULE mapper/pam_user_map.c) TARGET_LINK_LIBRARIES(pam_user_map pam) SET_TARGET_PROPERTIES (pam_user_map PROPERTIES PREFIX "") IF(INSTALL_PAMDIR) INSTALL(TARGETS pam_user_map DESTINATION ${INSTALL_PAMDIR} COMPONENT Server) INSTALL(FILES mapper/user_map.conf DESTINATION ${INSTALL_PAMDATADIR} COMPONENT Server) - SET(CPACK_RPM_server_USER_FILELIST ${CPACK_RPM_server_USER_FILELIST} "%config(noreplace) ${INSTALL_PAMDATADIR}/*" PARENT_SCOPE) + SET(CPACK_RPM_server_USER_FILELIST ${CPACK_RPM_server_USER_FILELIST} "%config(noreplace) ${INSTALL_PAMDATADIRABS}/*" PARENT_SCOPE) ENDIF() ENDIF() ENDIF() diff --git a/plugin/auth_pam/auth_pam.c b/plugin/auth_pam/auth_pam.c index c80ec51b48d..d232b3b5c65 100644 --- a/plugin/auth_pam/auth_pam.c +++ b/plugin/auth_pam/auth_pam.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2011, 2019, MariaDB Corporation. + Copyright (c) 2011, 2020, MariaDB Corporation. 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 @@ -12,39 +12,18 @@ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#define _GNU_SOURCE 1 /* for strndup */ #include <config_auth_pam.h> -#include <mysql/plugin_auth.h> -#include <stdio.h> +#include <unistd.h> #include <string.h> -#include <security/pam_appl.h> -#include <security/pam_modules.h> - -struct param { - unsigned char buf[10240], *ptr; - MYSQL_PLUGIN_VIO *vio; -}; - -/* It least solaris doesn't have strndup */ - -#ifndef HAVE_STRNDUP -char *strndup(const char *from, size_t length) -{ - char *ptr; - size_t max_length= strlen(from); - if (length > max_length) - length= max_length; - if ((ptr= (char*) malloc(length+1)) != 0) - { - memcpy((char*) ptr, (char*) from, length); - ptr[length]=0; - } - return ptr; -} -#endif +#include <sys/types.h> +#include <sys/wait.h> +#include <spawn.h> +#include <mysql/plugin_auth.h> +#include "auth_pam_tool.h" +#include <my_global.h> #ifndef DBUG_OFF static char pam_debug = 0; @@ -55,164 +34,191 @@ static char pam_debug = 0; static char winbind_hack = 0; -static int conv(int n, const struct pam_message **msg, - struct pam_response **resp, void *data) +static char *opt_plugin_dir; /* To be dynamically linked. */ +static const char *tool_name= "auth_pam_tool_dir/auth_pam_tool"; +static const int tool_name_len= 31; + +/* + sleep_limit is now 5 meaning up to 1 second sleep. + each step means 10 times longer sleep, so 6 would mean 10 seconds. +*/ +static const unsigned int sleep_limit= 5; + +static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) { - struct param *param = (struct param *)data; - unsigned char *end = param->buf + sizeof(param->buf) - 1; - int i; + int p_to_c[2], c_to_p[2]; /* Parent-to-child and child-to-parent pipes. */ + pid_t proc_id; + int result= CR_ERROR, pkt_len= 0; + unsigned char field, *pkt; + unsigned int n_sleep= 0; + useconds_t sleep_time= 100; + posix_spawn_file_actions_t file_actions; + char toolpath[FN_REFLEN]; + size_t plugin_dir_len= strlen(opt_plugin_dir); + char *const argv[2]= {toolpath, 0}; + int res; + + PAM_DEBUG((stderr, "PAM: opening pipes.\n")); + if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0) + { + my_printf_error(ENOEXEC, "pam: cannot create pipes (errno: %M)", + ME_ERROR_LOG_ONLY, errno); + return CR_ERROR; + } + + if (plugin_dir_len + tool_name_len + 2 > sizeof(toolpath)) + { + my_printf_error(ENOEXEC, "pam: too long path to <plugindir>/%s", + ME_ERROR_LOG_ONLY, tool_name); + return CR_ERROR; + } + + memcpy(toolpath, opt_plugin_dir, plugin_dir_len); + if (plugin_dir_len && toolpath[plugin_dir_len-1] != FN_LIBCHAR) + toolpath[plugin_dir_len++]= FN_LIBCHAR; + memcpy(toolpath+plugin_dir_len, tool_name, tool_name_len+1); + + PAM_DEBUG((stderr, "PAM: forking %s\n", toolpath)); + res= posix_spawn_file_actions_init(&file_actions) || + posix_spawn_file_actions_addclose(&file_actions, p_to_c[1]) || + posix_spawn_file_actions_addclose(&file_actions, c_to_p[0]) || + posix_spawn_file_actions_adddup2(&file_actions, p_to_c[0], 0) || + posix_spawn_file_actions_adddup2(&file_actions, c_to_p[1], 1) || + posix_spawn(&proc_id, toolpath, &file_actions, NULL, argv, NULL); + + /* Parent process continues. */ + posix_spawn_file_actions_destroy(&file_actions); + close(p_to_c[0]); + close(c_to_p[1]); + + if (res) + { + my_printf_error(ENOEXEC, "pam: cannot exec %s (errno: %M)", + ME_ERROR_LOG_ONLY, toolpath, errno); + goto error_ret; + } + + /* no user name yet ? read the client handshake packet with the user name */ + if (info->user_name == 0) + { + if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) + goto error_ret; + } + else + pkt= NULL; + + PAM_DEBUG((stderr, "PAM: parent sends user data [%s], [%s].\n", + info->user_name, info->auth_string)); + +#ifndef DBUG_OFF + field= pam_debug ? 1 : 0; +#else + field= 0; +#endif + field|= winbind_hack ? 2 : 0; - *resp = 0; + if (write(p_to_c[1], &field, 1) != 1 || + write_string(p_to_c[1], (const uchar *) info->user_name, + info->user_name_length) || + write_string(p_to_c[1], (const uchar *) info->auth_string, + info->auth_string_length)) + goto error_ret; - for (i = 0; i < n; i++) + for (;;) { - /* if there's a message - append it to the buffer */ - if (msg[i]->msg) + PAM_DEBUG((stderr, "PAM: listening to the sandbox.\n")); + if (read(c_to_p[0], &field, 1) < 1) { - int len = strlen(msg[i]->msg); - if (len > end - param->ptr) - len = end - param->ptr; - if (len > 0) - { - memcpy(param->ptr, msg[i]->msg, len); - param->ptr+= len; - *(param->ptr)++ = '\n'; - } + PAM_DEBUG((stderr, "PAM: read failed.\n")); + goto error_ret; } - /* if the message style is *_PROMPT_*, meaning PAM asks a question, - send the accumulated text to the client, read the reply */ - if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || - msg[i]->msg_style == PAM_PROMPT_ECHO_ON) + + if (field == AP_EOF) { - int pkt_len; - unsigned char *pkt; + PAM_DEBUG((stderr, "PAM: auth OK returned.\n")); + break; + } - /* allocate the response array. - freeing it is the responsibility of the caller */ - if (*resp == 0) + switch (field) + { + case AP_AUTHENTICATED_AS: + PAM_DEBUG((stderr, "PAM: reading authenticated_as string.\n")); + if (read_string(c_to_p[0], info->authenticated_as, + sizeof(info->authenticated_as) - 1) < 0) + goto error_ret; + break; + + case AP_CONV: { - *resp = calloc(sizeof(struct pam_response), n); - if (*resp == 0) - return PAM_BUF_ERR; - } + unsigned char buf[10240]; + int buf_len; - /* dialog plugin interprets the first byte of the packet - as the magic number. - 2 means "read the input with the echo enabled" - 4 means "password-like input, echo disabled" - C'est la vie. */ - param->buf[0] = msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? 2 : 4; - PAM_DEBUG((stderr, "PAM: conv: send(%.*s)\n", (int)(param->ptr - param->buf - 1), param->buf)); - if (param->vio->write_packet(param->vio, param->buf, param->ptr - param->buf - 1)) - return PAM_CONV_ERR; - - pkt_len = param->vio->read_packet(param->vio, &pkt); - if (pkt_len < 0) - { - PAM_DEBUG((stderr, "PAM: conv: recv() ERROR\n")); - return PAM_CONV_ERR; + PAM_DEBUG((stderr, "PAM: getting CONV string.\n")); + if ((buf_len= read_string(c_to_p[0], (char *) buf, sizeof(buf))) < 0) + goto error_ret; + + if (!pkt || !*pkt || (buf[0] >> 1) != 2) + { + PAM_DEBUG((stderr, "PAM: sending CONV string.\n")); + if (vio->write_packet(vio, buf, buf_len)) + goto error_ret; + + PAM_DEBUG((stderr, "PAM: reading CONV answer.\n")); + if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) + goto error_ret; + } + + PAM_DEBUG((stderr, "PAM: answering CONV.\n")); + if (write_string(p_to_c[1], pkt, pkt_len)) + goto error_ret; + + pkt= NULL; } - PAM_DEBUG((stderr, "PAM: conv: recv(%.*s)\n", pkt_len, pkt)); - /* allocate and copy the reply to the response array */ - if (!((*resp)[i].resp= strndup((char*) pkt, pkt_len))) - return PAM_CONV_ERR; - param->ptr = param->buf + 1; + break; + + default: + PAM_DEBUG((stderr, "PAM: unknown sandbox field.\n")); + goto error_ret; } } - return PAM_SUCCESS; -} - -#define DO(X) if ((status = (X)) != PAM_SUCCESS) goto end + result= CR_OK; -#if defined(SOLARIS) || defined(__sun) -typedef void** pam_get_item_3_arg; -#else -typedef const void** pam_get_item_3_arg; -#endif +error_ret: + close(p_to_c[1]); + close(c_to_p[0]); + while (waitpid(proc_id, NULL, WNOHANG) != (int) proc_id) + { + if (n_sleep++ == sleep_limit) + { + /* + The auth_pam_tool application doesn't terminate. + Means something wrong happened there like pam_xxx.so hanged. + */ + kill(proc_id, SIGKILL); + sleep_time= 1000000; /* 1 second wait should be enough. */ + PAM_DEBUG((stderr, "PAM: auth_pam_tool doesn't terminate," + " have to kill it.\n")); + } + else if (n_sleep > sleep_limit) + break; + usleep(sleep_time); + sleep_time*= 10; + } -static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) -{ - pam_handle_t *pamh = NULL; - int status; - const char *new_username= NULL; - struct param param; - /* The following is written in such a way to make also solaris happy */ - struct pam_conv pam_start_arg = { &conv, (char*) ¶m }; - - /* - get the service name, as specified in - - CREATE USER ... IDENTIFIED WITH pam AS "service" - */ - const char *service = info->auth_string && info->auth_string[0] - ? info->auth_string : "mysql"; - - param.ptr = param.buf + 1; - param.vio = vio; - - PAM_DEBUG((stderr, "PAM: pam_start(%s, %s)\n", service, info->user_name)); - DO( pam_start(service, info->user_name, &pam_start_arg, &pamh) ); - - PAM_DEBUG((stderr, "PAM: pam_authenticate(0)\n")); - DO( pam_authenticate (pamh, 0) ); - - PAM_DEBUG((stderr, "PAM: pam_acct_mgmt(0)\n")); - DO( pam_acct_mgmt(pamh, 0) ); - - PAM_DEBUG((stderr, "PAM: pam_get_item(PAM_USER)\n")); - DO( pam_get_item(pamh, PAM_USER, (pam_get_item_3_arg) &new_username) ); - - if (new_username && - (winbind_hack ? strcasecmp : strcmp)(new_username, info->user_name)) - strncpy(info->authenticated_as, new_username, - sizeof(info->authenticated_as)-1); - info->authenticated_as[sizeof(info->authenticated_as)-1]= 0; - -end: - pam_end(pamh, status); - PAM_DEBUG((stderr, "PAM: status = %d user = %s\n", status, info->authenticated_as)); - return status == PAM_SUCCESS ? CR_OK : CR_ERROR; + PAM_DEBUG((stderr, "PAM: auth result %d.\n", result)); + return result; } -static struct st_mysql_auth info = -{ - MYSQL_AUTHENTICATION_INTERFACE_VERSION, - "dialog", - pam_auth -}; - -static char use_cleartext_plugin; -static MYSQL_SYSVAR_BOOL(use_cleartext_plugin, use_cleartext_plugin, - PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, - "Use mysql_cleartext_plugin on the client side instead of the dialog " - "plugin. This may be needed for compatibility reasons, but it only " - "supports simple PAM policies that don't require anything besides " - "a password", NULL, NULL, 0); - -static MYSQL_SYSVAR_BOOL(winbind_workaround, winbind_hack, PLUGIN_VAR_OPCMDARG, - "Compare usernames case insensitively to work around pam_winbind " - "unconditional username lowercasing", NULL, NULL, 0); - -#ifndef DBUG_OFF -static MYSQL_SYSVAR_BOOL(debug, pam_debug, PLUGIN_VAR_OPCMDARG, - "Log all PAM activity", NULL, NULL, 0); -#endif - -static struct st_mysql_sys_var* vars[] = { - MYSQL_SYSVAR(use_cleartext_plugin), - MYSQL_SYSVAR(winbind_workaround), -#ifndef DBUG_OFF - MYSQL_SYSVAR(debug), -#endif - NULL -}; +#include "auth_pam_common.c" static int init(void *p __attribute__((unused))) { if (use_cleartext_plugin) info.client_auth_plugin= "mysql_clear_password"; + if (!(opt_plugin_dir= dlsym(RTLD_DEFAULT, "opt_plugin_dir"))) + return 1; return 0; } @@ -221,15 +227,15 @@ maria_declare_plugin(pam) MYSQL_AUTHENTICATION_PLUGIN, &info, "pam", - "Sergei Golubchik", + "MariaDB Corp", "PAM based authentication", PLUGIN_LICENSE_GPL, init, NULL, - 0x0100, + 0x0200, NULL, vars, - "1.0", + "2.0", MariaDB_PLUGIN_MATURITY_STABLE } maria_declare_plugin_end; diff --git a/plugin/auth_pam/auth_pam_base.c b/plugin/auth_pam/auth_pam_base.c new file mode 100644 index 00000000000..1e8f4a08def --- /dev/null +++ b/plugin/auth_pam/auth_pam_base.c @@ -0,0 +1,179 @@ +/* + Copyright (c) 2011, 2018 MariaDB Corporation + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ + +/* + This file contains code to interact with the PAM module. + To be included into auth_pam_tool.c and auth_pam_v2.c, + + Before the #include these sould be defined: + + struct param { + unsigned char buf[10240], *ptr; + MYSQL_PLUGIN_VIO *vio; + ... other arbitrary fields allowed. + }; + static int write_packet(struct param *param, const unsigned char *buf, + int buf_len) + static int read_packet(struct param *param, unsigned char **pkt) +*/ + +#include <config_auth_pam.h> +#include <stdio.h> +#include <string.h> +#include <security/pam_appl.h> +#include <security/pam_modules.h> + +/* It least solaris doesn't have strndup */ + +#ifndef HAVE_STRNDUP +char *strndup(const char *from, size_t length) +{ + char *ptr; + size_t max_length= strlen(from); + if (length > max_length) + length= max_length; + if ((ptr= (char*) malloc(length+1)) != 0) + { + memcpy((char*) ptr, (char*) from, length); + ptr[length]=0; + } + return ptr; +} +#endif + +#ifndef DBUG_OFF +static char pam_debug = 0; +#define PAM_DEBUG(X) do { if (pam_debug) { fprintf X; } } while(0) +#else +#define PAM_DEBUG(X) /* no-op */ +#endif + +static char winbind_hack = 0; + +static int conv(int n, const struct pam_message **msg, + struct pam_response **resp, void *data) +{ + struct param *param = (struct param *)data; + unsigned char *end = param->buf + sizeof(param->buf) - 1; + int i; + + *resp = 0; + + for (i = 0; i < n; i++) + { + /* if there's a message - append it to the buffer */ + if (msg[i]->msg) + { + int len = strlen(msg[i]->msg); + if (len > end - param->ptr) + len = end - param->ptr; + if (len > 0) + { + memcpy(param->ptr, msg[i]->msg, len); + param->ptr+= len; + *(param->ptr)++ = '\n'; + } + } + /* if the message style is *_PROMPT_*, meaning PAM asks a question, + send the accumulated text to the client, read the reply */ + if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || + msg[i]->msg_style == PAM_PROMPT_ECHO_ON) + { + int pkt_len; + unsigned char *pkt; + + /* allocate the response array. + freeing it is the responsibility of the caller */ + if (*resp == 0) + { + *resp = calloc(sizeof(struct pam_response), n); + if (*resp == 0) + return PAM_BUF_ERR; + } + + /* dialog plugin interprets the first byte of the packet + as the magic number. + 2 means "read the input with the echo enabled" + 4 means "password-like input, echo disabled" + C'est la vie. */ + param->buf[0] = msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? 2 : 4; + PAM_DEBUG((stderr, "PAM: conv: send(%.*s)\n", + (int)(param->ptr - param->buf - 1), param->buf)); + pkt_len= roundtrip(param, param->buf, param->ptr - param->buf - 1, &pkt); + if (pkt_len < 0) + return PAM_CONV_ERR; + + PAM_DEBUG((stderr, "PAM: conv: recv(%.*s)\n", pkt_len, pkt)); + /* allocate and copy the reply to the response array */ + if (!((*resp)[i].resp= strndup((char*) pkt, pkt_len))) + return PAM_CONV_ERR; + param->ptr = param->buf + 1; + } + } + return PAM_SUCCESS; +} + +#define DO(X) if ((status = (X)) != PAM_SUCCESS) goto end + +#if defined(SOLARIS) || defined(__sun) +typedef void** pam_get_item_3_arg; +#else +typedef const void** pam_get_item_3_arg; +#endif + +static int pam_auth_base(struct param *param, MYSQL_SERVER_AUTH_INFO *info) +{ + pam_handle_t *pamh = NULL; + int status; + const char *new_username= NULL; + /* The following is written in such a way to make also solaris happy */ + struct pam_conv pam_start_arg = { &conv, (char*) param }; + + /* + get the service name, as specified in + + CREATE USER ... IDENTIFIED WITH pam AS "service" + */ + const char *service = info->auth_string && info->auth_string[0] + ? info->auth_string : "mysql"; + + param->ptr = param->buf + 1; + + PAM_DEBUG((stderr, "PAM: pam_start(%s, %s)\n", service, info->user_name)); + DO( pam_start(service, info->user_name, &pam_start_arg, &pamh) ); + + PAM_DEBUG((stderr, "PAM: pam_authenticate(0)\n")); + DO( pam_authenticate (pamh, 0) ); + + PAM_DEBUG((stderr, "PAM: pam_acct_mgmt(0)\n")); + DO( pam_acct_mgmt(pamh, 0) ); + + PAM_DEBUG((stderr, "PAM: pam_get_item(PAM_USER)\n")); + DO( pam_get_item(pamh, PAM_USER, (pam_get_item_3_arg) &new_username) ); + + if (new_username && + (winbind_hack ? strcasecmp : strcmp)(new_username, info->user_name)) + strncpy(info->authenticated_as, new_username, + sizeof(info->authenticated_as)); + info->authenticated_as[sizeof(info->authenticated_as)-1]= 0; + +end: + PAM_DEBUG((stderr, "PAM: status = %d (%s) user = %s\n", + status, pam_strerror(pamh, status), info->authenticated_as)); + pam_end(pamh, status); + return status == PAM_SUCCESS ? CR_OK : CR_ERROR; +} + diff --git a/plugin/auth_pam/auth_pam_common.c b/plugin/auth_pam/auth_pam_common.c new file mode 100644 index 00000000000..ef8f0f658ff --- /dev/null +++ b/plugin/auth_pam/auth_pam_common.c @@ -0,0 +1,56 @@ +/* + Copyright (c) 2011, 2018 MariaDB Corporation + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ + +/* + In this file we gather the plugin interface definitions + that are same in all the PAM plugin versions. + To be included into auth_pam.c and auth_pam_v1.c. +*/ + +static struct st_mysql_auth info = +{ + MYSQL_AUTHENTICATION_INTERFACE_VERSION, + "dialog", + pam_auth, + NULL, NULL /* no PASSWORD() */ +}; + +static char use_cleartext_plugin; +static MYSQL_SYSVAR_BOOL(use_cleartext_plugin, use_cleartext_plugin, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Use mysql_cleartext_plugin on the client side instead of the dialog " + "plugin. This may be needed for compatibility reasons, but it only " + "supports simple PAM policies that don't require anything besides " + "a password", NULL, NULL, 0); + +static MYSQL_SYSVAR_BOOL(winbind_workaround, winbind_hack, PLUGIN_VAR_OPCMDARG, + "Compare usernames case insensitively to work around pam_winbind " + "unconditional username lowercasing", NULL, NULL, 0); + +#ifndef DBUG_OFF +static MYSQL_SYSVAR_BOOL(debug, pam_debug, PLUGIN_VAR_OPCMDARG, + "Log all PAM activity", NULL, NULL, 0); +#endif + + +static struct st_mysql_sys_var* vars[] = { + MYSQL_SYSVAR(use_cleartext_plugin), + MYSQL_SYSVAR(winbind_workaround), +#ifndef DBUG_OFF + MYSQL_SYSVAR(debug), +#endif + NULL +}; diff --git a/plugin/auth_pam/auth_pam_tool.c b/plugin/auth_pam/auth_pam_tool.c new file mode 100644 index 00000000000..225f35a6624 --- /dev/null +++ b/plugin/auth_pam/auth_pam_tool.c @@ -0,0 +1,120 @@ +/* + Copyright (c) 2011, 2018 MariaDB Corporation + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <mysql/plugin_auth_common.h> + +struct param { + unsigned char buf[10240], *ptr; +}; + + +#include "auth_pam_tool.h" + + +static int roundtrip(struct param *param, const unsigned char *buf, + int buf_len, unsigned char **pkt) +{ + unsigned char b= AP_CONV; + if (write(1, &b, 1) < 1 || write_string(1, buf, buf_len)) + return -1; + *pkt= (unsigned char *) param->buf; + return read_string(0, (char *) param->buf, (int) sizeof(param->buf)); +} + +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. + */ + char *user_name; + + /** + A corresponding column value from the mysql.user table for the + matching account name + */ + 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]; +} MYSQL_SERVER_AUTH_INFO; + + +#include "auth_pam_base.c" + + +int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) +{ + struct param param; + MYSQL_SERVER_AUTH_INFO info; + unsigned char field; + int res; + char a_buf[MYSQL_USERNAME_LENGTH + 1 + 1024]; + + if ((res= setreuid(0, 0))) + fprintf(stderr, "Got error %d from setreuid()\n", (int) errno); + + if (read(0, &field, 1) < 1) + return -1; +#ifndef DBUG_OFF + pam_debug= field & 1; +#endif + winbind_hack= field & 2; + + PAM_DEBUG((stderr, "PAM: sandbox started [%s].\n", argv[0])); + + info.user_name= a_buf; + if ((res= read_string(0, info.user_name, sizeof(a_buf))) < 0) + return -1; + PAM_DEBUG((stderr, "PAM: sandbox username [%s].\n", info.user_name)); + + info.auth_string= info.user_name + res + 1; + if (read_string(0, info.auth_string, sizeof(a_buf) - 1 - res) < 0) + return -1; + + PAM_DEBUG((stderr, "PAM: sandbox auth string [%s].\n", info.auth_string)); + + if ((res= pam_auth_base(¶m, &info)) != CR_OK) + { + PAM_DEBUG((stderr, "PAM: auth failed, sandbox closed.\n")); + return -1; + } + + if (info.authenticated_as[0]) + { + PAM_DEBUG((stderr, "PAM: send authenticated_as field.\n")); + field= AP_AUTHENTICATED_AS; + if (write(1, &field, 1) < 1 || + write_string(1, (unsigned char *) info.authenticated_as, + strlen(info.authenticated_as))) + return -1; + } + + PAM_DEBUG((stderr, "PAM: send OK result.\n")); + field= AP_EOF; + if (write(1, &field, 1) != 1) + return -1; + + PAM_DEBUG((stderr, "PAM: sandbox closed.\n")); + return 0; +} diff --git a/plugin/auth_pam/auth_pam_tool.h b/plugin/auth_pam/auth_pam_tool.h new file mode 100644 index 00000000000..60ae016db72 --- /dev/null +++ b/plugin/auth_pam/auth_pam_tool.h @@ -0,0 +1,81 @@ +/* + Copyright (c) 2011, 2018 MariaDB Corporation + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ + +/* + This file contains definitions and functions for + the interface between the auth_pam.so (PAM plugin version 2) + and the auth_pam_tool executable. + To be included both in auth_pam.c and auth_pam_tool.c. +*/ + +#define AP_AUTHENTICATED_AS 'A' +#define AP_CONV 'C' +#define AP_EOF 'E' + + +static int read_length(int file) +{ + unsigned char hdr[2]; + + if (read(file, hdr, 2) < 2) + return -1; + + return (((int) hdr[0]) << 8) + (int) hdr[1]; +} + + +static void store_length(int len, unsigned char *p_len) +{ + p_len[0]= (unsigned char) ((len >> 8) & 0xFF); + p_len[1]= (unsigned char) (len & 0xFF); +} + + +/* + Returns the length of the string read, + or -1 on error. +*/ + +static int read_string(int file, char *s, int s_size) +{ + int len; + + len= read_length(file); + + if (len < 0 || len > s_size-1 || + read(file, s, len) < len) + return -1; + + s[len]= 0; + + return len; +} + + +/* + Returns 0 on success. +*/ + +static int write_string(int file, const unsigned char *s, int s_len) +{ + unsigned char hdr[2]; + store_length(s_len, hdr); + return write(file, hdr, 2) < 2 || + write(file, s, s_len) < s_len; +} + + +#define MAX_PAM_SERVICE_NAME 1024 diff --git a/plugin/auth_pam/auth_pam_v1.c b/plugin/auth_pam/auth_pam_v1.c new file mode 100644 index 00000000000..a38ef8f53ca --- /dev/null +++ b/plugin/auth_pam/auth_pam_v1.c @@ -0,0 +1,86 @@ +/* + Copyright (c) 2011, 2018 MariaDB Corporation + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ + +#include <mysql/plugin_auth.h> + +struct param { + unsigned char buf[10240], *ptr, *cached; + int cached_len; + MYSQL_PLUGIN_VIO *vio; +}; + +static int roundtrip(struct param *param, const unsigned char *buf, + int buf_len, unsigned char **pkt) +{ + if (param->cached && *param->cached && (buf[0] >> 1) == 2) + { + *pkt= param->cached; + param->cached= NULL; + return param->cached_len; + } + param->cached= NULL; + if (param->vio->write_packet(param->vio, buf, buf_len)) + return -1; + return param->vio->read_packet(param->vio, pkt); +} + +#include "auth_pam_base.c" + +static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) +{ + struct param param; + param.vio = vio; + + /* no user name yet ? read the client handshake packet with the user name */ + if (info->user_name == 0) + { + if ((param.cached_len= vio->read_packet(vio, ¶m.cached)) < 0) + return CR_ERROR; + } + else + param.cached= NULL; + + return pam_auth_base(¶m, info); +} + + +#include "auth_pam_common.c" + + +static int init(void *p __attribute__((unused))) +{ + if (use_cleartext_plugin) + info.client_auth_plugin= "mysql_clear_password"; + return 0; +} + +maria_declare_plugin(pam) +{ + MYSQL_AUTHENTICATION_PLUGIN, + &info, + "pam", + "Sergei Golubchik", + "PAM based authentication", + PLUGIN_LICENSE_GPL, + init, + NULL, + 0x0100, + NULL, + vars, + "1.0", + MariaDB_PLUGIN_MATURITY_STABLE +} +maria_declare_plugin_end; diff --git a/plugin/auth_pam/testing/CMakeLists.txt b/plugin/auth_pam/testing/CMakeLists.txt new file mode 100644 index 00000000000..151823b9419 --- /dev/null +++ b/plugin/auth_pam/testing/CMakeLists.txt @@ -0,0 +1,15 @@ +# gcc pam_mariadb_mtr.c -shared -lpam -fPIC -o pam_mariadb_mtr.so + +ADD_LIBRARY(pam_mariadb_mtr MODULE pam_mariadb_mtr.c) +SET_TARGET_PROPERTIES (pam_mariadb_mtr PROPERTIES PREFIX "") +TARGET_LINK_LIBRARIES(pam_mariadb_mtr pam) + +IF(CMAKE_C_COMPILER_ID MATCHES "Clang") + SET_SOURCE_FILES_PROPERTIES( + pam_mariadb_mtr.c + PROPERTY COMPILE_FLAGS "-Wno-incompatible-pointer-types-discards-qualifiers") +ENDIF() + +SET(dest DESTINATION "${INSTALL_MYSQLTESTDIR}/suite/plugins/pam" COMPONENT Test) +INSTALL(TARGETS pam_mariadb_mtr ${dest}) +INSTALL(FILES mariadb_mtr.conf RENAME mariadb_mtr ${dest}) diff --git a/plugin/auth_pam/testing/mariadb_mtr.conf b/plugin/auth_pam/testing/mariadb_mtr.conf new file mode 100644 index 00000000000..241afb4367d --- /dev/null +++ b/plugin/auth_pam/testing/mariadb_mtr.conf @@ -0,0 +1,4 @@ +# Put it in /etc/pam.d/mariadb_mtr + +auth required pam_mariadb_mtr.so pam_test +account required pam_permit.so diff --git a/plugin/auth_pam/testing/pam_mariadb_mtr.c b/plugin/auth_pam/testing/pam_mariadb_mtr.c index 473ec246fe0..2075d5fdbf3 100644 --- a/plugin/auth_pam/testing/pam_mariadb_mtr.c +++ b/plugin/auth_pam/testing/pam_mariadb_mtr.c @@ -1,19 +1,11 @@ /* This code is in the public domain and has no copyright. - Pam module to test pam authentication plugin. Used in pam.test. + Pam module to test pam authentication plugin. Used in pam tests. Linux only. - - Compile as - gcc pam_mariadb_mtr.c -shared -lpam -fPIC -o pam_mariadb_mtr.so - Install as appropriate (for example, in /lib/security/). - Create /etc/pam.d/mariadb_mtr with -========================================================= -auth required pam_mariadb_mtr.so pam_test -account required pam_permit.so -========================================================= + see also mariadb_mtr.conf */ #include <stdlib.h> @@ -23,7 +15,7 @@ account required pam_permit.so #define N 3 -int pam_sm_authenticate(pam_handle_t *pamh, int flags, +int pam_sm_authenticate(pam_handle_t *pamh, int flags __attribute__((unused)), int argc, const char *argv[]) { struct pam_conv *conv; @@ -31,7 +23,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int pam_err, retval = PAM_SYSTEM_ERR; struct pam_message msg[N] = { { PAM_TEXT_INFO, "Challenge input first." }, - { PAM_PROMPT_ECHO_ON, "Enter:" }, + { PAM_PROMPT_ECHO_OFF, "Enter:" }, { PAM_ERROR_MSG, "Now, the magic number!" } }; const struct pam_message *msgp[N] = { msg, msg+1, msg+2 }; @@ -46,19 +38,29 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, if (pam_err != PAM_SUCCESS || !resp || !((r1= resp[1].resp))) goto ret; - free(resp); + if (strcmp(r1, "cleartext good") == 0) + retval = PAM_SUCCESS; + else if (strcmp(r1, "cleartext bad") == 0) + retval = PAM_AUTH_ERR; + else + { + free(resp); + msg[0].msg_style = PAM_PROMPT_ECHO_ON; + msg[0].msg = "PIN:"; + pam_err = (*conv->conv)(1, msgp, &resp, conv->appdata_ptr); - msg[0].msg_style = PAM_PROMPT_ECHO_OFF; - msg[0].msg = "PIN:"; - pam_err = (*conv->conv)(1, msgp, &resp, conv->appdata_ptr); + if (pam_err != PAM_SUCCESS || !resp || !((r2= resp[0].resp))) + goto ret; - if (pam_err != PAM_SUCCESS || !resp || !((r2= resp[0].resp))) - goto ret; + /* Produce the crash for testing purposes. */ + if (strcmp(r1, "crash pam module") == 0 && atoi(r2) == 616) + abort(); - if (strlen(r1) == atoi(r2) % 100) - retval = PAM_SUCCESS; - else - retval = PAM_AUTH_ERR; + if (strlen(r1) == (size_t)atoi(r2) % 100) + retval = PAM_SUCCESS; + else + retval = PAM_AUTH_ERR; + } if (argc > 0 && argv[0]) pam_set_item(pamh, PAM_USER, argv[0]); @@ -70,8 +72,10 @@ ret: return retval; } -int pam_sm_setcred(pam_handle_t *pamh, int flags, - int argc, const char *argv[]) +int pam_sm_setcred(pam_handle_t *pamh __attribute__((unused)), + int flags __attribute__((unused)), + int argc __attribute__((unused)), + const char *argv[] __attribute__((unused))) { return PAM_SUCCESS; diff --git a/plugin/auth_socket/CMakeLists.txt b/plugin/auth_socket/CMakeLists.txt index eafa82bda99..5a59520a3e4 100644 --- a/plugin/auth_socket/CMakeLists.txt +++ b/plugin/auth_socket/CMakeLists.txt @@ -65,5 +65,5 @@ ENDIF() ENDIF() IF(ok) - MYSQL_ADD_PLUGIN(auth_socket auth_socket.c) + MYSQL_ADD_PLUGIN(auth_socket auth_socket.c DEFAULT) ENDIF() diff --git a/plugin/auth_socket/auth_socket.c b/plugin/auth_socket/auth_socket.c index c31f78a4500..46eae517cb8 100644 --- a/plugin/auth_socket/auth_socket.c +++ b/plugin/auth_socket/auth_socket.c @@ -102,7 +102,8 @@ static struct st_mysql_auth socket_auth_handler= { MYSQL_AUTHENTICATION_INTERFACE_VERSION, 0, - socket_auth + socket_auth, + NULL, NULL /* no PASSWORD() */ }; maria_declare_plugin(auth_socket) diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt index 5389ad34bbd..3c6ca018273 100644 --- a/plugin/aws_key_management/CMakeLists.txt +++ b/plugin/aws_key_management/CMakeLists.txt @@ -1,180 +1,17 @@ -# We build parts of AWS C++ SDK as CMake external project -# The restrictions of the SDK (https://github.com/awslabs/aws-sdk-cpp/blob/master/README.md) -# are - -# - OS : Windows,Linux or OSX -# - C++11 compiler : VS2013+, gcc 4.8+, clang 3.3+ -# - libcurl development package needs to be present on Unixes -# -# If we build SDK outselves, we'll need require GIT to be present on the build machine - - -# Give message why the building this plugin is skipped (only if -DVERBOSE is defined) -# or if plugin is explicitly requested to build. Then bail out. -MACRO(SKIP_AWS_PLUGIN msg) - MESSAGE_ONCE(SKIP_AWS_PLUGIN "Skip aws_key_management - ${msg}") +INCLUDE(aws_sdk) +CHECK_AWS_SDK(HAVE_AWS_SDK REASON) +IF(NOT HAVE_AWS_SDK) + MESSAGE_ONCE(AWS_KEY_MANAGEMENT_NO_AWS_SDK "Can't build aws_key_management - AWS SDK not available (${REASON})") ADD_FEATURE_INFO(AWS_KEY_MANAGEMENT "OFF" "AWS Encryption Key Management Plugin") RETURN() -ENDMACRO() -SET(CMAKE_CXX_STANDARD 11) - -IF(NOT NOT_FOR_DISTRIBUTION) - SKIP_AWS_PLUGIN("AWS SDK has Apache 2.0 License which is not complatible with GPLv2. Set -DNOT_FOR_DISTRIBUTION=ON if you need this plugin") -ENDIF() - -# This plugin needs recent C++ compilers (AWS C++ SDK header files are using C++11 features) -SET(CXX11_FLAGS) -SET(OLD_COMPILER_MSG "AWS SDK requires c++11 -capable compiler (minimal supported versions are g++ 4.8, clang 3.3, VS2103)") - -IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - IF (GCC_VERSION VERSION_LESS 4.8) - SKIP_AWS_PLUGIN("${OLD_COMPILER_MSG}") - ENDIF() - SET(CXX11_FLAGS "-std=c++11") -ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - IF ((CMAKE_CXX_COMPILER_VERSION AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3) OR - (CLANG_VERSION_STRING AND CLANG_VERSION_STRING VERSION_LESS 3.3)) - SKIP_AWS_PLUGIN("${OLD_COMPILER_MSG}") - ENDIF() - SET(CXX11_FLAGS "-stdlib=libc++") -ELSEIF(MSVC) - IF (MSVC_VERSION LESS 1800) - SKIP_AWS_PLUGIN("${OLD_COMPILER_MSG}") - ENDIF() -ELSE() - SKIP_AWS_PLUGIN("Compiler not supported by AWS C++ SDK") -ENDIF() - -IF (NOT(WIN32 OR APPLE OR (CMAKE_SYSTEM_NAME MATCHES "Linux"))) - SKIP_AWS_PLUGIN("OS unsupported by AWS SDK") ENDIF() +MYSQL_ADD_PLUGIN(aws_key_management + aws_key_management_plugin.cc + COMPONENT aws-key-management) - -FIND_LIBRARY(AWS_CPP_SDK_CORE NAMES aws-cpp-sdk-core PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}") -FIND_LIBRARY(AWS_CPP_SDK_KMS NAMES aws-cpp-sdk-kms PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}") -FIND_PATH(AWS_CPP_SDK_INCLUDE_DIR NAMES aws/kms/KMSClient.h) - -IF(AWS_CPP_SDK_CORE AND AWS_CPP_SDK_KMS AND AWS_CPP_SDK_INCLUDE_DIR) - # AWS C++ SDK installed - INCLUDE_DIRECTORIES(${AWS_CPP_SDK_INCLUDE_DIR}) - SET(AWS_SDK_LIBS ${AWS_CPP_SDK_CORE} ${AWS_CPP_SDK_KMS}) -ELSE() - OPTION(AWS_SDK_EXTERNAL_PROJECT "Allow download and build AWS C++ SDK" OFF) - IF(NOT AWS_SDK_EXTERNAL_PROJECT) - SKIP_AWS_PLUGIN("AWS_SDK_EXTERNAL_PROJECT is not set") - ENDIF() - # Build from source, using ExternalProject_Add - # AWS C++ SDK requires cmake 2.8.12 - IF(CMAKE_VERSION VERSION_LESS "2.8.12") - SKIP_AWS_PLUGIN("CMake is too old") - ENDIF() - FIND_PACKAGE(Git) - IF(NOT GIT_FOUND) - SKIP_AWS_PLUGIN("no GIT") - ENDIF() - INCLUDE(ExternalProject) - IF(UNIX) - FIND_PACKAGE(CURL) - SET_PACKAGE_PROPERTIES(CURL PROPERTIES TYPE REQUIRED) - IF(NOT CURL_FOUND) - SKIP_AWS_PLUGIN("AWS C++ SDK requires libcurl development package") - ENDIF() - SET(PIC_FLAG -fPIC) - FIND_PATH(UUID_INCLUDE_DIR uuid/uuid.h) - IF(NOT UUID_INCLUDE_DIR) - SKIP_AWS_PLUGIN("AWS C++ SDK requires uuid development package") - ENDIF() - IF(NOT APPLE) - FIND_LIBRARY(UUID_LIBRARIES uuid) - SET_PACKAGE_PROPERTIES(UUID_LIBRARIES PROPERTIES TYPE REQUIRED) - IF(NOT UUID_LIBRARIES) - SKIP_AWS_PLUGIN("AWS C++ SDK requires uuid development package") - ENDIF() - FIND_PACKAGE(OpenSSL) - SET_PACKAGE_PROPERTIES(OpenSSL PROPERTIES TYPE REQUIRED) - IF(NOT OPENSSL_FOUND) - SKIP_AWS_PLUGIN("AWS C++ SDK requires openssl development package") - ENDIF() - ENDIF() - ENDIF() - IF(MSVC) - SET(EXTRA_SDK_CMAKE_FLAGS -DCMAKE_CXX_FLAGS_DEBUGOPT="" -DCMAKE_EXE_LINKER_FLAGS_DEBUGOPT="" "-DCMAKE_CXX_FLAGS=/wd4530 /wd4577 /WX-") - ENDIF() - IF(CMAKE_CXX_COMPILER) - SET(EXTRA_SDK_CMAKE_FLAGS ${EXTRA_SDK_CMAKE_FLAGS} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}) - ENDIF() - - SET(byproducts ) - # We do not need to build the whole SDK , just 2 of its libs - set(AWS_SDK_LIBS aws-cpp-sdk-core aws-cpp-sdk-kms) - FOREACH(lib ${AWS_SDK_LIBS}) - ADD_LIBRARY(${lib} STATIC IMPORTED GLOBAL) - ADD_DEPENDENCIES(${lib} aws_sdk_cpp) - SET(loc "${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}") - IF(CMAKE_VERSION VERSION_GREATER "3.1") - SET(byproducts ${byproducts} BUILD_BYPRODUCTS ${loc}) - ENDIF() - SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LOCATION ${loc}) - ENDFOREACH() - - # To be compatible with older cmake, we use older version of the SDK - IF(CMAKE_VERSION LESS "3.0") - SET(GIT_TAG "1.0.8") - ELSE() - SET(GIT_TAG "1.2.11") - ENDIF() - - SET(AWS_SDK_PATCH_COMMAND ) - ExternalProject_Add( - aws_sdk_cpp - GIT_REPOSITORY "https://github.com/awslabs/aws-sdk-cpp.git" - GIT_TAG ${GIT_TAG} - UPDATE_COMMAND "" - SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/aws-sdk-cpp" - ${byproducts} - CMAKE_ARGS - -DBUILD_ONLY=kms - -DBUILD_SHARED_LIBS=OFF - -DFORCE_SHARED_CRT=OFF - -DENABLE_TESTING=OFF - "-DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG} ${PIC_FLAG}" - "-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${PIC_FLAG}" - "-DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} ${PIC_FLAG}" - "-DCMAKE_CXX_FLAGS_MINSIZEREL=${CMAKE_CXX_FLAGS_MINSIZEREL} ${PIC_FLAG}" - ${EXTRA_SDK_CMAKE_FLAGS} - -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp - -DCMAKE_INSTALL_LIBDIR=lib - TEST_COMMAND "" - ) - SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE) - - IF(CMAKE_SYSTEM_NAME MATCHES "Linux") - # Need whole-archive , otherwise static libraries are not linked - SET(AWS_SDK_LIBS -Wl,--whole-archive ${AWS_SDK_LIBS} -Wl,--no-whole-archive) - ENDIF() - SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp/include) -ENDIF() - -ADD_DEFINITIONS(${SSL_DEFINES}) # Need to know whether openssl should be initialized -IF(CMAKE_VERSION GREATER "3.0") - SET(CMAKE_CXX_STANDARD 11) -ELSE() - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAGS}") -ENDIF() -IF(WIN32) - SET(AWS_CPP_SDK_DEPENDENCIES bcrypt winhttp wininet userenv version) -ELSE() - SET(AWS_CPP_SDK_DEPENDENCIES ${OPENSSL_LIBRARIES} ${CURL_LIBRARIES} ${UUID_LIBRARIES}) -ENDIF() -MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc - LINK_LIBRARIES ${AWS_SDK_LIBS} ${AWS_CPP_SDK_DEPENDENCIES} - COMPONENT aws-key-management) - -IF (TARGET aws_key_management) - SET(NON_DISTRIBUTABLE_WARNING "Apache 2.0" PARENT_SCOPE) +IF(TARGET aws_key_management) + USE_AWS_SDK_LIBS(aws_key_management kms) ENDIF() ADD_FEATURE_INFO(AWS_KEY_MANAGEMENT "ON" "AWS Encryption Key Management Plugin") diff --git a/plugin/aws_key_management/aws_key_management_plugin.cc b/plugin/aws_key_management/aws_key_management_plugin.cc index 4a8f318986f..e2182336aa6 100644 --- a/plugin/aws_key_management/aws_key_management_plugin.cc +++ b/plugin/aws_key_management/aws_key_management_plugin.cc @@ -110,7 +110,7 @@ static void print_kms_error(const char *func, const Aws::Client::AWSError<Aws::K { my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin : KMS Client API '%s' failed : %s - %s", - ME_ERROR_LOG, + ME_ERROR_LOG_ONLY, func, err.GetExceptionName().c_str(), err.GetMessage().c_str()); } @@ -161,6 +161,10 @@ public: { } + virtual void Flush(void) override + { + } + protected: virtual void ProcessFormattedStatement(Aws::String&& statement) override { @@ -214,7 +218,7 @@ Aws::SDKOptions sdkOptions; static int aws_init() { -#ifdef HAVE_YASSL +#ifdef HAVE_WOLFSSL sdkOptions.cryptoOptions.initAndCleanupOpenSSL = true; #else /* Server initialized OpenSSL already, thus AWS must skip it */ @@ -237,7 +241,7 @@ static int aws_init() client = new KMSClient(clientConfiguration); if (!client) { - my_printf_error(ER_UNKNOWN_ERROR, "Can not initialize KMS client", ME_ERROR_LOG | ME_WARNING); + my_printf_error(ER_UNKNOWN_ERROR, "Can't initialize KMS client", ME_ERROR_LOG_ONLY | ME_WARNING); return -1; } return 0; @@ -339,12 +343,12 @@ static int load_key(KEY_INFO *info) if (!ret) { - my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: loaded key %u, version %u, key length %u bit", ME_ERROR_LOG | ME_NOTE, + my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: loaded key %u, version %u, key length %u bit", ME_ERROR_LOG_ONLY | ME_NOTE, info->key_id, info->key_version,(uint)info->length*8); } else { - my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: key %u, version %u could not be decrypted", ME_ERROR_LOG | ME_WARNING, + my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: key %u, version %u could not be decrypted", ME_ERROR_LOG_ONLY | ME_WARNING, info->key_id, info->key_version); } return ret; @@ -443,13 +447,13 @@ static int read_and_decrypt_key(const char *path, KEY_INFO *info) ifstream ifs(path, ios::binary | ios::ate); if (!ifs.good()) { - my_printf_error(ER_UNKNOWN_ERROR, "can't open file %s", ME_ERROR_LOG, path); + my_printf_error(ER_UNKNOWN_ERROR, "can't open file %s", ME_ERROR_LOG_ONLY, path); return(-1); } size_t pos = (size_t)ifs.tellg(); if (!pos || pos == SIZE_T_MAX) { - my_printf_error(ER_UNKNOWN_ERROR, "invalid key file %s", ME_ERROR_LOG, path); + my_printf_error(ER_UNKNOWN_ERROR, "invalid key file %s", ME_ERROR_LOG_ONLY, path); return(-1); } std::vector<char> contents(pos); @@ -470,7 +474,7 @@ static int read_and_decrypt_key(const char *path, KEY_INFO *info) if (len > sizeof(info->data)) { - my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: encoding key too large for %s", ME_ERROR_LOG, path); + my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: encoding key too large for %s", ME_ERROR_LOG_ONLY, path); return(ENCRYPTION_KEY_BUFFER_TOO_SMALL); } memcpy(info->data, plaintext.GetUnderlyingData(), len); @@ -527,19 +531,19 @@ static int generate_and_save_datakey(uint keyid, uint version) int fd= open(filename, O_WRONLY |O_CREAT|O_BINARY, IF_WIN(_S_IREAD, S_IRUSR| S_IRGRP| S_IROTH)); if (fd < 0) { - my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: Can't create file %s", ME_ERROR_LOG, filename); + my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: Can't create file %s", ME_ERROR_LOG_ONLY, filename); return(-1); } unsigned int len= (unsigned int)byteBuffer.GetLength(); if (write(fd, byteBuffer.GetUnderlyingData(), len) != len) { - my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: can't write to %s", ME_ERROR_LOG, filename); + my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: can't write to %s", ME_ERROR_LOG_ONLY, filename); close(fd); unlink(filename); return(-1); } close(fd); - my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: generated encrypted datakey for key id=%u, version=%u", ME_ERROR_LOG | ME_NOTE, + my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: generated encrypted datakey for key id=%u, version=%u", ME_ERROR_LOG_ONLY | ME_NOTE, keyid, version); return(0); } @@ -552,13 +556,13 @@ static int rotate_single_key(uint key_id) if (!ver) { - my_printf_error(ER_UNKNOWN_ERROR, "key %u does not exist", MYF(ME_JUST_WARNING), key_id); + my_printf_error(ER_UNKNOWN_ERROR, "key %u does not exist", MYF(ME_WARNING), key_id); return -1; } else if (generate_and_save_datakey(key_id, ver + 1)) { my_printf_error(ER_UNKNOWN_ERROR, "Could not generate datakey for key id= %u, ver= %u", - MYF(ME_JUST_WARNING), key_id, ver); + MYF(ME_WARNING), key_id, ver); return -1; } else @@ -569,7 +573,7 @@ static int rotate_single_key(uint key_id) if (load_key(&info)) { my_printf_error(ER_UNKNOWN_ERROR, "Could not load datakey for key id= %u, ver= %u", - MYF(ME_JUST_WARNING), key_id, ver); + MYF(ME_WARNING), key_id, ver); return -1; } } @@ -594,7 +598,7 @@ static void update_rotate(MYSQL_THD, struct st_mysql_sys_var *, void *, const vo if (!master_key_id[0]) { my_printf_error(ER_UNKNOWN_ERROR, - "aws_key_management_master_key_id must be set to generate new data keys", MYF(ME_JUST_WARNING)); + "aws_key_management_master_key_id must be set to generate new data keys", MYF(ME_WARNING)); return; } mtx.lock(); diff --git a/plugin/cracklib_password_check/cracklib_password_check.c b/plugin/cracklib_password_check/cracklib_password_check.c index 55a1fd1c738..470e6e5280f 100644 --- a/plugin/cracklib_password_check/cracklib_password_check.c +++ b/plugin/cracklib_password_check/cracklib_password_check.c @@ -21,7 +21,8 @@ static char *dictionary; -static int crackme(MYSQL_CONST_LEX_STRING *username, MYSQL_CONST_LEX_STRING *password) +static int crackme(const MYSQL_CONST_LEX_STRING *username, + const MYSQL_CONST_LEX_STRING *password) { char *user= alloca(username->length + 1); char *host; diff --git a/plugin/disks/information_schema_disks.cc b/plugin/disks/information_schema_disks.cc index 414af59098f..bfae81eceac 100644 --- a/plugin/disks/information_schema_disks.cc +++ b/plugin/disks/information_schema_disks.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2017, MariaDB + Copyright (c) 2017, 2019, MariaDB 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 diff --git a/plugin/feedback/sender_thread.cc b/plugin/feedback/sender_thread.cc index 9a8e7775d01..3976c950541 100644 --- a/plugin/feedback/sender_thread.cc +++ b/plugin/feedback/sender_thread.cc @@ -90,9 +90,7 @@ static int prepare_for_fill(TABLE_LIST *tables) in SHOW STATUS and we want to avoid skewing the statistics) */ thd->variables.pseudo_thread_id= thd->thread_id; - mysql_mutex_lock(&LOCK_thread_count); - threads.append(thd); - mysql_mutex_unlock(&LOCK_thread_count); + server_threads.insert(thd); thd->thread_stack= (char*) &tables; if (thd->store_globals()) return 1; @@ -118,11 +116,12 @@ static int prepare_for_fill(TABLE_LIST *tables) tables->init_one_table(&INFORMATION_SCHEMA_NAME, &tbl_name, 0, TL_READ); tables->schema_table= i_s_feedback; tables->schema_table_reformed= 1; + tables->select_lex= thd->lex->first_select_lex(); + DBUG_ASSERT(tables->select_lex); tables->table= create_schema_table(thd, tables); if (!tables->table) return 1; - tables->select_lex= thd->lex->current_select; tables->table->pos_in_table_list= tables; return 0; @@ -139,7 +138,7 @@ static int prepare_for_fill(TABLE_LIST *tables) */ static bool going_down() { - return shutdown_plugin || shutdown_in_progress || (thd && thd->killed); + return shutdown_plugin || abort_loop || (thd && thd->killed); } /** @@ -258,12 +257,9 @@ ret: reset all thread local status variables to minimize the effect of the background thread on SHOW STATUS. */ - mysql_mutex_lock(&LOCK_thread_count); + server_threads.erase(thd); thd->set_status_var_init(); thd->killed= KILL_CONNECTION; - thd->unlink(); - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); delete thd; thd= 0; } diff --git a/plugin/file_key_management/CMakeLists.txt b/plugin/file_key_management/CMakeLists.txt index c2f13fb9f63..9b09da9bf20 100644 --- a/plugin/file_key_management/CMakeLists.txt +++ b/plugin/file_key_management/CMakeLists.txt @@ -1,4 +1,4 @@ SET(FILE_KEY_MANAGEMENT_PLUGIN_SOURCES file_key_management_plugin.cc parser.cc) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql) -MYSQL_ADD_PLUGIN(FILE_KEY_MANAGEMENT ${FILE_KEY_MANAGEMENT_PLUGIN_SOURCES}) +MYSQL_ADD_PLUGIN(FILE_KEY_MANAGEMENT ${FILE_KEY_MANAGEMENT_PLUGIN_SOURCES} MODULE_ONLY) diff --git a/plugin/file_key_management/parser.cc b/plugin/file_key_management/parser.cc index ec1b528da24..57e0139a57d 100644 --- a/plugin/file_key_management/parser.cc +++ b/plugin/file_key_management/parser.cc @@ -96,14 +96,6 @@ openssl enc -aes-256-cbc -md sha1 -k "secret" -in keys.txt -out keys.enc @param secret [in] the given secret as String, provided by the user @param key [out] 32 Bytes of key are written to this pointer @param iv [out] 16 Bytes of iv are written to this pointer - - Note, that in openssl this whole function can be reduced to - - #include <openssl/evp.h> - EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, - secret, strlen(secret), 1, key, iv); - - but alas! we want to support yassl too */ void Parser::bytes_to_key(const unsigned char *salt, const char *input, diff --git a/plugin/handler_socket/handlersocket/database.cpp b/plugin/handler_socket/handlersocket/database.cpp index a76428b29d3..9c0a2d81b98 100644 --- a/plugin/handler_socket/handlersocket/database.cpp +++ b/plugin/handler_socket/handlersocket/database.cpp @@ -280,7 +280,7 @@ dbcontext::init_thread(const void *stack_bottom, volatile int& shutdown_flag) DBG_THR(fprintf(stderr, "thread_stack = %p sizeof(THD)=%zu sizeof(mtx)=%zu " "O: %zu %zu %zu %zu %zu %zu %zu\n", - thd->thread_stack, sizeof(THD), sizeof(LOCK_thread_count), + thd->thread_stack, sizeof(THD), sizeof(mysql_mutex_t), DENA_THR_OFFSETOF(mdl_context), DENA_THR_OFFSETOF(net), DENA_THR_OFFSETOF(LOCK_thd_data), @@ -307,7 +307,7 @@ dbcontext::init_thread(const void *stack_bottom, volatile int& shutdown_flag) } { thd->thread_id = next_thread_id(); - add_to_active_threads(thd); + server_threads.insert(thd); } DBG_THR(fprintf(stderr, "HNDSOCK init thread wsts\n")); @@ -341,10 +341,8 @@ dbcontext::term_thread() close_tables_if(); my_pthread_setspecific_ptr(THR_THD, 0); { - pthread_mutex_lock(&LOCK_thread_count); delete thd; thd = 0; - pthread_mutex_unlock(&LOCK_thread_count); my_thread_end(); } } @@ -473,9 +471,7 @@ dbcontext::close_tables_if() unlock_tables_if(); DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK close tables\n")); close_thread_tables(thd); - #if MYSQL_VERSION_ID >= 50505 - thd->mdl_context.release_transactional_locks(); - #endif + thd->mdl_context.release_transactional_locks(thd); if (!table_vec.empty()) { statistic_increment(close_tables_count, &LOCK_status); table_vec.clear(); diff --git a/plugin/locale_info/CMakeLists.txt b/plugin/locale_info/CMakeLists.txt index 8f1dfa0d715..c988d652d40 100644 --- a/plugin/locale_info/CMakeLists.txt +++ b/plugin/locale_info/CMakeLists.txt @@ -1,5 +1,4 @@ -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex - ${CMAKE_SOURCE_DIR}/extra/yassl/include) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex) MYSQL_ADD_PLUGIN(LOCALES locale_info.cc RECOMPILE_FOR_EMBEDDED) diff --git a/plugin/metadata_lock_info/metadata_lock_info.cc b/plugin/metadata_lock_info/metadata_lock_info.cc index ae52a6b1353..a4c1d8ef205 100644 --- a/plugin/metadata_lock_info/metadata_lock_info.cc +++ b/plugin/metadata_lock_info/metadata_lock_info.cc @@ -21,7 +21,7 @@ #include "sql_show.h" static const LEX_STRING metadata_lock_info_lock_name[] = { - { C_STRING_WITH_LEN("Global read lock") }, + { C_STRING_WITH_LEN("Backup lock") }, { C_STRING_WITH_LEN("Schema metadata lock") }, { C_STRING_WITH_LEN("Table metadata lock") }, { C_STRING_WITH_LEN("Stored function metadata lock") }, @@ -29,23 +29,9 @@ static const LEX_STRING metadata_lock_info_lock_name[] = { { C_STRING_WITH_LEN("Stored package body metadata lock") }, { C_STRING_WITH_LEN("Trigger metadata lock") }, { C_STRING_WITH_LEN("Event metadata lock") }, - { C_STRING_WITH_LEN("Commit lock") }, { C_STRING_WITH_LEN("User lock") }, }; -static const LEX_STRING metadata_lock_info_lock_mode[] = { - { C_STRING_WITH_LEN("MDL_INTENTION_EXCLUSIVE") }, - { C_STRING_WITH_LEN("MDL_SHARED") }, - { C_STRING_WITH_LEN("MDL_SHARED_HIGH_PRIO") }, - { C_STRING_WITH_LEN("MDL_SHARED_READ") }, - { C_STRING_WITH_LEN("MDL_SHARED_WRITE") }, - { C_STRING_WITH_LEN("MDL_SHARED_UPGRADABLE") }, - { C_STRING_WITH_LEN("MDL_SHARED_READ_ONLY") }, - { C_STRING_WITH_LEN("MDL_SHARED_NO_WRITE") }, - { C_STRING_WITH_LEN("MDL_SHARED_NO_READ_WRITE") }, - { C_STRING_WITH_LEN("MDL_EXCLUSIVE") }, -}; - static ST_FIELD_INFO i_s_metadata_lock_info_fields_info[] = { {"THREAD_ID", 20, MYSQL_TYPE_LONGLONG, 0, @@ -71,22 +57,21 @@ struct st_i_s_metadata_param int i_s_metadata_lock_info_fill_row( MDL_ticket *mdl_ticket, - void *arg + void *arg, + bool granted ) { st_i_s_metadata_param *param = (st_i_s_metadata_param *) arg; THD *thd = param->thd; TABLE *table = param->table; DBUG_ENTER("i_s_metadata_lock_info_fill_row"); MDL_context *mdl_ctx = mdl_ticket->get_ctx(); - enum_mdl_type mdl_ticket_type = mdl_ticket->get_type(); MDL_key *mdl_key = mdl_ticket->get_key(); MDL_key::enum_mdl_namespace mdl_namespace = mdl_key->mdl_namespace(); + if (!granted) + DBUG_RETURN(0); table->field[0]->store((longlong) mdl_ctx->get_thread_id(), TRUE); table->field[1]->set_notnull(); - table->field[1]->store( - metadata_lock_info_lock_mode[(int) mdl_ticket_type].str, - metadata_lock_info_lock_mode[(int) mdl_ticket_type].length, - system_charset_info); + table->field[1]->store(mdl_ticket->get_type_name(), system_charset_info); table->field[2]->set_null(); table->field[3]->set_notnull(); table->field[3]->store( @@ -122,8 +107,6 @@ static int i_s_metadata_lock_info_init( compile_time_assert(sizeof(metadata_lock_info_lock_name)/sizeof(LEX_STRING) == MDL_key::NAMESPACE_END); - compile_time_assert(sizeof(metadata_lock_info_lock_mode)/sizeof(LEX_STRING) - == MDL_TYPE_END); ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p; DBUG_ENTER("i_s_metadata_lock_info_init"); diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result index 5803d7d1290..12afd5010cc 100644 --- a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result +++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result @@ -3,8 +3,7 @@ lock_mode lock_duration lock_type table_schema table_name FLUSH TABLES WITH READ LOCK; SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; lock_mode lock_duration lock_type table_schema table_name -MDL_SHARED NULL Commit lock -MDL_SHARED NULL Global read lock +MDL_BACKUP_FTWRL2 NULL Backup lock UNLOCK TABLES; SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; lock_mode lock_duration lock_type table_schema table_name diff --git a/plugin/qc_info/CMakeLists.txt b/plugin/qc_info/CMakeLists.txt index 821ffb79225..b8c5f926cff 100644 --- a/plugin/qc_info/CMakeLists.txt +++ b/plugin/qc_info/CMakeLists.txt @@ -1,5 +1,4 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql - ${PCRE_INCLUDES} - ${CMAKE_SOURCE_DIR}/extra/yassl/include) + ${PCRE_INCLUDES}) MYSQL_ADD_PLUGIN(QUERY_CACHE_INFO qc_info.cc RECOMPILE_FOR_EMBEDDED) diff --git a/plugin/query_response_time/query_response_time.cc b/plugin/query_response_time/query_response_time.cc index 5d6119d20ef..a669f7d4236 100644 --- a/plugin/query_response_time/query_response_time.cc +++ b/plugin/query_response_time/query_response_time.cc @@ -147,42 +147,36 @@ void print_time(char* buffer, std::size_t buffer_size, const char* format, class time_collector { + utility *m_utility; + Atomic_counter<uint32_t> m_count[OVERALL_POWER_COUNT + 1]; + Atomic_counter<uint64_t> m_total[OVERALL_POWER_COUNT + 1]; + public: - time_collector(utility& u) : m_utility(&u) - { } - ~time_collector() - { } - uint32 count(uint index) - { - return my_atomic_load32((int32*)&m_count[index]); - } - uint64 total(uint index) - { - return my_atomic_load64((int64*)&m_total[index]); - } -public: + time_collector(utility& u): m_utility(&u) { flush(); } + ~time_collector() { } + uint32_t count(uint index) { return m_count[index]; } + uint64_t total(uint index) { return m_total[index]; } void flush() { - memset((void*)&m_count,0,sizeof(m_count)); - memset((void*)&m_total,0,sizeof(m_total)); + for (auto i= 0; i < OVERALL_POWER_COUNT + 1; i++) + { + m_count[i]= 0; + m_total[i]= 0; + } } - void collect(uint64 time) + void collect(uint64_t time) { int i= 0; for(int count= m_utility->bound_count(); count > i; ++i) { if(m_utility->bound(i) > time) { - my_atomic_add32((int32*)(&m_count[i]), 1); - my_atomic_add64((int64*)(&m_total[i]), time); + m_count[i]++; + m_total[i]+= time; break; } } } -private: - utility* m_utility; - uint32 m_count[OVERALL_POWER_COUNT + 1]; - uint64 m_total[OVERALL_POWER_COUNT + 1]; }; class collector @@ -191,7 +185,6 @@ public: collector() : m_time(m_utility) { m_utility.setup(DEFAULT_BASE); - m_time.flush(); } public: void flush() diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 80b4b644732..86f38edf724 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -1,4 +1,5 @@ /* Copyright (C) 2013, 2015, Alexey Botchkov and SkySQL Ab + Copyright (c) 2019, 2020, MariaDB Corporation. 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 @@ -763,7 +764,7 @@ static int user_coll_fill(struct user_coll *c, char *users, ADD_ATOMIC(internal_stop_logging, 1); CLIENT_ERROR(1, "User '%.*b' was removed from the" " server_audit_excl_users.", - MYF(ME_JUST_WARNING), (int) cmp_length, users); + MYF(ME_WARNING), (int) cmp_length, users); ADD_ATOMIC(internal_stop_logging, -1); blank_user(cmp_user); refill_cmp_coll= 1; @@ -772,7 +773,7 @@ static int user_coll_fill(struct user_coll *c, char *users, { ADD_ATOMIC(internal_stop_logging, 1); CLIENT_ERROR(1, "User '%.*b' is in the server_audit_incl_users, " - "so wasn't added.", MYF(ME_JUST_WARNING), (int) cmp_length, users); + "so wasn't added.", MYF(ME_WARNING), (int) cmp_length, users); ADD_ATOMIC(internal_stop_logging, -1); remove_user(users); continue; @@ -1091,7 +1092,7 @@ static int start_logging() "Could not create file '%s'.", alt_fname); is_active= 0; CLIENT_ERROR(1, "SERVER AUDIT plugin can't create file '%s'.", - MYF(ME_JUST_WARNING), alt_fname); + MYF(ME_WARNING), alt_fname); return 1; } error_header(); @@ -2749,7 +2750,7 @@ static void update_file_path(MYSQL_THD thd, { error_header(); fprintf(stderr, "Logging was disabled..\n"); - CLIENT_ERROR(1, "Logging was disabled.", MYF(ME_JUST_WARNING)); + CLIENT_ERROR(1, "Logging was disabled.", MYF(ME_WARNING)); } goto exit_func; } @@ -2964,7 +2965,7 @@ static void update_logging(MYSQL_THD thd, start_logging(); if (!logging) { - CLIENT_ERROR(1, "Logging was disabled.", MYF(ME_JUST_WARNING)); + CLIENT_ERROR(1, "Logging was disabled.", MYF(ME_WARNING)); } mark_always_logged(thd); } diff --git a/plugin/simple_password_check/simple_password_check.c b/plugin/simple_password_check/simple_password_check.c index 93f759b293b..1762690f2c5 100644 --- a/plugin/simple_password_check/simple_password_check.c +++ b/plugin/simple_password_check/simple_password_check.c @@ -22,8 +22,8 @@ static unsigned min_length, min_digits, min_letters, min_others; -static int validate(MYSQL_CONST_LEX_STRING *username, - MYSQL_CONST_LEX_STRING *password) +static int validate(const MYSQL_CONST_LEX_STRING *username, + const MYSQL_CONST_LEX_STRING *password) { unsigned digits=0 , uppers=0 , lowers=0, others=0, length= (unsigned)password->length; const char *ptr= password->str, *end= ptr + length; diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf index c9d47e40d4b..8f62cfd0cc9 100644 --- a/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf +++ b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf @@ -2,22 +2,23 @@ !include include/default_mysqld.cnf [mysqld] -wsrep-on=1 binlog-format=row innodb-autoinc-lock-mode=2 -wsrep-cluster-address=gcomm:// wsrep_provider=@ENV.WSREP_PROVIDER [mysqld.1] #galera_port=@OPT.port +#ist_port=@OPT.port #sst_port=@OPT.port wsrep-on=1 +wsrep-cluster-address=gcomm:// wsrep_provider_options='base_port=@mysqld.1.#galera_port' wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port' wsrep_node_name=test-node-1 [mysqld.2] #galera_port=@OPT.port +#ist_port=@OPT.port #sst_port=@OPT.port wsrep-on=1 wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port' diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result index f33a628d428..f99f27f3539 100644 --- a/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result +++ b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result @@ -1,8 +1,10 @@ +connection node_2; +connection node_1; # On node 1 connection node_1; SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS; -NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID GAP PROTOCOL_VERSION -<IDX> Synced Primary 2 <CLUSTER_STATE_UUID> 0 <CLUSTER_CONF_ID> NO 3 +NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID PROTOCOL_VERSION +<IDX> synced primary 2 <CLUSTER_STATE_UUID> 2 <CLUSTER_CONF_ID> 4 SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME; INDEX UUID NAME ADDRESS <IDX> <MEMBER_ID> test-node-1 <ADDRESS> @@ -10,8 +12,8 @@ INDEX UUID NAME ADDRESS # On node 2 connection node_2; SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS; -NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID GAP PROTOCOL_VERSION -<IDX> Synced Primary 2 <CLUSTER_STATE_UUID> 0 <CLUSTER_CONF_ID> YES 3 +NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID PROTOCOL_VERSION +<IDX> synced primary 2 <CLUSTER_STATE_UUID> 2 <CLUSTER_CONF_ID> 4 SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME; INDEX UUID NAME ADDRESS <IDX> <MEMBER_ID> test-node-1 <ADDRESS> diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm index aed698ed6b4..48c1bcccd45 100644 --- a/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm +++ b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm @@ -4,15 +4,9 @@ use My::Find; @ISA = qw(My::Suite); -return "Not run for embedded server" if $::opt_embedded_server; - -return "WSREP is not compiled in" if not ::have_wsrep(); - -return "No wsrep provider library" unless ::have_wsrep_provider(); - -return ::wsrep_version_message() unless ::check_wsrep_version(); - -return "No WSREP_INFO plugin" unless $ENV{WSREP_INFO_SO}; +use lib 'suite'; +use wsrep::common; +return wsrep_not_ok() if wsrep_not_ok(); push @::global_suppressions, ( diff --git a/plugin/wsrep_info/plugin.cc b/plugin/wsrep_info/plugin.cc index 1d9b4e2e2de..f78ecdcb68c 100644 --- a/plugin/wsrep_info/plugin.cc +++ b/plugin/wsrep_info/plugin.cc @@ -52,37 +52,9 @@ #define COLUMN_WSREP_STATUS_CLUSTER_STATE_SEQNO 5 /* Cluster membership changes */ #define COLUMN_WSREP_STATUS_CLUSTER_CONF_ID 6 -/* Gap between global and local states ? */ -#define COLUMN_WSREP_STATUS_GAP 7 /* Application protocol version */ -#define COLUMN_WSREP_STATUS_PROTO_VERSION 8 +#define COLUMN_WSREP_STATUS_PROTO_VERSION 7 -static const char* get_member_status(wsrep_member_status_t status) -{ - switch (status) - { - case WSREP_MEMBER_UNDEFINED: return "Undefined"; - case WSREP_MEMBER_JOINER: return "Joiner"; - case WSREP_MEMBER_DONOR: return "Donor"; - case WSREP_MEMBER_JOINED: return "Joined"; - case WSREP_MEMBER_SYNCED: return "Synced"; - case WSREP_MEMBER_ERROR: return "Error"; - default: break; - } - return "UNKNOWN"; -} - -static const char* get_cluster_status(wsrep_view_status_t status) -{ - switch (status) - { - case WSREP_VIEW_PRIMARY: return "Primary"; - case WSREP_VIEW_NON_PRIMARY: return "Non-primary"; - case WSREP_VIEW_DISCONNECTED: return "Disconnected"; - default: break; - } - return "UNKNOWN"; -} static ST_FIELD_INFO wsrep_memb_fields[]= { @@ -107,7 +79,6 @@ static ST_FIELD_INFO wsrep_status_fields[]= 0, 0, 0, 0}, {"CLUSTER_CONF_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0, 0}, - {"GAP", 10, MYSQL_TYPE_STRING, 0, 0, 0, 0}, {"PROTOCOL_VERSION", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, 0, 0}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} @@ -122,25 +93,26 @@ static int wsrep_memb_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) wsrep_config_state->lock(); - Dynamic_array<wsrep_member_info_t> *memb_arr= - wsrep_config_state->get_member_info(); + const wsrep::view& view(wsrep_config_state->get_view_info()); + const std::vector<wsrep::view::member>& members(view.members()); + TABLE *table= tables->table; - for (unsigned int i= 0; i < memb_arr->elements(); i ++) + for (unsigned int i= 0; i < members.size(); i++) { - wsrep_member_info_t memb= memb_arr->at(i); - table->field[COLUMN_WSREP_MEMB_INDEX]->store(i, 0); - char uuid[40]; - wsrep_uuid_print(&memb.id, uuid, sizeof(uuid)); - table->field[COLUMN_WSREP_MEMB_UUID]->store(uuid, sizeof(uuid), + std::ostringstream os; + os << members[i].id(); + table->field[COLUMN_WSREP_MEMB_UUID]->store(os.str().c_str(), + os.str().length(), system_charset_info); - table->field[COLUMN_WSREP_MEMB_NAME]->store(memb.name, strlen(memb.name), + table->field[COLUMN_WSREP_MEMB_NAME]->store(members[i].name().c_str(), + members[i].name().length(), system_charset_info); - table->field[COLUMN_WSREP_MEMB_ADDRESS]->store(memb.incoming, - strlen(memb.incoming), + table->field[COLUMN_WSREP_MEMB_ADDRESS]->store(members[i].incoming().c_str(), + members[i].incoming().length(), system_charset_info); if (schema_table_store_record(thd, table)) @@ -177,35 +149,34 @@ static int wsrep_status_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) wsrep_config_state->lock(); - wsrep_view_info_t view= wsrep_config_state->get_view_info(); - wsrep_member_status_t status= wsrep_config_state->get_status(); + const wsrep::view& view= wsrep_config_state->get_view_info(); + enum wsrep::server_state::state status= wsrep_config_state->get_status(); TABLE *table= tables->table; table->field[COLUMN_WSREP_STATUS_NODE_INDEX] - ->store(view.my_idx, 0); + ->store(view.own_index(), 0); table->field[COLUMN_WSREP_STATUS_NODE_STATUS] - ->store(get_member_status(status), strlen(get_member_status(status)), + ->store(to_c_string(status), + strlen(to_c_string(status)), system_charset_info); table->field[COLUMN_WSREP_STATUS_CLUSTER_STATUS] - ->store(get_cluster_status(view.status), - strlen(get_cluster_status(view.status)), + ->store(to_c_string(view.status()), + strlen(to_c_string(view.status())), system_charset_info); - table->field[COLUMN_WSREP_STATUS_CLUSTER_SIZE]->store(view.memb_num, 0); + table->field[COLUMN_WSREP_STATUS_CLUSTER_SIZE]->store(view.members().size(), 0); - char uuid[40]; - wsrep_uuid_print(&view.state_id.uuid, uuid, sizeof(uuid)); + std::ostringstream os; + os << view.state_id().id(); table->field[COLUMN_WSREP_STATUS_CLUSTER_STATE_UUID] - ->store(uuid, sizeof(uuid), system_charset_info); + ->store(os.str().c_str(), os.str().length(), system_charset_info); table->field[COLUMN_WSREP_STATUS_CLUSTER_STATE_SEQNO] - ->store(view.state_id.seqno, 0); - table->field[COLUMN_WSREP_STATUS_CLUSTER_CONF_ID]->store(view.view, 0); - - const char *gap= (view.state_gap == true) ? "YES" : "NO"; - table->field[COLUMN_WSREP_STATUS_GAP]->store(gap, strlen(gap), - system_charset_info); - table->field[COLUMN_WSREP_STATUS_PROTO_VERSION]->store(view.proto_ver, 0); + ->store(view.state_id().seqno().get(), 0); + table->field[COLUMN_WSREP_STATUS_CLUSTER_CONF_ID] + ->store(view.view_seqno().get(), 0); + table->field[COLUMN_WSREP_STATUS_PROTO_VERSION] + ->store(view.protocol_version(), 0); if (schema_table_store_record(thd, table)) rc= 1; |