summaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'plugin')
-rw-r--r--plugin/audit_null/audit_null.c11
-rw-r--r--plugin/auth_dialog/CMakeLists.txt6
-rw-r--r--plugin/auth_dialog/dialog.c2
-rw-r--r--plugin/auth_ed25519/CMakeLists.txt32
-rw-r--r--plugin/auth_ed25519/README27
-rw-r--r--plugin/auth_ed25519/client_ed25519.c68
-rw-r--r--plugin/auth_ed25519/common.h23
-rw-r--r--plugin/auth_ed25519/crypto_hash_sha512.h2
-rw-r--r--plugin/auth_ed25519/crypto_int32.h5
-rw-r--r--plugin/auth_ed25519/crypto_int64.h5
-rw-r--r--plugin/auth_ed25519/crypto_sign.h13
-rw-r--r--plugin/auth_ed25519/crypto_uint32.h5
-rw-r--r--plugin/auth_ed25519/crypto_uint64.h5
-rw-r--r--plugin/auth_ed25519/crypto_verify.h1
-rw-r--r--plugin/auth_ed25519/crypto_verify_32.h2
-rw-r--r--plugin/auth_ed25519/ed25519-t.c55
-rw-r--r--plugin/auth_ed25519/ref10/api.h3
-rw-r--r--plugin/auth_ed25519/ref10/base.h1344
-rw-r--r--plugin/auth_ed25519/ref10/base2.h40
-rw-r--r--plugin/auth_ed25519/ref10/d.h1
-rw-r--r--plugin/auth_ed25519/ref10/d2.h1
-rw-r--r--plugin/auth_ed25519/ref10/fe.h56
-rw-r--r--plugin/auth_ed25519/ref10/fe_0.c19
-rw-r--r--plugin/auth_ed25519/ref10/fe_1.c19
-rw-r--r--plugin/auth_ed25519/ref10/fe_add.c57
-rw-r--r--plugin/auth_ed25519/ref10/fe_cmov.c63
-rw-r--r--plugin/auth_ed25519/ref10/fe_copy.c29
-rw-r--r--plugin/auth_ed25519/ref10/fe_frombytes.c73
-rw-r--r--plugin/auth_ed25519/ref10/fe_invert.c14
-rw-r--r--plugin/auth_ed25519/ref10/fe_isnegative.c16
-rw-r--r--plugin/auth_ed25519/ref10/fe_isnonzero.c19
-rw-r--r--plugin/auth_ed25519/ref10/fe_mul.c253
-rw-r--r--plugin/auth_ed25519/ref10/fe_neg.c45
-rw-r--r--plugin/auth_ed25519/ref10/fe_pow22523.c13
-rw-r--r--plugin/auth_ed25519/ref10/fe_sq.c149
-rw-r--r--plugin/auth_ed25519/ref10/fe_sq2.c160
-rw-r--r--plugin/auth_ed25519/ref10/fe_sub.c57
-rw-r--r--plugin/auth_ed25519/ref10/fe_tobytes.c119
-rw-r--r--plugin/auth_ed25519/ref10/ge.h95
-rw-r--r--plugin/auth_ed25519/ref10/ge_add.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_add.h97
-rw-r--r--plugin/auth_ed25519/ref10/ge_double_scalarmult.c96
-rw-r--r--plugin/auth_ed25519/ref10/ge_frombytes.c50
-rw-r--r--plugin/auth_ed25519/ref10/ge_madd.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_madd.h88
-rw-r--r--plugin/auth_ed25519/ref10/ge_msub.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_msub.h88
-rw-r--r--plugin/auth_ed25519/ref10/ge_p1p1_to_p2.c12
-rw-r--r--plugin/auth_ed25519/ref10/ge_p1p1_to_p3.c13
-rw-r--r--plugin/auth_ed25519/ref10/ge_p2_0.c8
-rw-r--r--plugin/auth_ed25519/ref10/ge_p2_dbl.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_p2_dbl.h73
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_0.c9
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_dbl.c12
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_to_cached.c17
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_to_p2.c12
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_tobytes.c14
-rw-r--r--plugin/auth_ed25519/ref10/ge_precomp_0.c8
-rw-r--r--plugin/auth_ed25519/ref10/ge_scalarmult_base.c105
-rw-r--r--plugin/auth_ed25519/ref10/ge_sub.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_sub.h97
-rw-r--r--plugin/auth_ed25519/ref10/ge_tobytes.c14
-rw-r--r--plugin/auth_ed25519/ref10/keypair.c23
-rw-r--r--plugin/auth_ed25519/ref10/open.c36
-rw-r--r--plugin/auth_ed25519/ref10/pow22523.h160
-rw-r--r--plugin/auth_ed25519/ref10/pow225521.h160
-rw-r--r--plugin/auth_ed25519/ref10/sc.h15
-rw-r--r--plugin/auth_ed25519/ref10/sc_muladd.c368
-rw-r--r--plugin/auth_ed25519/ref10/sc_reduce.c275
-rw-r--r--plugin/auth_ed25519/ref10/sign.c39
-rw-r--r--plugin/auth_ed25519/ref10/sqrtm1.h1
-rw-r--r--plugin/auth_ed25519/ref10/verify.c40
-rw-r--r--plugin/auth_ed25519/server_ed25519.c146
-rw-r--r--plugin/auth_examples/CMakeLists.txt2
-rw-r--r--plugin/auth_gssapi/CMakeLists.txt45
-rw-r--r--plugin/auth_gssapi/README.md129
-rw-r--r--plugin/auth_gssapi/client_plugin.cc112
-rw-r--r--plugin/auth_gssapi/cmake/FindGSSAPI.cmake98
-rw-r--r--plugin/auth_gssapi/common.h4
-rw-r--r--plugin/auth_gssapi/gssapi_client.cc127
-rw-r--r--plugin/auth_gssapi/gssapi_errmsg.cc75
-rw-r--r--plugin/auth_gssapi/gssapi_errmsg.h29
-rw-r--r--plugin/auth_gssapi/gssapi_server.cc253
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/basic.result20
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/basic.test46
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/suite.opt1
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm49
-rw-r--r--plugin/auth_gssapi/server_plugin.cc183
-rw-r--r--plugin/auth_gssapi/server_plugin.h51
-rw-r--r--plugin/auth_gssapi/sspi.h38
-rw-r--r--plugin/auth_gssapi/sspi_client.cc183
-rw-r--r--plugin/auth_gssapi/sspi_errmsg.cc150
-rw-r--r--plugin/auth_gssapi/sspi_server.cc317
-rw-r--r--plugin/auth_pam/CMakeLists.txt1
-rw-r--r--plugin/auth_pam/auth_pam.c54
-rw-r--r--plugin/auth_pam/mapper/pam_user_map.c170
-rw-r--r--plugin/auth_pipe/CMakeLists.txt3
-rw-r--r--plugin/auth_pipe/auth_pipe.c94
-rw-r--r--plugin/auth_socket/CMakeLists.txt3
-rw-r--r--plugin/auth_socket/auth_socket.c21
-rw-r--r--plugin/aws_key_management/CMakeLists.txt185
-rw-r--r--plugin/aws_key_management/aws_key_management_plugin.cc750
-rw-r--r--plugin/cracklib_password_check/CMakeLists.txt13
-rw-r--r--plugin/cracklib_password_check/cracklib_password_check.c84
-rw-r--r--plugin/daemon_example/CMakeLists.txt5
-rw-r--r--plugin/daemon_example/daemon_example.cc19
-rw-r--r--plugin/debug_key_management/CMakeLists.txt2
-rw-r--r--plugin/debug_key_management/debug_key_management_plugin.cc100
-rw-r--r--plugin/disks/CMakeLists.txt5
-rw-r--r--plugin/disks/README.txt86
-rw-r--r--plugin/disks/information_schema_disks.cc155
-rw-r--r--plugin/disks/mysql-test/disks/disks.result12
-rw-r--r--plugin/disks/mysql-test/disks/disks.test2
-rw-r--r--plugin/disks/mysql-test/disks/suite.opt1
-rw-r--r--plugin/disks/mysql-test/disks/suite.pm10
-rw-r--r--plugin/example_key_management/CMakeLists.txt2
-rw-r--r--plugin/example_key_management/example_key_management_plugin.cc170
-rw-r--r--plugin/feedback/CMakeLists.txt15
-rw-r--r--plugin/feedback/feedback.cc20
-rw-r--r--plugin/feedback/feedback.h1
-rw-r--r--plugin/feedback/sender_thread.cc9
-rw-r--r--plugin/feedback/url_http.cc2
-rw-r--r--plugin/feedback/utils.cc31
-rw-r--r--plugin/file_key_management/CMakeLists.txt4
-rw-r--r--plugin/file_key_management/file_key_management_plugin.cc201
-rw-r--r--plugin/file_key_management/parser.cc409
-rw-r--r--plugin/file_key_management/parser.h54
-rw-r--r--plugin/fulltext/plugin_example.c18
-rw-r--r--plugin/handler_socket/CMakeLists.txt6
-rw-r--r--plugin/handler_socket/client/hslongrun.cpp6
-rw-r--r--plugin/handler_socket/docs-en/about-handlersocket.en.txt2
-rw-r--r--plugin/handler_socket/docs-en/installation.en.txt9
-rw-r--r--plugin/handler_socket/docs-en/perl-client.en.txt16
-rw-r--r--plugin/handler_socket/docs-en/protocol.en.txt33
-rw-r--r--plugin/handler_socket/docs-ja/installation.ja.txt3
-rw-r--r--plugin/handler_socket/docs-ja/perl-client.ja.txt10
-rw-r--r--plugin/handler_socket/docs-ja/protocol.ja.txt256
-rw-r--r--plugin/handler_socket/handlersocket/database.cpp17
-rw-r--r--plugin/handler_socket/libhsclient/auto_file.hpp5
-rw-r--r--plugin/handler_socket/libhsclient/fatal.cpp8
-rw-r--r--plugin/handler_socket/libhsclient/fatal.hpp1
-rw-r--r--plugin/handler_socket/libhsclient/socket.cpp2
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.xs2
-rw-r--r--plugin/handler_socket/plug.in20
-rwxr-xr-xplugin/handler_socket/regtest/test_01_lib/run.sh2
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test14.pl2
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test17.pl2
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test19.pl2
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test24.expected2
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test24.pl35
-rw-r--r--plugin/locale_info/CMakeLists.txt5
-rw-r--r--plugin/locale_info/locale_info.cc122
-rw-r--r--plugin/metadata_lock_info/CMakeLists.txt3
-rw-r--r--plugin/metadata_lock_info/metadata_lock_info.cc182
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result10
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result13
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result13
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt2
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm11
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test6
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test8
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test5
-rw-r--r--plugin/qc_info/CMakeLists.txt5
-rw-r--r--plugin/qc_info/qc_info.cc122
-rw-r--r--plugin/query_response_time/CMakeLists.txt3
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/basic.result27
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/basic.test3
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.inc36
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.result392
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.test44
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time.inc41
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time.result1003
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time.test28
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/suite.opt1
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/suite.pm14
-rw-r--r--plugin/query_response_time/plugin.cc164
-rw-r--r--plugin/query_response_time/query_response_time.cc285
-rw-r--r--plugin/query_response_time/query_response_time.h67
-rw-r--r--plugin/semisync/CMakeLists.txt9
-rw-r--r--plugin/semisync/semisync.h5
-rw-r--r--plugin/semisync/semisync_master.cc22
-rw-r--r--plugin/semisync/semisync_master.h18
-rw-r--r--plugin/semisync/semisync_master_plugin.cc98
-rw-r--r--plugin/semisync/semisync_slave_plugin.cc11
-rw-r--r--plugin/server_audit/CMakeLists.txt5
-rw-r--r--plugin/server_audit/plugin_audit_v4.h2
-rw-r--r--plugin/server_audit/server_audit.c34
-rw-r--r--plugin/simple_password_check/CMakeLists.txt1
-rw-r--r--plugin/simple_password_check/simple_password_check.c116
-rw-r--r--plugin/sql_errlog/sql_errlog.c20
-rw-r--r--plugin/userstat/CMakeLists.txt4
-rw-r--r--plugin/userstat/client_stats.cc99
-rw-r--r--plugin/userstat/index_stats.cc72
-rw-r--r--plugin/userstat/table_stats.cc73
-rw-r--r--plugin/userstat/user_stats.cc56
-rw-r--r--plugin/userstat/userstat.cc82
-rw-r--r--plugin/win_auth_client/CMakeLists.txt2
-rw-r--r--plugin/win_auth_client/handshake_client.cc2
-rw-r--r--plugin/wsrep_info/CMakeLists.txt5
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/my.cnf33
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result17
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/suite.opt1
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/suite.pm48
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test23
-rw-r--r--plugin/wsrep_info/plugin.cc266
205 files changed, 13478 insertions, 363 deletions
diff --git a/plugin/audit_null/audit_null.c b/plugin/audit_null/audit_null.c
index 10088dd2881..58f9c3ef8e2 100644
--- a/plugin/audit_null/audit_null.c
+++ b/plugin/audit_null/audit_null.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2006, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2012, 2013, 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
@@ -174,10 +175,10 @@ static struct st_mysql_audit audit_null_descriptor=
static struct st_mysql_show_var simple_status[]=
{
- { "Audit_null_called", (char *) &ncalls, SHOW_INT },
- { "Audit_null_general_log", (char *) &ncalls_general_log, SHOW_INT },
- { "Audit_null_general_error", (char *) &ncalls_general_error, SHOW_INT },
- { "Audit_null_general_result", (char *) &ncalls_general_result, SHOW_INT },
+ { "called", (char *) &ncalls, SHOW_INT },
+ { "general_error", (char *) &ncalls_general_error, SHOW_INT },
+ { "general_log", (char *) &ncalls_general_log, SHOW_INT },
+ { "general_result", (char *) &ncalls_general_result, SHOW_INT },
{ 0, 0, 0}
};
diff --git a/plugin/auth_dialog/CMakeLists.txt b/plugin/auth_dialog/CMakeLists.txt
index 7bde18fbf5d..b612dd14fe2 100644
--- a/plugin/auth_dialog/CMakeLists.txt
+++ b/plugin/auth_dialog/CMakeLists.txt
@@ -14,5 +14,9 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+ADD_DEFINITIONS(-DNO_GET_TTY_PASSWORD)
+IF(LIBDL)
+ SET(LLDL LINK_LIBRARIES dl)
+ENDIF()
MYSQL_ADD_PLUGIN(dialog dialog.c ${CMAKE_SOURCE_DIR}/libmysql/get_password.c
- MODULE_ONLY COMPONENT SharedLibraries)
+ MODULE_ONLY CLIENT ${LLDL} COMPONENT ClientPlugins)
diff --git a/plugin/auth_dialog/dialog.c b/plugin/auth_dialog/dialog.c
index ac5029ce35e..3ea1da229e7 100644
--- a/plugin/auth_dialog/dialog.c
+++ b/plugin/auth_dialog/dialog.c
@@ -25,6 +25,8 @@
the answer back to the server. No encryption is involved,
the answers are sent in clear text.
*/
+#define _GNU_SOURCE 1 /* for RTLD_DEFAULT */
+
#include <my_global.h>
#include <mysql/client_plugin.h>
#include <mysql.h>
diff --git a/plugin/auth_ed25519/CMakeLists.txt b/plugin/auth_ed25519/CMakeLists.txt
new file mode 100644
index 00000000000..73d8eeb208b
--- /dev/null
+++ b/plugin/auth_ed25519/CMakeLists.txt
@@ -0,0 +1,32 @@
+SET(REF10_SOURCES
+ ref10/fe_0.c ref10/fe_1.c ref10/fe_add.c ref10/fe_cmov.c ref10/fe_copy.c
+ ref10/fe_frombytes.c ref10/fe_invert.c ref10/fe_isnegative.c
+ ref10/fe_isnonzero.c ref10/fe_mul.c ref10/fe_neg.c ref10/fe_pow22523.c
+ ref10/fe_sq.c ref10/fe_sq2.c ref10/fe_sub.c ref10/fe_tobytes.c
+ ref10/ge_add.c ref10/ge_double_scalarmult.c ref10/ge_frombytes.c
+ ref10/ge_madd.c ref10/ge_msub.c ref10/ge_p1p1_to_p2.c
+ ref10/ge_p1p1_to_p3.c ref10/ge_p2_0.c ref10/ge_p2_dbl.c ref10/ge_p3_0.c
+ ref10/ge_p3_dbl.c ref10/ge_p3_to_cached.c ref10/ge_p3_to_p2.c
+ ref10/ge_p3_tobytes.c ref10/ge_precomp_0.c ref10/ge_scalarmult_base.c
+ ref10/ge_sub.c ref10/ge_tobytes.c ref10/keypair.c ref10/open.c
+ ref10/sc_muladd.c ref10/sc_reduce.c ref10/sign.c ref10/verify.c)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+ADD_CONVENIENCE_LIBRARY(ref10 ${REF10_SOURCES})
+IF(MSVC)
+ # Silence conversion (integer truncantion) warnings from reference code
+ SET_SOURCE_FILES_PROPERTIES(${REF10_SOURCES} PROPERTY COMPILE_FLAGS "/wd4244 /wd4146")
+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)
+
+# client plugin and unit test ed25519-t can use the library
+MYSQL_ADD_PLUGIN(client_ed25519 client_ed25519.c MODULE_ONLY
+ CLIENT LINK_LIBRARIES mysys_ssl ref10 COMPONENT ClientPlugins)
+
+IF(WITH_UNIT_TESTS)
+ MY_ADD_TESTS(ed25519 LINK_LIBRARIES mysys ref10)
+ENDIF()
diff --git a/plugin/auth_ed25519/README b/plugin/auth_ed25519/README
new file mode 100644
index 00000000000..e65a33e6019
--- /dev/null
+++ b/plugin/auth_ed25519/README
@@ -0,0 +1,27 @@
+This plugin uses public domain ed25519 code
+by Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, Bo-Yin Yang.
+
+It is "ref10" implementation from the SUPERCOP:
+https://bench.cr.yp.to/supercop.html
+
+OpenSSH also uses ed25519 from SUPERCOP, but "ref" implementation.
+
+There are four ed25519 implementations in SUPERCOP, ref10 is faster then ref,
+and there are two that are even faster, written in amd64 assembler.
+Benchmarks are here: https://bench.cr.yp.to/impl-sign/ed25519.html
+
+==============================
+MariaDB changes:
+
+API functions were simplified to better fit our use case:
+* crypto_sign_open() does not return the verified message, only the
+ result of the verification (passed/failed)
+* no secret key is generated explicitly, user specified password is used
+ as a source of randomness instead (SHA512("user password")).
+* lengths are not returned, where they're known in advance
+ (e.g. from crypto_sign()).
+* crypto_sign() does not take the public key as an argument, but
+ generates it on the fly (we used to generate public key before
+ crypto_sign(), doing it internally avoids double work).
+
+See the changes done in this commit.
diff --git a/plugin/auth_ed25519/client_ed25519.c b/plugin/auth_ed25519/client_ed25519.c
new file mode 100644
index 00000000000..5222da8c7e8
--- /dev/null
+++ b/plugin/auth_ed25519/client_ed25519.c
@@ -0,0 +1,68 @@
+/*
+ Copyright (c) 2017, 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
+ 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 02110-1335 USA */
+
+/************************** CLIENT *************************************/
+
+#include <stdlib.h>
+#include "common.h"
+#include <mysql/client_plugin.h>
+#include <errmsg.h>
+
+#if !defined(__attribute__) && !defined(__GNUC__)
+#define __attribute__(A)
+#endif
+
+static int do_auth(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ unsigned char reply[CRYPTO_BYTES + NONCE_BYTES], *pkt;
+ int pkt_len;
+
+ /* read the nonce */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) != NONCE_BYTES)
+ return CR_SERVER_HANDSHAKE_ERR;
+
+ /* sign the nonce */
+ crypto_sign(reply, pkt, NONCE_BYTES,
+ (unsigned char*)mysql->passwd, strlen(mysql->passwd));
+
+ /* send the signature */
+ if (vio->write_packet(vio, reply, CRYPTO_BYTES))
+ return CR_ERROR;
+
+ return CR_OK;
+}
+
+static int init_client(char *unused1 __attribute__((unused)),
+ size_t unused2 __attribute__((unused)),
+ int unused3 __attribute__((unused)),
+ va_list unused4 __attribute__((unused)))
+{
+ return 0;
+}
+
+mysql_declare_client_plugin(AUTHENTICATION)
+ "client_ed25519",
+ "Sergei Golubchik",
+ "Elliptic curve ED25519 based authentication",
+ {0,1,0},
+ "GPL",
+ NULL,
+ init_client,
+ NULL,
+ NULL,
+ do_auth,
+mysql_end_client_plugin;
+
diff --git a/plugin/auth_ed25519/common.h b/plugin/auth_ed25519/common.h
new file mode 100644
index 00000000000..963a8afb421
--- /dev/null
+++ b/plugin/auth_ed25519/common.h
@@ -0,0 +1,23 @@
+/*
+ Copyright (c) 2017, 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
+ 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 02110-1335 USA */
+
+#include <mysql.h>
+#include <string.h>
+
+#include "ref10/api.h"
+#include "crypto_sign.h"
+
+#define NONCE_BYTES 32
diff --git a/plugin/auth_ed25519/crypto_hash_sha512.h b/plugin/auth_ed25519/crypto_hash_sha512.h
new file mode 100644
index 00000000000..a1be896f911
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_hash_sha512.h
@@ -0,0 +1,2 @@
+#include <mysql/service_sha2.h>
+#define crypto_hash_sha512(DST,SRC,SLEN) my_sha512(DST,(char*)(SRC),SLEN)
diff --git a/plugin/auth_ed25519/crypto_int32.h b/plugin/auth_ed25519/crypto_int32.h
new file mode 100644
index 00000000000..642fca05767
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_int32.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+#include <sys/types.h>
+typedef int32_t crypto_int32;
+
+#define select ed25519_select
diff --git a/plugin/auth_ed25519/crypto_int64.h b/plugin/auth_ed25519/crypto_int64.h
new file mode 100644
index 00000000000..a308e406721
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_int64.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+#include <sys/types.h>
+typedef int64_t crypto_int64;
+
+#define select ed25519_select
diff --git a/plugin/auth_ed25519/crypto_sign.h b/plugin/auth_ed25519/crypto_sign.h
new file mode 100644
index 00000000000..e12a8c71f6e
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_sign.h
@@ -0,0 +1,13 @@
+int crypto_sign_keypair(
+ unsigned char *pk,
+ unsigned char *pw, unsigned long long pwlen
+);
+int crypto_sign(
+ unsigned char *sm,
+ const unsigned char *m, unsigned long long mlen,
+ const unsigned char *pw, unsigned long long pwlen
+);
+int crypto_sign_open(
+ unsigned char *sm, unsigned long long smlen,
+ const unsigned char *pk
+);
diff --git a/plugin/auth_ed25519/crypto_uint32.h b/plugin/auth_ed25519/crypto_uint32.h
new file mode 100644
index 00000000000..ab2977caac2
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_uint32.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+#include <sys/types.h>
+typedef uint32_t crypto_uint32;
+
+#define select ed25519_select
diff --git a/plugin/auth_ed25519/crypto_uint64.h b/plugin/auth_ed25519/crypto_uint64.h
new file mode 100644
index 00000000000..029c68191ab
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_uint64.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+#include <sys/types.h>
+typedef uint64_t crypto_uint64;
+
+#define select ed25519_select
diff --git a/plugin/auth_ed25519/crypto_verify.h b/plugin/auth_ed25519/crypto_verify.h
new file mode 100644
index 00000000000..33e11b1edb0
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_verify.h
@@ -0,0 +1 @@
+int crypto_verify(const unsigned char *x,const unsigned char *y);
diff --git a/plugin/auth_ed25519/crypto_verify_32.h b/plugin/auth_ed25519/crypto_verify_32.h
new file mode 100644
index 00000000000..d8235b75c79
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_verify_32.h
@@ -0,0 +1,2 @@
+#define crypto_verify_32 crypto_verify
+int crypto_verify(const unsigned char *x,const unsigned char *y);
diff --git a/plugin/auth_ed25519/ed25519-t.c b/plugin/auth_ed25519/ed25519-t.c
new file mode 100644
index 00000000000..4373e59a154
--- /dev/null
+++ b/plugin/auth_ed25519/ed25519-t.c
@@ -0,0 +1,55 @@
+/*
+ Copyright (c) 2017, 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
+ 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 02110-1335 USA */
+
+#include <tap.h>
+#include <m_string.h>
+#include "common.h"
+
+int main()
+{
+ uchar pk[CRYPTO_PUBLICKEYBYTES];
+ uchar foobar_pk[CRYPTO_PUBLICKEYBYTES]= {170, 253, 166, 27, 161, 214, 10,
+ 236, 183, 217, 41, 91, 231, 24, 85, 225, 49, 210, 181, 236, 13, 207, 101,
+ 72, 53, 83, 219, 130, 79, 151, 0, 159};
+ uchar foobar_sign[CRYPTO_BYTES]= {232, 61, 201, 63, 67, 63, 51, 53, 86, 73,
+ 238, 35, 170, 117, 146, 214, 26, 17, 35, 9, 8, 132, 245, 141, 48, 99, 66,
+ 58, 36, 228, 48, 84, 115, 254, 187, 168, 88, 162, 249, 57, 35, 85, 79, 238,
+ 167, 106, 68, 117, 56, 135, 171, 47, 20, 14, 133, 79, 15, 229, 124, 160,
+ 176, 100, 138, 14};
+
+ uchar nonce[NONCE_BYTES];
+ uchar reply[NONCE_BYTES+CRYPTO_BYTES];
+ int r;
+
+ plan(4);
+
+ crypto_sign_keypair(pk, USTRING_WITH_LEN("foobar"));
+ ok(!memcmp(pk, foobar_pk, CRYPTO_PUBLICKEYBYTES), "foobar pk");
+
+ memset(nonce, 'A', sizeof(nonce));
+ crypto_sign(reply, nonce, sizeof(nonce), USTRING_WITH_LEN("foobar"));
+ ok(!memcmp(reply, foobar_sign, CRYPTO_BYTES), "foobar sign");
+
+ r= crypto_sign_open(reply, sizeof(reply), pk);
+ ok(!r, "good nonce");
+
+ crypto_sign(reply, nonce, sizeof(nonce), USTRING_WITH_LEN("foobar"));
+ reply[CRYPTO_BYTES + 10]='B';
+ r= crypto_sign_open(reply, sizeof(reply), pk);
+ ok(r, "bad nonce");
+
+ return exit_status();
+}
diff --git a/plugin/auth_ed25519/ref10/api.h b/plugin/auth_ed25519/ref10/api.h
new file mode 100644
index 00000000000..9f1db7e566a
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/api.h
@@ -0,0 +1,3 @@
+#define CRYPTO_PUBLICKEYBYTES 32
+#define CRYPTO_BYTES 64
+#define CRYPTO_DETERMINISTIC 1
diff --git a/plugin/auth_ed25519/ref10/base.h b/plugin/auth_ed25519/ref10/base.h
new file mode 100644
index 00000000000..573bd8a05c6
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/base.h
@@ -0,0 +1,1344 @@
+{
+ {
+ { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+ { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+ { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+ { -12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303 },
+ { -21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081 },
+ { 26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697 },
+ },
+ {
+ { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+ { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+ { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+ { -17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540 },
+ { 23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397 },
+ { 7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325 },
+ },
+ {
+ { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+ { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+ { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+ { -15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777 },
+ { -8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737 },
+ { -18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652 },
+ },
+ {
+ { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+ { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+ { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+ { 14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726 },
+ { -7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955 },
+ { 27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425 },
+ },
+},
+{
+ {
+ { -13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171 },
+ { 27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510 },
+ { 17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660 },
+ },
+ {
+ { -10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639 },
+ { 29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963 },
+ { 5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950 },
+ },
+ {
+ { -27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568 },
+ { 12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335 },
+ { 25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628 },
+ },
+ {
+ { -26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007 },
+ { -2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772 },
+ { -22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653 },
+ },
+ {
+ { 2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567 },
+ { 13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686 },
+ { 21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372 },
+ },
+ {
+ { -13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887 },
+ { -23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954 },
+ { -29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953 },
+ },
+ {
+ { 24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833 },
+ { -16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532 },
+ { -22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876 },
+ },
+ {
+ { 2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268 },
+ { 33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214 },
+ { 1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038 },
+ },
+},
+{
+ {
+ { 6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800 },
+ { 4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645 },
+ { -4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664 },
+ },
+ {
+ { 1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933 },
+ { -25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182 },
+ { -17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222 },
+ },
+ {
+ { -18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991 },
+ { 20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880 },
+ { 9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092 },
+ },
+ {
+ { -16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295 },
+ { 19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788 },
+ { 8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553 },
+ },
+ {
+ { -15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026 },
+ { 11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347 },
+ { -18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033 },
+ },
+ {
+ { -23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395 },
+ { -27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278 },
+ { 1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890 },
+ },
+ {
+ { 32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995 },
+ { -30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596 },
+ { -11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891 },
+ },
+ {
+ { 31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060 },
+ { 11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608 },
+ { -20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606 },
+ },
+},
+{
+ {
+ { 7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389 },
+ { -19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016 },
+ { -11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341 },
+ },
+ {
+ { -22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505 },
+ { 14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553 },
+ { -28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655 },
+ },
+ {
+ { 15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220 },
+ { 12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631 },
+ { -4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099 },
+ },
+ {
+ { 26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556 },
+ { 14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749 },
+ { 236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930 },
+ },
+ {
+ { 1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391 },
+ { 5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253 },
+ { 20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066 },
+ },
+ {
+ { 24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958 },
+ { -11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082 },
+ { -28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383 },
+ },
+ {
+ { -30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521 },
+ { -11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807 },
+ { 23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948 },
+ },
+ {
+ { 9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134 },
+ { -32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455 },
+ { 27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629 },
+ },
+},
+{
+ {
+ { -8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069 },
+ { -32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746 },
+ { 24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919 },
+ },
+ {
+ { 11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837 },
+ { 8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906 },
+ { -28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771 },
+ },
+ {
+ { -25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817 },
+ { 10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098 },
+ { 10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409 },
+ },
+ {
+ { -12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504 },
+ { -26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727 },
+ { 28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420 },
+ },
+ {
+ { -32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003 },
+ { -1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605 },
+ { -30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384 },
+ },
+ {
+ { -26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701 },
+ { -23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683 },
+ { 29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708 },
+ },
+ {
+ { -3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563 },
+ { -19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260 },
+ { -5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387 },
+ },
+ {
+ { -19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672 },
+ { 23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686 },
+ { -24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665 },
+ },
+},
+{
+ {
+ { 11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182 },
+ { -31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277 },
+ { 14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628 },
+ },
+ {
+ { -4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474 },
+ { -26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539 },
+ { -25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822 },
+ },
+ {
+ { -10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970 },
+ { 19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756 },
+ { -24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508 },
+ },
+ {
+ { -26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683 },
+ { -10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655 },
+ { -20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158 },
+ },
+ {
+ { -4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125 },
+ { -15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839 },
+ { -20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664 },
+ },
+ {
+ { 27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294 },
+ { -18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899 },
+ { -11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070 },
+ },
+ {
+ { 3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294 },
+ { -15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949 },
+ { -21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083 },
+ },
+ {
+ { 31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420 },
+ { -5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940 },
+ { 29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396 },
+ },
+},
+{
+ {
+ { -12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567 },
+ { 20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127 },
+ { -16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294 },
+ },
+ {
+ { -12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887 },
+ { 22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964 },
+ { 16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195 },
+ },
+ {
+ { 9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244 },
+ { 24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999 },
+ { -1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762 },
+ },
+ {
+ { -18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274 },
+ { -33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236 },
+ { -16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605 },
+ },
+ {
+ { -13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761 },
+ { -22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884 },
+ { -6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482 },
+ },
+ {
+ { -24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638 },
+ { -11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490 },
+ { -32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170 },
+ },
+ {
+ { 5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736 },
+ { 10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124 },
+ { -17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392 },
+ },
+ {
+ { 8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029 },
+ { 6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048 },
+ { 28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958 },
+ },
+},
+{
+ {
+ { 24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593 },
+ { 26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071 },
+ { -11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692 },
+ },
+ {
+ { 11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687 },
+ { -160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441 },
+ { -20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001 },
+ },
+ {
+ { -938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460 },
+ { -19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007 },
+ { -21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762 },
+ },
+ {
+ { 15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005 },
+ { -9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674 },
+ { 4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035 },
+ },
+ {
+ { 7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590 },
+ { -2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957 },
+ { -30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812 },
+ },
+ {
+ { 33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740 },
+ { -18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122 },
+ { -27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158 },
+ },
+ {
+ { 8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885 },
+ { 26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140 },
+ { 19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857 },
+ },
+ {
+ { 801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155 },
+ { 19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260 },
+ { 19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483 },
+ },
+},
+{
+ {
+ { -3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677 },
+ { 32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815 },
+ { 22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751 },
+ },
+ {
+ { -16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203 },
+ { -11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208 },
+ { 1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230 },
+ },
+ {
+ { 16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850 },
+ { -21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389 },
+ { -9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968 },
+ },
+ {
+ { -11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689 },
+ { 14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880 },
+ { 5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304 },
+ },
+ {
+ { 30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632 },
+ { -3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412 },
+ { 20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566 },
+ },
+ {
+ { -20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038 },
+ { -26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232 },
+ { -1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943 },
+ },
+ {
+ { 17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856 },
+ { 23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738 },
+ { 15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971 },
+ },
+ {
+ { -27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718 },
+ { -13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697 },
+ { -11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883 },
+ },
+},
+{
+ {
+ { 5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912 },
+ { -26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358 },
+ { 3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849 },
+ },
+ {
+ { 29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307 },
+ { -14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977 },
+ { -6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335 },
+ },
+ {
+ { -29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644 },
+ { -22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616 },
+ { -27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735 },
+ },
+ {
+ { -21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099 },
+ { 29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341 },
+ { -936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336 },
+ },
+ {
+ { -23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646 },
+ { 31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425 },
+ { -17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388 },
+ },
+ {
+ { -31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743 },
+ { -16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822 },
+ { -8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462 },
+ },
+ {
+ { 18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985 },
+ { 9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702 },
+ { -22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797 },
+ },
+ {
+ { 21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293 },
+ { 27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100 },
+ { 19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688 },
+ },
+},
+{
+ {
+ { 12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186 },
+ { 2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610 },
+ { -2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707 },
+ },
+ {
+ { 7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220 },
+ { 915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025 },
+ { 32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044 },
+ },
+ {
+ { 32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992 },
+ { -4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027 },
+ { 21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197 },
+ },
+ {
+ { 8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901 },
+ { 31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952 },
+ { 19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878 },
+ },
+ {
+ { -28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390 },
+ { 32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730 },
+ { 2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730 },
+ },
+ {
+ { -19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180 },
+ { -30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272 },
+ { -15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715 },
+ },
+ {
+ { -22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970 },
+ { -31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772 },
+ { -17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865 },
+ },
+ {
+ { 15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750 },
+ { 20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373 },
+ { 32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348 },
+ },
+},
+{
+ {
+ { 9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144 },
+ { -22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195 },
+ { 5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086 },
+ },
+ {
+ { -13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684 },
+ { -8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518 },
+ { -2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233 },
+ },
+ {
+ { -5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793 },
+ { -2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794 },
+ { 580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435 },
+ },
+ {
+ { 23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921 },
+ { 13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518 },
+ { 2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563 },
+ },
+ {
+ { 14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278 },
+ { -27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024 },
+ { 4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030 },
+ },
+ {
+ { 10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783 },
+ { 27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717 },
+ { 6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844 },
+ },
+ {
+ { 14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333 },
+ { 16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048 },
+ { 22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760 },
+ },
+ {
+ { -4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760 },
+ { -15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757 },
+ { -2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112 },
+ },
+},
+{
+ {
+ { -19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468 },
+ { 3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184 },
+ { 10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289 },
+ },
+ {
+ { 15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066 },
+ { 24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882 },
+ { 13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226 },
+ },
+ {
+ { 16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101 },
+ { 29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279 },
+ { -6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811 },
+ },
+ {
+ { 27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709 },
+ { 20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714 },
+ { -2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121 },
+ },
+ {
+ { 9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464 },
+ { 12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847 },
+ { 13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400 },
+ },
+ {
+ { 4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414 },
+ { -15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158 },
+ { 17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045 },
+ },
+ {
+ { -461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415 },
+ { -5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459 },
+ { -31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079 },
+ },
+ {
+ { 21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412 },
+ { -20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743 },
+ { -14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836 },
+ },
+},
+{
+ {
+ { 12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022 },
+ { 18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429 },
+ { -6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065 },
+ },
+ {
+ { 30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861 },
+ { 10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000 },
+ { -33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101 },
+ },
+ {
+ { 32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815 },
+ { 29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642 },
+ { 10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966 },
+ },
+ {
+ { 25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574 },
+ { -21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742 },
+ { -18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689 },
+ },
+ {
+ { 12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020 },
+ { -10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772 },
+ { 3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982 },
+ },
+ {
+ { -14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953 },
+ { -16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218 },
+ { -17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265 },
+ },
+ {
+ { 29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073 },
+ { -3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325 },
+ { -11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798 },
+ },
+ {
+ { -4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870 },
+ { -7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863 },
+ { -13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927 },
+ },
+},
+{
+ {
+ { -2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267 },
+ { -9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663 },
+ { 22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862 },
+ },
+ {
+ { -25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673 },
+ { 15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943 },
+ { 15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020 },
+ },
+ {
+ { -4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238 },
+ { 11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064 },
+ { 14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795 },
+ },
+ {
+ { 15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052 },
+ { -10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904 },
+ { 29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531 },
+ },
+ {
+ { -13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979 },
+ { -5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841 },
+ { 10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431 },
+ },
+ {
+ { 10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324 },
+ { -31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940 },
+ { 10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320 },
+ },
+ {
+ { -15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184 },
+ { 14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114 },
+ { 30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878 },
+ },
+ {
+ { 12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784 },
+ { -2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091 },
+ { -16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585 },
+ },
+},
+{
+ {
+ { -8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208 },
+ { 10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864 },
+ { 17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661 },
+ },
+ {
+ { 7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233 },
+ { 26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212 },
+ { -12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525 },
+ },
+ {
+ { -24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068 },
+ { 9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397 },
+ { -8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988 },
+ },
+ {
+ { 5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889 },
+ { 32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038 },
+ { 14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697 },
+ },
+ {
+ { 20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875 },
+ { -25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905 },
+ { -25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656 },
+ },
+ {
+ { 11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818 },
+ { 27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714 },
+ { 10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203 },
+ },
+ {
+ { 20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931 },
+ { -30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024 },
+ { -23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084 },
+ },
+ {
+ { -1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204 },
+ { 20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817 },
+ { 27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667 },
+ },
+},
+{
+ {
+ { 11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504 },
+ { -12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768 },
+ { -19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255 },
+ },
+ {
+ { 6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790 },
+ { 1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438 },
+ { -22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333 },
+ },
+ {
+ { 17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971 },
+ { 31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905 },
+ { 29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409 },
+ },
+ {
+ { 12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409 },
+ { 6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499 },
+ { -8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363 },
+ },
+ {
+ { 28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664 },
+ { -11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324 },
+ { -21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940 },
+ },
+ {
+ { 13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990 },
+ { -17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914 },
+ { -25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290 },
+ },
+ {
+ { 24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257 },
+ { -6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433 },
+ { -16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236 },
+ },
+ {
+ { -12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045 },
+ { 11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093 },
+ { -1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347 },
+ },
+},
+{
+ {
+ { -28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191 },
+ { -15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507 },
+ { -12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906 },
+ },
+ {
+ { 3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018 },
+ { -16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109 },
+ { -23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926 },
+ },
+ {
+ { -24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528 },
+ { 8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625 },
+ { -32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286 },
+ },
+ {
+ { 2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033 },
+ { 27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866 },
+ { 21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896 },
+ },
+ {
+ { 30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075 },
+ { 26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347 },
+ { -22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437 },
+ },
+ {
+ { -5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165 },
+ { -18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588 },
+ { -32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193 },
+ },
+ {
+ { -19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017 },
+ { -28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883 },
+ { 21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961 },
+ },
+ {
+ { 8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043 },
+ { 29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663 },
+ { -20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362 },
+ },
+},
+{
+ {
+ { -33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860 },
+ { 2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466 },
+ { -24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063 },
+ },
+ {
+ { -26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997 },
+ { -1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295 },
+ { -13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369 },
+ },
+ {
+ { 9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385 },
+ { 18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109 },
+ { 2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906 },
+ },
+ {
+ { 4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424 },
+ { -19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185 },
+ { 7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962 },
+ },
+ {
+ { -7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325 },
+ { 10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593 },
+ { 696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404 },
+ },
+ {
+ { -11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644 },
+ { 17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801 },
+ { 26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804 },
+ },
+ {
+ { -31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884 },
+ { -586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577 },
+ { -9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849 },
+ },
+ {
+ { 32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473 },
+ { -8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644 },
+ { -2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319 },
+ },
+},
+{
+ {
+ { -11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599 },
+ { -9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768 },
+ { -27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084 },
+ },
+ {
+ { -27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328 },
+ { -15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369 },
+ { 20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920 },
+ },
+ {
+ { 12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815 },
+ { -32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025 },
+ { -21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397 },
+ },
+ {
+ { -20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448 },
+ { 6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981 },
+ { 30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165 },
+ },
+ {
+ { 32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501 },
+ { 17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073 },
+ { -1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861 },
+ },
+ {
+ { 14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845 },
+ { -1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211 },
+ { 18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870 },
+ },
+ {
+ { 10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096 },
+ { 33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803 },
+ { -32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168 },
+ },
+ {
+ { 30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965 },
+ { -14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505 },
+ { 18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598 },
+ },
+},
+{
+ {
+ { 5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782 },
+ { 5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900 },
+ { -31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479 },
+ },
+ {
+ { -12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208 },
+ { 8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232 },
+ { 17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719 },
+ },
+ {
+ { 16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271 },
+ { -4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326 },
+ { -8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132 },
+ },
+ {
+ { 14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300 },
+ { 8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570 },
+ { 15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670 },
+ },
+ {
+ { -2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994 },
+ { -12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913 },
+ { 31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317 },
+ },
+ {
+ { -25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730 },
+ { 842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096 },
+ { -4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078 },
+ },
+ {
+ { -15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411 },
+ { -19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905 },
+ { -9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654 },
+ },
+ {
+ { -28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870 },
+ { -23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498 },
+ { 12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579 },
+ },
+},
+{
+ {
+ { 14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677 },
+ { 10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647 },
+ { -2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743 },
+ },
+ {
+ { -25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468 },
+ { 21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375 },
+ { -25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155 },
+ },
+ {
+ { 6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725 },
+ { -12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612 },
+ { -10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943 },
+ },
+ {
+ { -30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944 },
+ { 30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928 },
+ { 9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406 },
+ },
+ {
+ { 22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139 },
+ { -8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963 },
+ { -31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693 },
+ },
+ {
+ { 1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734 },
+ { -448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680 },
+ { -24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410 },
+ },
+ {
+ { -9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931 },
+ { -16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654 },
+ { 22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710 },
+ },
+ {
+ { 29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180 },
+ { -26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684 },
+ { -10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895 },
+ },
+},
+{
+ {
+ { 22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501 },
+ { -11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413 },
+ { 6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880 },
+ },
+ {
+ { -8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874 },
+ { 22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962 },
+ { -7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899 },
+ },
+ {
+ { 21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152 },
+ { 9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063 },
+ { 7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080 },
+ },
+ {
+ { -9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146 },
+ { -17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183 },
+ { -19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133 },
+ },
+ {
+ { -32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421 },
+ { -3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622 },
+ { -4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197 },
+ },
+ {
+ { 2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663 },
+ { 31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753 },
+ { 4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755 },
+ },
+ {
+ { -9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862 },
+ { -26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118 },
+ { 26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171 },
+ },
+ {
+ { 15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380 },
+ { 16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824 },
+ { 28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270 },
+ },
+},
+{
+ {
+ { -817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438 },
+ { -31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584 },
+ { -594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562 },
+ },
+ {
+ { 30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471 },
+ { 18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610 },
+ { 19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269 },
+ },
+ {
+ { -30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650 },
+ { 14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369 },
+ { 19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461 },
+ },
+ {
+ { 30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462 },
+ { -5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793 },
+ { -2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218 },
+ },
+ {
+ { -24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226 },
+ { 18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019 },
+ { -15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037 },
+ },
+ {
+ { 31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171 },
+ { -17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132 },
+ { -28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841 },
+ },
+ {
+ { 21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181 },
+ { -33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210 },
+ { -1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040 },
+ },
+ {
+ { 3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935 },
+ { 24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105 },
+ { -28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814 },
+ },
+},
+{
+ {
+ { 793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852 },
+ { 5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581 },
+ { -4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646 },
+ },
+ {
+ { 10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844 },
+ { 10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025 },
+ { 27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453 },
+ },
+ {
+ { -23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068 },
+ { 4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192 },
+ { -17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921 },
+ },
+ {
+ { -9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259 },
+ { -12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426 },
+ { -5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072 },
+ },
+ {
+ { -17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305 },
+ { 13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832 },
+ { 28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943 },
+ },
+ {
+ { -16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011 },
+ { 24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447 },
+ { 17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494 },
+ },
+ {
+ { -28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245 },
+ { -20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859 },
+ { 28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915 },
+ },
+ {
+ { 16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707 },
+ { 10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848 },
+ { -11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224 },
+ },
+},
+{
+ {
+ { -25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391 },
+ { 15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215 },
+ { -23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101 },
+ },
+ {
+ { 23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713 },
+ { 21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849 },
+ { -7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930 },
+ },
+ {
+ { -29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940 },
+ { -21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031 },
+ { -17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404 },
+ },
+ {
+ { -25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243 },
+ { -23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116 },
+ { -24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525 },
+ },
+ {
+ { -23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509 },
+ { -10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883 },
+ { 15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865 },
+ },
+ {
+ { -3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660 },
+ { 4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273 },
+ { -28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138 },
+ },
+ {
+ { -25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560 },
+ { -10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135 },
+ { 2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941 },
+ },
+ {
+ { -4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739 },
+ { 18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756 },
+ { -30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819 },
+ },
+},
+{
+ {
+ { -6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347 },
+ { -27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028 },
+ { 21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075 },
+ },
+ {
+ { 16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799 },
+ { -2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609 },
+ { -25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817 },
+ },
+ {
+ { -23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989 },
+ { -30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523 },
+ { 4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278 },
+ },
+ {
+ { 31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045 },
+ { 19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377 },
+ { 24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480 },
+ },
+ {
+ { 17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016 },
+ { 510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426 },
+ { 18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525 },
+ },
+ {
+ { 13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396 },
+ { 9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080 },
+ { 12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892 },
+ },
+ {
+ { 15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275 },
+ { 11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074 },
+ { 20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140 },
+ },
+ {
+ { -16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717 },
+ { -1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101 },
+ { 24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127 },
+ },
+},
+{
+ {
+ { -12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632 },
+ { -26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415 },
+ { -31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160 },
+ },
+ {
+ { 31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876 },
+ { 22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625 },
+ { -15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478 },
+ },
+ {
+ { 27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164 },
+ { 26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595 },
+ { -7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248 },
+ },
+ {
+ { -16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858 },
+ { 15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193 },
+ { 8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184 },
+ },
+ {
+ { -18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942 },
+ { -1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635 },
+ { 21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948 },
+ },
+ {
+ { 11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935 },
+ { -25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415 },
+ { -15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416 },
+ },
+ {
+ { -7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018 },
+ { 4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778 },
+ { 366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659 },
+ },
+ {
+ { -24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385 },
+ { 18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503 },
+ { 476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329 },
+ },
+},
+{
+ {
+ { 20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056 },
+ { -13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838 },
+ { 24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948 },
+ },
+ {
+ { -3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691 },
+ { -15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118 },
+ { -23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517 },
+ },
+ {
+ { -20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269 },
+ { -6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904 },
+ { -23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589 },
+ },
+ {
+ { -28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193 },
+ { -7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910 },
+ { -30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930 },
+ },
+ {
+ { -7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667 },
+ { 25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481 },
+ { -9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876 },
+ },
+ {
+ { 22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640 },
+ { -8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278 },
+ { -21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112 },
+ },
+ {
+ { 26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272 },
+ { 17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012 },
+ { -10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221 },
+ },
+ {
+ { 30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046 },
+ { 13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345 },
+ { -19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310 },
+ },
+},
+{
+ {
+ { 19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937 },
+ { 31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636 },
+ { -9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008 },
+ },
+ {
+ { -2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429 },
+ { -15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576 },
+ { 31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066 },
+ },
+ {
+ { -9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490 },
+ { -12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104 },
+ { 33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053 },
+ },
+ {
+ { 31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275 },
+ { -20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511 },
+ { 22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095 },
+ },
+ {
+ { -28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439 },
+ { 23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939 },
+ { -23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424 },
+ },
+ {
+ { 2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310 },
+ { 3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608 },
+ { -32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079 },
+ },
+ {
+ { -23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101 },
+ { 21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418 },
+ { 18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576 },
+ },
+ {
+ { 30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356 },
+ { 9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996 },
+ { -26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099 },
+ },
+},
+{
+ {
+ { -26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728 },
+ { -13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658 },
+ { -10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242 },
+ },
+ {
+ { -21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001 },
+ { -4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766 },
+ { 18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373 },
+ },
+ {
+ { 26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458 },
+ { -17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628 },
+ { -13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657 },
+ },
+ {
+ { -23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062 },
+ { 25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616 },
+ { 31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014 },
+ },
+ {
+ { 24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383 },
+ { -25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814 },
+ { -20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718 },
+ },
+ {
+ { 30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417 },
+ { 2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222 },
+ { 33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444 },
+ },
+ {
+ { -20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597 },
+ { 23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970 },
+ { 1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799 },
+ },
+ {
+ { -5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647 },
+ { 13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511 },
+ { -29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032 },
+ },
+},
+{
+ {
+ { 9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834 },
+ { -23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461 },
+ { 29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062 },
+ },
+ {
+ { -25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516 },
+ { -20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547 },
+ { -24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240 },
+ },
+ {
+ { -17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038 },
+ { -33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741 },
+ { 16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103 },
+ },
+ {
+ { -19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747 },
+ { -1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323 },
+ { 31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016 },
+ },
+ {
+ { -14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373 },
+ { 15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228 },
+ { -2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141 },
+ },
+ {
+ { 16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399 },
+ { 11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831 },
+ { -185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376 },
+ },
+ {
+ { -32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313 },
+ { -18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958 },
+ { -6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577 },
+ },
+ {
+ { -22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743 },
+ { 29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684 },
+ { -20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476 },
+ },
+},
diff --git a/plugin/auth_ed25519/ref10/base2.h b/plugin/auth_ed25519/ref10/base2.h
new file mode 100644
index 00000000000..8c538440fff
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/base2.h
@@ -0,0 +1,40 @@
+ {
+ { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+ { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+ { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+ { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+ { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+ { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+ { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+ { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+ { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+ { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+ { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+ { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+ { -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 },
+ { -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 },
+ { 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 },
+ },
+ {
+ { -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 },
+ { 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 },
+ { 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 },
+ },
+ {
+ { -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 },
+ { -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 },
+ { -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 },
+ },
+ {
+ { -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 },
+ { -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 },
+ { -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 },
+ },
diff --git a/plugin/auth_ed25519/ref10/d.h b/plugin/auth_ed25519/ref10/d.h
new file mode 100644
index 00000000000..e25f5783507
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/d.h
@@ -0,0 +1 @@
+-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116
diff --git a/plugin/auth_ed25519/ref10/d2.h b/plugin/auth_ed25519/ref10/d2.h
new file mode 100644
index 00000000000..01aaec75127
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/d2.h
@@ -0,0 +1 @@
+-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199
diff --git a/plugin/auth_ed25519/ref10/fe.h b/plugin/auth_ed25519/ref10/fe.h
new file mode 100644
index 00000000000..60c308ba463
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe.h
@@ -0,0 +1,56 @@
+#ifndef FE_H
+#define FE_H
+
+#include "crypto_int32.h"
+
+typedef crypto_int32 fe[10];
+
+/*
+fe means field element.
+Here the field is \Z/(2^255-19).
+An element t, entries t[0]...t[9], represents the integer
+t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+Bounds on each t[i] vary depending on context.
+*/
+
+#define fe_frombytes crypto_sign_ed25519_ref10_fe_frombytes
+#define fe_tobytes crypto_sign_ed25519_ref10_fe_tobytes
+#define fe_copy crypto_sign_ed25519_ref10_fe_copy
+#define fe_isnonzero crypto_sign_ed25519_ref10_fe_isnonzero
+#define fe_isnegative crypto_sign_ed25519_ref10_fe_isnegative
+#define fe_0 crypto_sign_ed25519_ref10_fe_0
+#define fe_1 crypto_sign_ed25519_ref10_fe_1
+#define fe_cswap crypto_sign_ed25519_ref10_fe_cswap
+#define fe_cmov crypto_sign_ed25519_ref10_fe_cmov
+#define fe_add crypto_sign_ed25519_ref10_fe_add
+#define fe_sub crypto_sign_ed25519_ref10_fe_sub
+#define fe_neg crypto_sign_ed25519_ref10_fe_neg
+#define fe_mul crypto_sign_ed25519_ref10_fe_mul
+#define fe_sq crypto_sign_ed25519_ref10_fe_sq
+#define fe_sq2 crypto_sign_ed25519_ref10_fe_sq2
+#define fe_mul121666 crypto_sign_ed25519_ref10_fe_mul121666
+#define fe_invert crypto_sign_ed25519_ref10_fe_invert
+#define fe_pow22523 crypto_sign_ed25519_ref10_fe_pow22523
+
+extern void fe_frombytes(fe,const unsigned char *);
+extern void fe_tobytes(unsigned char *,const fe);
+
+extern void fe_copy(fe,const fe);
+extern int fe_isnonzero(const fe);
+extern int fe_isnegative(const fe);
+extern void fe_0(fe);
+extern void fe_1(fe);
+extern void fe_cswap(fe,fe,unsigned int);
+extern void fe_cmov(fe,const fe,unsigned int);
+
+extern void fe_add(fe,const fe,const fe);
+extern void fe_sub(fe,const fe,const fe);
+extern void fe_neg(fe,const fe);
+extern void fe_mul(fe,const fe,const fe);
+extern void fe_sq(fe,const fe);
+extern void fe_sq2(fe,const fe);
+extern void fe_mul121666(fe,const fe);
+extern void fe_invert(fe,const fe);
+extern void fe_pow22523(fe,const fe);
+
+#endif
diff --git a/plugin/auth_ed25519/ref10/fe_0.c b/plugin/auth_ed25519/ref10/fe_0.c
new file mode 100644
index 00000000000..ec879d7337f
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_0.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 0
+*/
+
+void fe_0(fe h)
+{
+ h[0] = 0;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_1.c b/plugin/auth_ed25519/ref10/fe_1.c
new file mode 100644
index 00000000000..8cf77848447
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_1.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 1
+*/
+
+void fe_1(fe h)
+{
+ h[0] = 1;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_add.c b/plugin/auth_ed25519/ref10/fe_add.c
new file mode 100644
index 00000000000..e6a81da2021
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_add.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_add(fe h,const fe f,const fe g)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 h0 = f0 + g0;
+ crypto_int32 h1 = f1 + g1;
+ crypto_int32 h2 = f2 + g2;
+ crypto_int32 h3 = f3 + g3;
+ crypto_int32 h4 = f4 + g4;
+ crypto_int32 h5 = f5 + g5;
+ crypto_int32 h6 = f6 + g6;
+ crypto_int32 h7 = f7 + g7;
+ crypto_int32 h8 = f8 + g8;
+ crypto_int32 h9 = f9 + g9;
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_cmov.c b/plugin/auth_ed25519/ref10/fe_cmov.c
new file mode 100644
index 00000000000..8ca584fb19a
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_cmov.c
@@ -0,0 +1,63 @@
+#include "fe.h"
+
+/*
+Replace (f,g) with (g,g) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+void fe_cmov(fe f,const fe g,unsigned int b)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 x0 = f0 ^ g0;
+ crypto_int32 x1 = f1 ^ g1;
+ crypto_int32 x2 = f2 ^ g2;
+ crypto_int32 x3 = f3 ^ g3;
+ crypto_int32 x4 = f4 ^ g4;
+ crypto_int32 x5 = f5 ^ g5;
+ crypto_int32 x6 = f6 ^ g6;
+ crypto_int32 x7 = f7 ^ g7;
+ crypto_int32 x8 = f8 ^ g8;
+ crypto_int32 x9 = f9 ^ g9;
+ b = -b;
+ x0 &= b;
+ x1 &= b;
+ x2 &= b;
+ x3 &= b;
+ x4 &= b;
+ x5 &= b;
+ x6 &= b;
+ x7 &= b;
+ x8 &= b;
+ x9 &= b;
+ f[0] = f0 ^ x0;
+ f[1] = f1 ^ x1;
+ f[2] = f2 ^ x2;
+ f[3] = f3 ^ x3;
+ f[4] = f4 ^ x4;
+ f[5] = f5 ^ x5;
+ f[6] = f6 ^ x6;
+ f[7] = f7 ^ x7;
+ f[8] = f8 ^ x8;
+ f[9] = f9 ^ x9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_copy.c b/plugin/auth_ed25519/ref10/fe_copy.c
new file mode 100644
index 00000000000..9c5bf865a24
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_copy.c
@@ -0,0 +1,29 @@
+#include "fe.h"
+
+/*
+h = f
+*/
+
+void fe_copy(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ h[0] = f0;
+ h[1] = f1;
+ h[2] = f2;
+ h[3] = f3;
+ h[4] = f4;
+ h[5] = f5;
+ h[6] = f6;
+ h[7] = f7;
+ h[8] = f8;
+ h[9] = f9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_frombytes.c b/plugin/auth_ed25519/ref10/fe_frombytes.c
new file mode 100644
index 00000000000..5c179174877
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_frombytes.c
@@ -0,0 +1,73 @@
+#include "fe.h"
+#include "crypto_int64.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ result |= ((crypto_uint64) in[3]) << 24;
+ return result;
+}
+
+/*
+Ignores top bit of h.
+*/
+
+void fe_frombytes(fe h,const unsigned char *s)
+{
+ crypto_int64 h0 = load_4(s);
+ crypto_int64 h1 = load_3(s + 4) << 6;
+ crypto_int64 h2 = load_3(s + 7) << 5;
+ crypto_int64 h3 = load_3(s + 10) << 3;
+ crypto_int64 h4 = load_3(s + 13) << 2;
+ crypto_int64 h5 = load_4(s + 16);
+ crypto_int64 h6 = load_3(s + 20) << 7;
+ crypto_int64 h7 = load_3(s + 23) << 5;
+ crypto_int64 h8 = load_3(s + 26) << 4;
+ crypto_int64 h9 = (load_3(s + 29) & 8388607) << 2;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_invert.c b/plugin/auth_ed25519/ref10/fe_invert.c
new file mode 100644
index 00000000000..bcfdb8ff87e
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_invert.c
@@ -0,0 +1,14 @@
+#include "fe.h"
+
+void fe_invert(fe out,const fe z)
+{
+ fe t0;
+ fe t1;
+ fe t2;
+ fe t3;
+ int i;
+
+#include "pow225521.h"
+
+ return;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_isnegative.c b/plugin/auth_ed25519/ref10/fe_isnegative.c
new file mode 100644
index 00000000000..3b2c8b8d523
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_isnegative.c
@@ -0,0 +1,16 @@
+#include "fe.h"
+
+/*
+return 1 if f is in {1,3,5,...,q-2}
+return 0 if f is in {0,2,4,...,q-1}
+
+Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+int fe_isnegative(const fe f)
+{
+ unsigned char s[32];
+ fe_tobytes(s,f);
+ return s[0] & 1;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_isnonzero.c b/plugin/auth_ed25519/ref10/fe_isnonzero.c
new file mode 100644
index 00000000000..47568001ce5
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_isnonzero.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+#include "crypto_verify_32.h"
+
+/*
+return 1 if f == 0
+return 0 if f != 0
+
+Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+static const unsigned char zero[32];
+
+int fe_isnonzero(const fe f)
+{
+ unsigned char s[32];
+ fe_tobytes(s,f);
+ return crypto_verify_32(s,zero);
+}
diff --git a/plugin/auth_ed25519/ref10/fe_mul.c b/plugin/auth_ed25519/ref10/fe_mul.c
new file mode 100644
index 00000000000..26ca8b3682d
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_mul.c
@@ -0,0 +1,253 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+ |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+Notes on implementation strategy:
+
+Using schoolbook multiplication.
+Karatsuba would save a little in some cost models.
+
+Most multiplications by 2 and 19 are 32-bit precomputations;
+cheaper than 64-bit postcomputations.
+
+There is one remaining multiplication by 19 in the carry chain;
+one *19 precomputation can be merged into this,
+but the resulting data flow is considerably less clean.
+
+There are 12 carries below.
+10 of them are 2-way parallelizable and vectorizable.
+Can get away with 11 carries, but then data flow is much deeper.
+
+With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+void fe_mul(fe h,const fe f,const fe g)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 g1_19 = 19 * g1; /* 1.959375*2^29 */
+ crypto_int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+ crypto_int32 g3_19 = 19 * g3;
+ crypto_int32 g4_19 = 19 * g4;
+ crypto_int32 g5_19 = 19 * g5;
+ crypto_int32 g6_19 = 19 * g6;
+ crypto_int32 g7_19 = 19 * g7;
+ crypto_int32 g8_19 = 19 * g8;
+ crypto_int32 g9_19 = 19 * g9;
+ crypto_int32 f1_2 = 2 * f1;
+ crypto_int32 f3_2 = 2 * f3;
+ crypto_int32 f5_2 = 2 * f5;
+ crypto_int32 f7_2 = 2 * f7;
+ crypto_int32 f9_2 = 2 * f9;
+ crypto_int64 f0g0 = f0 * (crypto_int64) g0;
+ crypto_int64 f0g1 = f0 * (crypto_int64) g1;
+ crypto_int64 f0g2 = f0 * (crypto_int64) g2;
+ crypto_int64 f0g3 = f0 * (crypto_int64) g3;
+ crypto_int64 f0g4 = f0 * (crypto_int64) g4;
+ crypto_int64 f0g5 = f0 * (crypto_int64) g5;
+ crypto_int64 f0g6 = f0 * (crypto_int64) g6;
+ crypto_int64 f0g7 = f0 * (crypto_int64) g7;
+ crypto_int64 f0g8 = f0 * (crypto_int64) g8;
+ crypto_int64 f0g9 = f0 * (crypto_int64) g9;
+ crypto_int64 f1g0 = f1 * (crypto_int64) g0;
+ crypto_int64 f1g1_2 = f1_2 * (crypto_int64) g1;
+ crypto_int64 f1g2 = f1 * (crypto_int64) g2;
+ crypto_int64 f1g3_2 = f1_2 * (crypto_int64) g3;
+ crypto_int64 f1g4 = f1 * (crypto_int64) g4;
+ crypto_int64 f1g5_2 = f1_2 * (crypto_int64) g5;
+ crypto_int64 f1g6 = f1 * (crypto_int64) g6;
+ crypto_int64 f1g7_2 = f1_2 * (crypto_int64) g7;
+ crypto_int64 f1g8 = f1 * (crypto_int64) g8;
+ crypto_int64 f1g9_38 = f1_2 * (crypto_int64) g9_19;
+ crypto_int64 f2g0 = f2 * (crypto_int64) g0;
+ crypto_int64 f2g1 = f2 * (crypto_int64) g1;
+ crypto_int64 f2g2 = f2 * (crypto_int64) g2;
+ crypto_int64 f2g3 = f2 * (crypto_int64) g3;
+ crypto_int64 f2g4 = f2 * (crypto_int64) g4;
+ crypto_int64 f2g5 = f2 * (crypto_int64) g5;
+ crypto_int64 f2g6 = f2 * (crypto_int64) g6;
+ crypto_int64 f2g7 = f2 * (crypto_int64) g7;
+ crypto_int64 f2g8_19 = f2 * (crypto_int64) g8_19;
+ crypto_int64 f2g9_19 = f2 * (crypto_int64) g9_19;
+ crypto_int64 f3g0 = f3 * (crypto_int64) g0;
+ crypto_int64 f3g1_2 = f3_2 * (crypto_int64) g1;
+ crypto_int64 f3g2 = f3 * (crypto_int64) g2;
+ crypto_int64 f3g3_2 = f3_2 * (crypto_int64) g3;
+ crypto_int64 f3g4 = f3 * (crypto_int64) g4;
+ crypto_int64 f3g5_2 = f3_2 * (crypto_int64) g5;
+ crypto_int64 f3g6 = f3 * (crypto_int64) g6;
+ crypto_int64 f3g7_38 = f3_2 * (crypto_int64) g7_19;
+ crypto_int64 f3g8_19 = f3 * (crypto_int64) g8_19;
+ crypto_int64 f3g9_38 = f3_2 * (crypto_int64) g9_19;
+ crypto_int64 f4g0 = f4 * (crypto_int64) g0;
+ crypto_int64 f4g1 = f4 * (crypto_int64) g1;
+ crypto_int64 f4g2 = f4 * (crypto_int64) g2;
+ crypto_int64 f4g3 = f4 * (crypto_int64) g3;
+ crypto_int64 f4g4 = f4 * (crypto_int64) g4;
+ crypto_int64 f4g5 = f4 * (crypto_int64) g5;
+ crypto_int64 f4g6_19 = f4 * (crypto_int64) g6_19;
+ crypto_int64 f4g7_19 = f4 * (crypto_int64) g7_19;
+ crypto_int64 f4g8_19 = f4 * (crypto_int64) g8_19;
+ crypto_int64 f4g9_19 = f4 * (crypto_int64) g9_19;
+ crypto_int64 f5g0 = f5 * (crypto_int64) g0;
+ crypto_int64 f5g1_2 = f5_2 * (crypto_int64) g1;
+ crypto_int64 f5g2 = f5 * (crypto_int64) g2;
+ crypto_int64 f5g3_2 = f5_2 * (crypto_int64) g3;
+ crypto_int64 f5g4 = f5 * (crypto_int64) g4;
+ crypto_int64 f5g5_38 = f5_2 * (crypto_int64) g5_19;
+ crypto_int64 f5g6_19 = f5 * (crypto_int64) g6_19;
+ crypto_int64 f5g7_38 = f5_2 * (crypto_int64) g7_19;
+ crypto_int64 f5g8_19 = f5 * (crypto_int64) g8_19;
+ crypto_int64 f5g9_38 = f5_2 * (crypto_int64) g9_19;
+ crypto_int64 f6g0 = f6 * (crypto_int64) g0;
+ crypto_int64 f6g1 = f6 * (crypto_int64) g1;
+ crypto_int64 f6g2 = f6 * (crypto_int64) g2;
+ crypto_int64 f6g3 = f6 * (crypto_int64) g3;
+ crypto_int64 f6g4_19 = f6 * (crypto_int64) g4_19;
+ crypto_int64 f6g5_19 = f6 * (crypto_int64) g5_19;
+ crypto_int64 f6g6_19 = f6 * (crypto_int64) g6_19;
+ crypto_int64 f6g7_19 = f6 * (crypto_int64) g7_19;
+ crypto_int64 f6g8_19 = f6 * (crypto_int64) g8_19;
+ crypto_int64 f6g9_19 = f6 * (crypto_int64) g9_19;
+ crypto_int64 f7g0 = f7 * (crypto_int64) g0;
+ crypto_int64 f7g1_2 = f7_2 * (crypto_int64) g1;
+ crypto_int64 f7g2 = f7 * (crypto_int64) g2;
+ crypto_int64 f7g3_38 = f7_2 * (crypto_int64) g3_19;
+ crypto_int64 f7g4_19 = f7 * (crypto_int64) g4_19;
+ crypto_int64 f7g5_38 = f7_2 * (crypto_int64) g5_19;
+ crypto_int64 f7g6_19 = f7 * (crypto_int64) g6_19;
+ crypto_int64 f7g7_38 = f7_2 * (crypto_int64) g7_19;
+ crypto_int64 f7g8_19 = f7 * (crypto_int64) g8_19;
+ crypto_int64 f7g9_38 = f7_2 * (crypto_int64) g9_19;
+ crypto_int64 f8g0 = f8 * (crypto_int64) g0;
+ crypto_int64 f8g1 = f8 * (crypto_int64) g1;
+ crypto_int64 f8g2_19 = f8 * (crypto_int64) g2_19;
+ crypto_int64 f8g3_19 = f8 * (crypto_int64) g3_19;
+ crypto_int64 f8g4_19 = f8 * (crypto_int64) g4_19;
+ crypto_int64 f8g5_19 = f8 * (crypto_int64) g5_19;
+ crypto_int64 f8g6_19 = f8 * (crypto_int64) g6_19;
+ crypto_int64 f8g7_19 = f8 * (crypto_int64) g7_19;
+ crypto_int64 f8g8_19 = f8 * (crypto_int64) g8_19;
+ crypto_int64 f8g9_19 = f8 * (crypto_int64) g9_19;
+ crypto_int64 f9g0 = f9 * (crypto_int64) g0;
+ crypto_int64 f9g1_38 = f9_2 * (crypto_int64) g1_19;
+ crypto_int64 f9g2_19 = f9 * (crypto_int64) g2_19;
+ crypto_int64 f9g3_38 = f9_2 * (crypto_int64) g3_19;
+ crypto_int64 f9g4_19 = f9 * (crypto_int64) g4_19;
+ crypto_int64 f9g5_38 = f9_2 * (crypto_int64) g5_19;
+ crypto_int64 f9g6_19 = f9 * (crypto_int64) g6_19;
+ crypto_int64 f9g7_38 = f9_2 * (crypto_int64) g7_19;
+ crypto_int64 f9g8_19 = f9 * (crypto_int64) g8_19;
+ crypto_int64 f9g9_38 = f9_2 * (crypto_int64) g9_19;
+ crypto_int64 h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+ crypto_int64 h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+ crypto_int64 h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+ crypto_int64 h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+ crypto_int64 h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+ crypto_int64 h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+ crypto_int64 h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38;
+ crypto_int64 h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19;
+ crypto_int64 h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38;
+ crypto_int64 h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ /*
+ |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
+ i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
+ |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
+ i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9
+ */
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ /* |h0| <= 2^25 */
+ /* |h4| <= 2^25 */
+ /* |h1| <= 1.71*2^59 */
+ /* |h5| <= 1.71*2^59 */
+
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ /* |h1| <= 2^24; from now on fits into int32 */
+ /* |h5| <= 2^24; from now on fits into int32 */
+ /* |h2| <= 1.41*2^60 */
+ /* |h6| <= 1.41*2^60 */
+
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ /* |h2| <= 2^25; from now on fits into int32 unchanged */
+ /* |h6| <= 2^25; from now on fits into int32 unchanged */
+ /* |h3| <= 1.71*2^59 */
+ /* |h7| <= 1.71*2^59 */
+
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+ /* |h3| <= 2^24; from now on fits into int32 unchanged */
+ /* |h7| <= 2^24; from now on fits into int32 unchanged */
+ /* |h4| <= 1.72*2^34 */
+ /* |h8| <= 1.41*2^60 */
+
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+ /* |h4| <= 2^25; from now on fits into int32 unchanged */
+ /* |h8| <= 2^25; from now on fits into int32 unchanged */
+ /* |h5| <= 1.01*2^24 */
+ /* |h9| <= 1.71*2^59 */
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ /* |h9| <= 2^24; from now on fits into int32 unchanged */
+ /* |h0| <= 1.1*2^39 */
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ /* |h0| <= 2^25; from now on fits into int32 unchanged */
+ /* |h1| <= 1.01*2^24 */
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_neg.c b/plugin/auth_ed25519/ref10/fe_neg.c
new file mode 100644
index 00000000000..2078ce5284a
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_neg.c
@@ -0,0 +1,45 @@
+#include "fe.h"
+
+/*
+h = -f
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_neg(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 h0 = -f0;
+ crypto_int32 h1 = -f1;
+ crypto_int32 h2 = -f2;
+ crypto_int32 h3 = -f3;
+ crypto_int32 h4 = -f4;
+ crypto_int32 h5 = -f5;
+ crypto_int32 h6 = -f6;
+ crypto_int32 h7 = -f7;
+ crypto_int32 h8 = -f8;
+ crypto_int32 h9 = -f9;
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_pow22523.c b/plugin/auth_ed25519/ref10/fe_pow22523.c
new file mode 100644
index 00000000000..56675a5902f
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_pow22523.c
@@ -0,0 +1,13 @@
+#include "fe.h"
+
+void fe_pow22523(fe out,const fe z)
+{
+ fe t0;
+ fe t1;
+ fe t2;
+ int i;
+
+#include "pow22523.h"
+
+ return;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_sq.c b/plugin/auth_ed25519/ref10/fe_sq.c
new file mode 100644
index 00000000000..8dd119841c6
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_sq.c
@@ -0,0 +1,149 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 f0_2 = 2 * f0;
+ crypto_int32 f1_2 = 2 * f1;
+ crypto_int32 f2_2 = 2 * f2;
+ crypto_int32 f3_2 = 2 * f3;
+ crypto_int32 f4_2 = 2 * f4;
+ crypto_int32 f5_2 = 2 * f5;
+ crypto_int32 f6_2 = 2 * f6;
+ crypto_int32 f7_2 = 2 * f7;
+ crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+ crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+ crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+ crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+ crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+ crypto_int64 f0f0 = f0 * (crypto_int64) f0;
+ crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1;
+ crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2;
+ crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3;
+ crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4;
+ crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5;
+ crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6;
+ crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7;
+ crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8;
+ crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9;
+ crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1;
+ crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2;
+ crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2;
+ crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4;
+ crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2;
+ crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6;
+ crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2;
+ crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8;
+ crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+ crypto_int64 f2f2 = f2 * (crypto_int64) f2;
+ crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3;
+ crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4;
+ crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5;
+ crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6;
+ crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7;
+ crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+ crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38;
+ crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3;
+ crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4;
+ crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2;
+ crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6;
+ crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+ crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+ crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+ crypto_int64 f4f4 = f4 * (crypto_int64) f4;
+ crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5;
+ crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+ crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38;
+ crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+ crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38;
+ crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38;
+ crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+ crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+ crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+ crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+ crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19;
+ crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38;
+ crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+ crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38;
+ crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38;
+ crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+ crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+ crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19;
+ crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38;
+ crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38;
+ crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+ crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+ crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+ crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+ crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38;
+ crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+ crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+ crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+ crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38;
+ crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_sq2.c b/plugin/auth_ed25519/ref10/fe_sq2.c
new file mode 100644
index 00000000000..026ed3aacf5
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_sq2.c
@@ -0,0 +1,160 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq2(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 f0_2 = 2 * f0;
+ crypto_int32 f1_2 = 2 * f1;
+ crypto_int32 f2_2 = 2 * f2;
+ crypto_int32 f3_2 = 2 * f3;
+ crypto_int32 f4_2 = 2 * f4;
+ crypto_int32 f5_2 = 2 * f5;
+ crypto_int32 f6_2 = 2 * f6;
+ crypto_int32 f7_2 = 2 * f7;
+ crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+ crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+ crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+ crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+ crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+ crypto_int64 f0f0 = f0 * (crypto_int64) f0;
+ crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1;
+ crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2;
+ crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3;
+ crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4;
+ crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5;
+ crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6;
+ crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7;
+ crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8;
+ crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9;
+ crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1;
+ crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2;
+ crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2;
+ crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4;
+ crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2;
+ crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6;
+ crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2;
+ crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8;
+ crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+ crypto_int64 f2f2 = f2 * (crypto_int64) f2;
+ crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3;
+ crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4;
+ crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5;
+ crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6;
+ crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7;
+ crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+ crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38;
+ crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3;
+ crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4;
+ crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2;
+ crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6;
+ crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+ crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+ crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+ crypto_int64 f4f4 = f4 * (crypto_int64) f4;
+ crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5;
+ crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+ crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38;
+ crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+ crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38;
+ crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38;
+ crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+ crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+ crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+ crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+ crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19;
+ crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38;
+ crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+ crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38;
+ crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38;
+ crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+ crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+ crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19;
+ crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38;
+ crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38;
+ crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+ crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+ crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+ crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+ crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38;
+ crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+ crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+ crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+ crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38;
+ crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ h0 += h0;
+ h1 += h1;
+ h2 += h2;
+ h3 += h3;
+ h4 += h4;
+ h5 += h5;
+ h6 += h6;
+ h7 += h7;
+ h8 += h8;
+ h9 += h9;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_sub.c b/plugin/auth_ed25519/ref10/fe_sub.c
new file mode 100644
index 00000000000..6e26b7df8f5
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_sub.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_sub(fe h,const fe f,const fe g)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 h0 = f0 - g0;
+ crypto_int32 h1 = f1 - g1;
+ crypto_int32 h2 = f2 - g2;
+ crypto_int32 h3 = f3 - g3;
+ crypto_int32 h4 = f4 - g4;
+ crypto_int32 h5 = f5 - g5;
+ crypto_int32 h6 = f6 - g6;
+ crypto_int32 h7 = f7 - g7;
+ crypto_int32 h8 = f8 - g8;
+ crypto_int32 h9 = f9 - g9;
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_tobytes.c b/plugin/auth_ed25519/ref10/fe_tobytes.c
new file mode 100644
index 00000000000..0a63baf9c17
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_tobytes.c
@@ -0,0 +1,119 @@
+#include "fe.h"
+
+/*
+Preconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+ Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+ Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+ Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+ Then 0<y<1.
+
+ Write r=h-pq.
+ Have 0<=r<=p-1=2^255-20.
+ Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+ Write x=r+19(2^-255)r+y.
+ Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+ Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+ so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+void fe_tobytes(unsigned char *s,const fe h)
+{
+ crypto_int32 h0 = h[0];
+ crypto_int32 h1 = h[1];
+ crypto_int32 h2 = h[2];
+ crypto_int32 h3 = h[3];
+ crypto_int32 h4 = h[4];
+ crypto_int32 h5 = h[5];
+ crypto_int32 h6 = h[6];
+ crypto_int32 h7 = h[7];
+ crypto_int32 h8 = h[8];
+ crypto_int32 h9 = h[9];
+ crypto_int32 q;
+ crypto_int32 carry0;
+ crypto_int32 carry1;
+ crypto_int32 carry2;
+ crypto_int32 carry3;
+ crypto_int32 carry4;
+ crypto_int32 carry5;
+ crypto_int32 carry6;
+ crypto_int32 carry7;
+ crypto_int32 carry8;
+ crypto_int32 carry9;
+
+ q = (19 * h9 + (((crypto_int32) 1) << 24)) >> 25;
+ q = (h0 + q) >> 26;
+ q = (h1 + q) >> 25;
+ q = (h2 + q) >> 26;
+ q = (h3 + q) >> 25;
+ q = (h4 + q) >> 26;
+ q = (h5 + q) >> 25;
+ q = (h6 + q) >> 26;
+ q = (h7 + q) >> 25;
+ q = (h8 + q) >> 26;
+ q = (h9 + q) >> 25;
+
+ /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+ h0 += 19 * q;
+ /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+ carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+ carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+ carry9 = h9 >> 25; h9 -= carry9 << 25;
+ /* h10 = carry9 */
+
+ /*
+ Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ Have h0+...+2^230 h9 between 0 and 2^255-1;
+ evidently 2^255 h10-2^255 q = 0.
+ Goal: Output h0+...+2^230 h9.
+ */
+
+ s[0] = h0 >> 0;
+ s[1] = h0 >> 8;
+ s[2] = h0 >> 16;
+ s[3] = (h0 >> 24) | (h1 << 2);
+ s[4] = h1 >> 6;
+ s[5] = h1 >> 14;
+ s[6] = (h1 >> 22) | (h2 << 3);
+ s[7] = h2 >> 5;
+ s[8] = h2 >> 13;
+ s[9] = (h2 >> 21) | (h3 << 5);
+ s[10] = h3 >> 3;
+ s[11] = h3 >> 11;
+ s[12] = (h3 >> 19) | (h4 << 6);
+ s[13] = h4 >> 2;
+ s[14] = h4 >> 10;
+ s[15] = h4 >> 18;
+ s[16] = h5 >> 0;
+ s[17] = h5 >> 8;
+ s[18] = h5 >> 16;
+ s[19] = (h5 >> 24) | (h6 << 1);
+ s[20] = h6 >> 7;
+ s[21] = h6 >> 15;
+ s[22] = (h6 >> 23) | (h7 << 3);
+ s[23] = h7 >> 5;
+ s[24] = h7 >> 13;
+ s[25] = (h7 >> 21) | (h8 << 4);
+ s[26] = h8 >> 4;
+ s[27] = h8 >> 12;
+ s[28] = (h8 >> 20) | (h9 << 6);
+ s[29] = h9 >> 2;
+ s[30] = h9 >> 10;
+ s[31] = h9 >> 18;
+}
diff --git a/plugin/auth_ed25519/ref10/ge.h b/plugin/auth_ed25519/ref10/ge.h
new file mode 100644
index 00000000000..55e95f95b6e
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge.h
@@ -0,0 +1,95 @@
+#ifndef GE_H
+#define GE_H
+
+/*
+ge means group element.
+
+Here the group is the set of pairs (x,y) of field elements (see fe.h)
+satisfying -x^2 + y^2 = 1 + d x^2y^2
+where d = -121665/121666.
+
+Representations:
+ ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+ ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+ ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+ ge_precomp (Duif): (y+x,y-x,2dxy)
+*/
+
+#include "fe.h"
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+} ge_p2;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p3;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p1p1;
+
+typedef struct {
+ fe yplusx;
+ fe yminusx;
+ fe xy2d;
+} ge_precomp;
+
+typedef struct {
+ fe YplusX;
+ fe YminusX;
+ fe Z;
+ fe T2d;
+} ge_cached;
+
+#define ge_frombytes_negate_vartime crypto_sign_ed25519_ref10_ge_frombytes_negate_vartime
+#define ge_tobytes crypto_sign_ed25519_ref10_ge_tobytes
+#define ge_p3_tobytes crypto_sign_ed25519_ref10_ge_p3_tobytes
+
+#define ge_p2_0 crypto_sign_ed25519_ref10_ge_p2_0
+#define ge_p3_0 crypto_sign_ed25519_ref10_ge_p3_0
+#define ge_precomp_0 crypto_sign_ed25519_ref10_ge_precomp_0
+#define ge_p3_to_p2 crypto_sign_ed25519_ref10_ge_p3_to_p2
+#define ge_p3_to_cached crypto_sign_ed25519_ref10_ge_p3_to_cached
+#define ge_p1p1_to_p2 crypto_sign_ed25519_ref10_ge_p1p1_to_p2
+#define ge_p1p1_to_p3 crypto_sign_ed25519_ref10_ge_p1p1_to_p3
+#define ge_p2_dbl crypto_sign_ed25519_ref10_ge_p2_dbl
+#define ge_p3_dbl crypto_sign_ed25519_ref10_ge_p3_dbl
+
+#define ge_madd crypto_sign_ed25519_ref10_ge_madd
+#define ge_msub crypto_sign_ed25519_ref10_ge_msub
+#define ge_add crypto_sign_ed25519_ref10_ge_add
+#define ge_sub crypto_sign_ed25519_ref10_ge_sub
+#define ge_scalarmult_base crypto_sign_ed25519_ref10_ge_scalarmult_base
+#define ge_double_scalarmult_vartime crypto_sign_ed25519_ref10_ge_double_scalarmult_vartime
+
+extern void ge_tobytes(unsigned char *,const ge_p2 *);
+extern void ge_p3_tobytes(unsigned char *,const ge_p3 *);
+extern int ge_frombytes_negate_vartime(ge_p3 *,const unsigned char *);
+
+extern void ge_p2_0(ge_p2 *);
+extern void ge_p3_0(ge_p3 *);
+extern void ge_precomp_0(ge_precomp *);
+extern void ge_p3_to_p2(ge_p2 *,const ge_p3 *);
+extern void ge_p3_to_cached(ge_cached *,const ge_p3 *);
+extern void ge_p1p1_to_p2(ge_p2 *,const ge_p1p1 *);
+extern void ge_p1p1_to_p3(ge_p3 *,const ge_p1p1 *);
+extern void ge_p2_dbl(ge_p1p1 *,const ge_p2 *);
+extern void ge_p3_dbl(ge_p1p1 *,const ge_p3 *);
+
+extern void ge_madd(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_msub(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_add(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_sub(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_scalarmult_base(ge_p3 *,const unsigned char *);
+extern void ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,const ge_p3 *,const unsigned char *);
+
+#endif
diff --git a/plugin/auth_ed25519/ref10/ge_add.c b/plugin/auth_ed25519/ref10/ge_add.c
new file mode 100644
index 00000000000..da7ff5d2ebe
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_add.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+ fe t0;
+#include "ge_add.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_add.h b/plugin/auth_ed25519/ref10/ge_add.h
new file mode 100644
index 00000000000..7481f8ffbed
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_add.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_add */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YpX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YpX2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YpX2=q->YplusX); */
+fe_mul(r->Z,r->X,q->YplusX);
+
+/* qhasm: B = YmX1*YmX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YmX2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YmX2=q->YminusX); */
+fe_mul(r->Y,r->Y,q->YminusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_double_scalarmult.c b/plugin/auth_ed25519/ref10/ge_double_scalarmult.c
new file mode 100644
index 00000000000..f8bf4bf775b
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_double_scalarmult.c
@@ -0,0 +1,96 @@
+#include "ge.h"
+
+static void slide(signed char *r,const unsigned char *a)
+{
+ int i;
+ int b;
+ int k;
+
+ for (i = 0;i < 256;++i)
+ r[i] = 1 & (a[i >> 3] >> (i & 7));
+
+ for (i = 0;i < 256;++i)
+ if (r[i]) {
+ for (b = 1;b <= 6 && i + b < 256;++b) {
+ if (r[i + b]) {
+ if (r[i] + (r[i + b] << b) <= 15) {
+ r[i] += r[i + b] << b; r[i + b] = 0;
+ } else if (r[i] - (r[i + b] << b) >= -15) {
+ r[i] -= r[i + b] << b;
+ for (k = i + b;k < 256;++k) {
+ if (!r[k]) {
+ r[k] = 1;
+ break;
+ }
+ r[k] = 0;
+ }
+ } else
+ break;
+ }
+ }
+ }
+
+}
+
+static ge_precomp Bi[8] = {
+#include "base2.h"
+} ;
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+void ge_double_scalarmult_vartime(ge_p2 *r,const unsigned char *a,const ge_p3 *A,const unsigned char *b)
+{
+ signed char aslide[256];
+ signed char bslide[256];
+ ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
+ ge_p1p1 t;
+ ge_p3 u;
+ ge_p3 A2;
+ int i;
+
+ slide(aslide,a);
+ slide(bslide,b);
+
+ ge_p3_to_cached(&Ai[0],A);
+ ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
+ ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
+ ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
+ ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
+ ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
+ ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
+ ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
+ ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
+
+ ge_p2_0(r);
+
+ for (i = 255;i >= 0;--i) {
+ if (aslide[i] || bslide[i]) break;
+ }
+
+ for (;i >= 0;--i) {
+ ge_p2_dbl(&t,r);
+
+ if (aslide[i] > 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_add(&t,&u,&Ai[aslide[i]/2]);
+ } else if (aslide[i] < 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
+ }
+
+ if (bslide[i] > 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_madd(&t,&u,&Bi[bslide[i]/2]);
+ } else if (bslide[i] < 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
+ }
+
+ ge_p1p1_to_p2(r,&t);
+ }
+}
diff --git a/plugin/auth_ed25519/ref10/ge_frombytes.c b/plugin/auth_ed25519/ref10/ge_frombytes.c
new file mode 100644
index 00000000000..1a059ee93fa
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_frombytes.c
@@ -0,0 +1,50 @@
+#include "ge.h"
+
+static const fe d = {
+#include "d.h"
+} ;
+
+static const fe sqrtm1 = {
+#include "sqrtm1.h"
+} ;
+
+int ge_frombytes_negate_vartime(ge_p3 *h,const unsigned char *s)
+{
+ fe u;
+ fe v;
+ fe v3;
+ fe vxx;
+ fe check;
+
+ fe_frombytes(h->Y,s);
+ fe_1(h->Z);
+ fe_sq(u,h->Y);
+ fe_mul(v,u,d);
+ fe_sub(u,u,h->Z); /* u = y^2-1 */
+ fe_add(v,v,h->Z); /* v = dy^2+1 */
+
+ fe_sq(v3,v);
+ fe_mul(v3,v3,v); /* v3 = v^3 */
+ fe_sq(h->X,v3);
+ fe_mul(h->X,h->X,v);
+ fe_mul(h->X,h->X,u); /* x = uv^7 */
+
+ fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
+ fe_mul(h->X,h->X,v3);
+ fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */
+
+ fe_sq(vxx,h->X);
+ fe_mul(vxx,vxx,v);
+ fe_sub(check,vxx,u); /* vx^2-u */
+ if (fe_isnonzero(check)) {
+ fe_add(check,vxx,u); /* vx^2+u */
+ if (fe_isnonzero(check)) return -1;
+ fe_mul(h->X,h->X,sqrtm1);
+ }
+
+ if (fe_isnegative(h->X) == (s[31] >> 7))
+ fe_neg(h->X,h->X);
+
+ fe_mul(h->T,h->X,h->Y);
+ return 0;
+}
diff --git a/plugin/auth_ed25519/ref10/ge_madd.c b/plugin/auth_ed25519/ref10/ge_madd.c
new file mode 100644
index 00000000000..622571774b4
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_madd.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_madd(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+ fe t0;
+#include "ge_madd.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_madd.h b/plugin/auth_ed25519/ref10/ge_madd.h
new file mode 100644
index 00000000000..ecae84952b3
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_madd.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_madd */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ypx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ypx2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ypx2=q->yplusx); */
+fe_mul(r->Z,r->X,q->yplusx);
+
+/* qhasm: B = YmX1*ymx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ymx2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ymx2=q->yminusx); */
+fe_mul(r->Y,r->Y,q->yminusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_msub.c b/plugin/auth_ed25519/ref10/ge_msub.c
new file mode 100644
index 00000000000..741ecbf1139
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_msub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_msub(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+ fe t0;
+#include "ge_msub.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_msub.h b/plugin/auth_ed25519/ref10/ge_msub.h
new file mode 100644
index 00000000000..500f986ba0d
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_msub.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_msub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ymx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ymx2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ymx2=q->yminusx); */
+fe_mul(r->Z,r->X,q->yminusx);
+
+/* qhasm: B = YmX1*ypx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ypx2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ypx2=q->yplusx); */
+fe_mul(r->Y,r->Y,q->yplusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_p1p1_to_p2.c b/plugin/auth_ed25519/ref10/ge_p1p1_to_p2.c
new file mode 100644
index 00000000000..9bb5013d668
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p1p1_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p)
+{
+ fe_mul(r->X,p->X,p->T);
+ fe_mul(r->Y,p->Y,p->Z);
+ fe_mul(r->Z,p->Z,p->T);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p1p1_to_p3.c b/plugin/auth_ed25519/ref10/ge_p1p1_to_p3.c
new file mode 100644
index 00000000000..2f57b109685
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p1p1_to_p3.c
@@ -0,0 +1,13 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p)
+{
+ fe_mul(r->X,p->X,p->T);
+ fe_mul(r->Y,p->Y,p->Z);
+ fe_mul(r->Z,p->Z,p->T);
+ fe_mul(r->T,p->X,p->Y);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p2_0.c b/plugin/auth_ed25519/ref10/ge_p2_0.c
new file mode 100644
index 00000000000..6191d1e6e4e
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p2_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_p2_0(ge_p2 *h)
+{
+ fe_0(h->X);
+ fe_1(h->Y);
+ fe_1(h->Z);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p2_dbl.c b/plugin/auth_ed25519/ref10/ge_p2_dbl.c
new file mode 100644
index 00000000000..2e332b5cee4
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p2_dbl.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p2_dbl(ge_p1p1 *r,const ge_p2 *p)
+{
+ fe t0;
+#include "ge_p2_dbl.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p2_dbl.h b/plugin/auth_ed25519/ref10/ge_p2_dbl.h
new file mode 100644
index 00000000000..128efed9076
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p2_dbl.h
@@ -0,0 +1,73 @@
+
+/* qhasm: enter ge_p2_dbl */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe AA */
+
+/* qhasm: fe XX */
+
+/* qhasm: fe YY */
+
+/* qhasm: fe B */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: XX=X1^2 */
+/* asm 1: fe_sq(>XX=fe#1,<X1=fe#11); */
+/* asm 2: fe_sq(>XX=r->X,<X1=p->X); */
+fe_sq(r->X,p->X);
+
+/* qhasm: YY=Y1^2 */
+/* asm 1: fe_sq(>YY=fe#3,<Y1=fe#12); */
+/* asm 2: fe_sq(>YY=r->Z,<Y1=p->Y); */
+fe_sq(r->Z,p->Y);
+
+/* qhasm: B=2*Z1^2 */
+/* asm 1: fe_sq2(>B=fe#4,<Z1=fe#13); */
+/* asm 2: fe_sq2(>B=r->T,<Z1=p->Z); */
+fe_sq2(r->T,p->Z);
+
+/* qhasm: A=X1+Y1 */
+/* asm 1: fe_add(>A=fe#2,<X1=fe#11,<Y1=fe#12); */
+/* asm 2: fe_add(>A=r->Y,<X1=p->X,<Y1=p->Y); */
+fe_add(r->Y,p->X,p->Y);
+
+/* qhasm: AA=A^2 */
+/* asm 1: fe_sq(>AA=fe#5,<A=fe#2); */
+/* asm 2: fe_sq(>AA=t0,<A=r->Y); */
+fe_sq(t0,r->Y);
+
+/* qhasm: Y3=YY+XX */
+/* asm 1: fe_add(>Y3=fe#2,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_add(>Y3=r->Y,<YY=r->Z,<XX=r->X); */
+fe_add(r->Y,r->Z,r->X);
+
+/* qhasm: Z3=YY-XX */
+/* asm 1: fe_sub(>Z3=fe#3,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_sub(>Z3=r->Z,<YY=r->Z,<XX=r->X); */
+fe_sub(r->Z,r->Z,r->X);
+
+/* qhasm: X3=AA-Y3 */
+/* asm 1: fe_sub(>X3=fe#1,<AA=fe#5,<Y3=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<AA=t0,<Y3=r->Y); */
+fe_sub(r->X,t0,r->Y);
+
+/* qhasm: T3=B-Z3 */
+/* asm 1: fe_sub(>T3=fe#4,<B=fe#4,<Z3=fe#3); */
+/* asm 2: fe_sub(>T3=r->T,<B=r->T,<Z3=r->Z); */
+fe_sub(r->T,r->T,r->Z);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_p3_0.c b/plugin/auth_ed25519/ref10/ge_p3_0.c
new file mode 100644
index 00000000000..401b2935a11
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_0.c
@@ -0,0 +1,9 @@
+#include "ge.h"
+
+void ge_p3_0(ge_p3 *h)
+{
+ fe_0(h->X);
+ fe_1(h->Y);
+ fe_1(h->Z);
+ fe_0(h->T);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p3_dbl.c b/plugin/auth_ed25519/ref10/ge_p3_dbl.c
new file mode 100644
index 00000000000..0d8a05915d3
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_dbl.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p)
+{
+ ge_p2 q;
+ ge_p3_to_p2(&q,p);
+ ge_p2_dbl(r,&q);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p3_to_cached.c b/plugin/auth_ed25519/ref10/ge_p3_to_cached.c
new file mode 100644
index 00000000000..bde64228cf1
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_to_cached.c
@@ -0,0 +1,17 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+static const fe d2 = {
+#include "d2.h"
+} ;
+
+extern void ge_p3_to_cached(ge_cached *r,const ge_p3 *p)
+{
+ fe_add(r->YplusX,p->Y,p->X);
+ fe_sub(r->YminusX,p->Y,p->X);
+ fe_copy(r->Z,p->Z);
+ fe_mul(r->T2d,p->T,d2);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p3_to_p2.c b/plugin/auth_ed25519/ref10/ge_p3_to_p2.c
new file mode 100644
index 00000000000..e532a9e4cbc
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p)
+{
+ fe_copy(r->X,p->X);
+ fe_copy(r->Y,p->Y);
+ fe_copy(r->Z,p->Z);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p3_tobytes.c b/plugin/auth_ed25519/ref10/ge_p3_tobytes.c
new file mode 100644
index 00000000000..21cb2fc656d
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_p3_tobytes(unsigned char *s,const ge_p3 *h)
+{
+ fe recip;
+ fe x;
+ fe y;
+
+ fe_invert(recip,h->Z);
+ fe_mul(x,h->X,recip);
+ fe_mul(y,h->Y,recip);
+ fe_tobytes(s,y);
+ s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/plugin/auth_ed25519/ref10/ge_precomp_0.c b/plugin/auth_ed25519/ref10/ge_precomp_0.c
new file mode 100644
index 00000000000..2e218861d8b
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_precomp_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_precomp_0(ge_precomp *h)
+{
+ fe_1(h->yplusx);
+ fe_1(h->yminusx);
+ fe_0(h->xy2d);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_scalarmult_base.c b/plugin/auth_ed25519/ref10/ge_scalarmult_base.c
new file mode 100644
index 00000000000..421e4fa0fba
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_scalarmult_base.c
@@ -0,0 +1,105 @@
+#include "ge.h"
+#include "crypto_uint32.h"
+
+static unsigned char equal(signed char b,signed char c)
+{
+ unsigned char ub = b;
+ unsigned char uc = c;
+ unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+ crypto_uint32 y = x; /* 0: yes; 1..255: no */
+ y -= 1; /* 4294967295: yes; 0..254: no */
+ y >>= 31; /* 1: yes; 0: no */
+ return y;
+}
+
+static unsigned char negative(signed char b)
+{
+ unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+ x >>= 63; /* 1: yes; 0: no */
+ return x;
+}
+
+static void cmov(ge_precomp *t,ge_precomp *u,unsigned char b)
+{
+ fe_cmov(t->yplusx,u->yplusx,b);
+ fe_cmov(t->yminusx,u->yminusx,b);
+ fe_cmov(t->xy2d,u->xy2d,b);
+}
+
+/* base[i][j] = (j+1)*256^i*B */
+static ge_precomp base[32][8] = {
+#include "base.h"
+} ;
+
+static void select(ge_precomp *t,int pos,signed char b)
+{
+ ge_precomp minust;
+ unsigned char bnegative = negative(b);
+ unsigned char babs = b - (((-bnegative) & b) << 1);
+
+ ge_precomp_0(t);
+ cmov(t,&base[pos][0],equal(babs,1));
+ cmov(t,&base[pos][1],equal(babs,2));
+ cmov(t,&base[pos][2],equal(babs,3));
+ cmov(t,&base[pos][3],equal(babs,4));
+ cmov(t,&base[pos][4],equal(babs,5));
+ cmov(t,&base[pos][5],equal(babs,6));
+ cmov(t,&base[pos][6],equal(babs,7));
+ cmov(t,&base[pos][7],equal(babs,8));
+ fe_copy(minust.yplusx,t->yminusx);
+ fe_copy(minust.yminusx,t->yplusx);
+ fe_neg(minust.xy2d,t->xy2d);
+ cmov(t,&minust,bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+ a[31] <= 127
+*/
+
+void ge_scalarmult_base(ge_p3 *h,const unsigned char *a)
+{
+ signed char e[64];
+ signed char carry;
+ ge_p1p1 r;
+ ge_p2 s;
+ ge_precomp t;
+ int i;
+
+ for (i = 0;i < 32;++i) {
+ e[2 * i + 0] = (a[i] >> 0) & 15;
+ e[2 * i + 1] = (a[i] >> 4) & 15;
+ }
+ /* each e[i] is between 0 and 15 */
+ /* e[63] is between 0 and 7 */
+
+ carry = 0;
+ for (i = 0;i < 63;++i) {
+ e[i] += carry;
+ carry = e[i] + 8;
+ carry >>= 4;
+ e[i] -= carry << 4;
+ }
+ e[63] += carry;
+ /* each e[i] is between -8 and 8 */
+
+ ge_p3_0(h);
+ for (i = 1;i < 64;i += 2) {
+ select(&t,i / 2,e[i]);
+ ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+ }
+
+ ge_p3_dbl(&r,h); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r);
+
+ for (i = 0;i < 64;i += 2) {
+ select(&t,i / 2,e[i]);
+ ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+ }
+}
diff --git a/plugin/auth_ed25519/ref10/ge_sub.c b/plugin/auth_ed25519/ref10/ge_sub.c
new file mode 100644
index 00000000000..69f3d54062f
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_sub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_sub(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+ fe t0;
+#include "ge_sub.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_sub.h b/plugin/auth_ed25519/ref10/ge_sub.h
new file mode 100644
index 00000000000..b4ef1f5dd04
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_sub.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_sub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YmX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YmX2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YmX2=q->YminusX); */
+fe_mul(r->Z,r->X,q->YminusX);
+
+/* qhasm: B = YmX1*YpX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YpX2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YpX2=q->YplusX); */
+fe_mul(r->Y,r->Y,q->YplusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_tobytes.c b/plugin/auth_ed25519/ref10/ge_tobytes.c
new file mode 100644
index 00000000000..31b3d33e095
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_tobytes(unsigned char *s,const ge_p2 *h)
+{
+ fe recip;
+ fe x;
+ fe y;
+
+ fe_invert(recip,h->Z);
+ fe_mul(x,h->X,recip);
+ fe_mul(y,h->Y,recip);
+ fe_tobytes(s,y);
+ s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/plugin/auth_ed25519/ref10/keypair.c b/plugin/auth_ed25519/ref10/keypair.c
new file mode 100644
index 00000000000..64000838b5e
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/keypair.c
@@ -0,0 +1,23 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+
+int crypto_sign_keypair(
+ unsigned char *pk,
+ unsigned char *pw, unsigned long long pwlen
+)
+{
+ unsigned char az[64];
+ ge_p3 A;
+
+ crypto_hash_sha512(az,pw,pwlen);
+ az[0] &= 248;
+ az[31] &= 63;
+ az[31] |= 64;
+
+ ge_scalarmult_base(&A,az);
+ ge_p3_tobytes(pk,&A);
+
+ return 0;
+}
diff --git a/plugin/auth_ed25519/ref10/open.c b/plugin/auth_ed25519/ref10/open.c
new file mode 100644
index 00000000000..7362b681436
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/open.c
@@ -0,0 +1,36 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "crypto_verify_32.h"
+#include "ge.h"
+#include "sc.h"
+
+int crypto_sign_open(
+ unsigned char *sm, unsigned long long smlen,
+ const unsigned char *pk
+)
+{
+ unsigned char scopy[32];
+ unsigned char h[64];
+ unsigned char rcheck[32];
+ ge_p3 A;
+ ge_p2 R;
+
+ if (smlen < 64) goto badsig;
+ if (sm[63] & 224) goto badsig;
+ if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig;
+
+ memmove(scopy,sm + 32,32);
+
+ memmove(sm + 32,pk,32);
+ crypto_hash_sha512(h,sm,smlen);
+ sc_reduce(h);
+
+ ge_double_scalarmult_vartime(&R,h,&A,scopy);
+ ge_tobytes(rcheck,&R);
+ if (crypto_verify_32(rcheck,sm) == 0)
+ return 0;
+
+badsig:
+ return -1;
+}
diff --git a/plugin/auth_ed25519/ref10/pow22523.h b/plugin/auth_ed25519/ref10/pow22523.h
new file mode 100644
index 00000000000..60ffe0d34c8
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/pow22523.h
@@ -0,0 +1,160 @@
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_252_2 */
+
+/* qhasm: fe z_252_3 */
+
+/* qhasm: enter pow22523 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#1,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#1,>z22=fe#1); */
+/* asm 2: fe_sq(>z22=t0,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t0,>z22=t0); */
+fe_sq(t0,t0); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#1,<z9=fe#2,<z22=fe#1); */
+/* asm 2: fe_mul(>z_5_0=t0,<z9=t1,<z22=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#2,<z_5_0=fe#1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#2,>z_10_5=fe#2); */
+/* asm 2: fe_sq(>z_10_5=t1,<z_5_0=t0); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t1,>z_10_5=t1); */
+fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#1,<z_10_5=fe#2,<z_5_0=fe#1); */
+/* asm 2: fe_mul(>z_10_0=t0,<z_10_5=t1,<z_5_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#2,<z_10_0=fe#1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#2,>z_20_10=fe#2); */
+/* asm 2: fe_sq(>z_20_10=t1,<z_10_0=t0); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t1,>z_20_10=t1); */
+fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#2,<z_20_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_20_0=t1,<z_20_10=t1,<z_10_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#3,<z_20_0=fe#2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#3,>z_40_20=fe#3); */
+/* asm 2: fe_sq(>z_40_20=t2,<z_20_0=t1); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t2,>z_40_20=t2); */
+fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq(t2,t2);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#2,<z_40_20=fe#3,<z_20_0=fe#2); */
+/* asm 2: fe_mul(>z_40_0=t1,<z_40_20=t2,<z_20_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#2,<z_40_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#2,>z_50_10=fe#2); */
+/* asm 2: fe_sq(>z_50_10=t1,<z_40_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t1,>z_50_10=t1); */
+fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#1,<z_50_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_50_0=t0,<z_50_10=t1,<z_10_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#2,<z_50_0=fe#1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#2,>z_100_50=fe#2); */
+/* asm 2: fe_sq(>z_100_50=t1,<z_50_0=t0); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t1,>z_100_50=t1); */
+fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#2,<z_100_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_100_0=t1,<z_100_50=t1,<z_50_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#3,<z_100_0=fe#2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#3,>z_200_100=fe#3); */
+/* asm 2: fe_sq(>z_200_100=t2,<z_100_0=t1); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t2,>z_200_100=t2); */
+fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq(t2,t2);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#2,<z_200_100=fe#3,<z_100_0=fe#2); */
+/* asm 2: fe_mul(>z_200_0=t1,<z_200_100=t2,<z_100_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#2,<z_200_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#2,>z_250_50=fe#2); */
+/* asm 2: fe_sq(>z_250_50=t1,<z_200_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t1,>z_250_50=t1); */
+fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#1,<z_250_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_250_0=t0,<z_250_50=t1,<z_50_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_252_2 = z_250_0^2^2 */
+/* asm 1: fe_sq(>z_252_2=fe#1,<z_250_0=fe#1); for (i = 1;i < 2;++i) fe_sq(>z_252_2=fe#1,>z_252_2=fe#1); */
+/* asm 2: fe_sq(>z_252_2=t0,<z_250_0=t0); for (i = 1;i < 2;++i) fe_sq(>z_252_2=t0,>z_252_2=t0); */
+fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq(t0,t0);
+
+/* qhasm: z_252_3 = z_252_2*z1 */
+/* asm 1: fe_mul(>z_252_3=fe#12,<z_252_2=fe#1,<z1=fe#11); */
+/* asm 2: fe_mul(>z_252_3=out,<z_252_2=t0,<z1=z); */
+fe_mul(out,t0,z);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/pow225521.h b/plugin/auth_ed25519/ref10/pow225521.h
new file mode 100644
index 00000000000..109df779a2d
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/pow225521.h
@@ -0,0 +1,160 @@
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_255_5 */
+
+/* qhasm: fe z_255_21 */
+
+/* qhasm: enter pow225521 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#3,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#3,>z22=fe#3); */
+/* asm 2: fe_sq(>z22=t2,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t2,>z22=t2); */
+fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#2,<z9=fe#2,<z22=fe#3); */
+/* asm 2: fe_mul(>z_5_0=t1,<z9=t1,<z22=t2); */
+fe_mul(t1,t1,t2);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#3,<z_5_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#3,>z_10_5=fe#3); */
+/* asm 2: fe_sq(>z_10_5=t2,<z_5_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t2,>z_10_5=t2); */
+fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#2,<z_10_5=fe#3,<z_5_0=fe#2); */
+/* asm 2: fe_mul(>z_10_0=t1,<z_10_5=t2,<z_5_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#3,<z_10_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#3,>z_20_10=fe#3); */
+/* asm 2: fe_sq(>z_20_10=t2,<z_10_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t2,>z_20_10=t2); */
+fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#3,<z_20_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_20_0=t2,<z_20_10=t2,<z_10_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#4,<z_20_0=fe#3); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#4,>z_40_20=fe#4); */
+/* asm 2: fe_sq(>z_40_20=t3,<z_20_0=t2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t3,>z_40_20=t3); */
+fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#3,<z_40_20=fe#4,<z_20_0=fe#3); */
+/* asm 2: fe_mul(>z_40_0=t2,<z_40_20=t3,<z_20_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#3,<z_40_0=fe#3); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#3,>z_50_10=fe#3); */
+/* asm 2: fe_sq(>z_50_10=t2,<z_40_0=t2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t2,>z_50_10=t2); */
+fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#2,<z_50_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_50_0=t1,<z_50_10=t2,<z_10_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#3,<z_50_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#3,>z_100_50=fe#3); */
+/* asm 2: fe_sq(>z_100_50=t2,<z_50_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t2,>z_100_50=t2); */
+fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#3,<z_100_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_100_0=t2,<z_100_50=t2,<z_50_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#4,<z_100_0=fe#3); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#4,>z_200_100=fe#4); */
+/* asm 2: fe_sq(>z_200_100=t3,<z_100_0=t2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t3,>z_200_100=t3); */
+fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#3,<z_200_100=fe#4,<z_100_0=fe#3); */
+/* asm 2: fe_mul(>z_200_0=t2,<z_200_100=t3,<z_100_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#3,<z_200_0=fe#3); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#3,>z_250_50=fe#3); */
+/* asm 2: fe_sq(>z_250_50=t2,<z_200_0=t2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t2,>z_250_50=t2); */
+fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#2,<z_250_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_250_0=t1,<z_250_50=t2,<z_50_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_255_5 = z_250_0^2^5 */
+/* asm 1: fe_sq(>z_255_5=fe#2,<z_250_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_255_5=fe#2,>z_255_5=fe#2); */
+/* asm 2: fe_sq(>z_255_5=t1,<z_250_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_255_5=t1,>z_255_5=t1); */
+fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_255_21 = z_255_5*z11 */
+/* asm 1: fe_mul(>z_255_21=fe#12,<z_255_5=fe#2,<z11=fe#1); */
+/* asm 2: fe_mul(>z_255_21=out,<z_255_5=t1,<z11=t0); */
+fe_mul(out,t1,t0);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/sc.h b/plugin/auth_ed25519/ref10/sc.h
new file mode 100644
index 00000000000..d32ed2e8ca8
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sc.h
@@ -0,0 +1,15 @@
+#ifndef SC_H
+#define SC_H
+
+/*
+The set of scalars is \Z/l
+where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+#define sc_reduce crypto_sign_ed25519_ref10_sc_reduce
+#define sc_muladd crypto_sign_ed25519_ref10_sc_muladd
+
+extern void sc_reduce(unsigned char *);
+extern void sc_muladd(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *);
+
+#endif
diff --git a/plugin/auth_ed25519/ref10/sc_muladd.c b/plugin/auth_ed25519/ref10/sc_muladd.c
new file mode 100644
index 00000000000..6f1e9d02d60
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sc_muladd.c
@@ -0,0 +1,368 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ result |= ((crypto_uint64) in[3]) << 24;
+ return result;
+}
+
+/*
+Input:
+ a[0]+256*a[1]+...+256^31*a[31] = a
+ b[0]+256*b[1]+...+256^31*b[31] = b
+ c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+void sc_muladd(unsigned char *s,const unsigned char *a,const unsigned char *b,const unsigned char *c)
+{
+ crypto_int64 a0 = 2097151 & load_3(a);
+ crypto_int64 a1 = 2097151 & (load_4(a + 2) >> 5);
+ crypto_int64 a2 = 2097151 & (load_3(a + 5) >> 2);
+ crypto_int64 a3 = 2097151 & (load_4(a + 7) >> 7);
+ crypto_int64 a4 = 2097151 & (load_4(a + 10) >> 4);
+ crypto_int64 a5 = 2097151 & (load_3(a + 13) >> 1);
+ crypto_int64 a6 = 2097151 & (load_4(a + 15) >> 6);
+ crypto_int64 a7 = 2097151 & (load_3(a + 18) >> 3);
+ crypto_int64 a8 = 2097151 & load_3(a + 21);
+ crypto_int64 a9 = 2097151 & (load_4(a + 23) >> 5);
+ crypto_int64 a10 = 2097151 & (load_3(a + 26) >> 2);
+ crypto_int64 a11 = (load_4(a + 28) >> 7);
+ crypto_int64 b0 = 2097151 & load_3(b);
+ crypto_int64 b1 = 2097151 & (load_4(b + 2) >> 5);
+ crypto_int64 b2 = 2097151 & (load_3(b + 5) >> 2);
+ crypto_int64 b3 = 2097151 & (load_4(b + 7) >> 7);
+ crypto_int64 b4 = 2097151 & (load_4(b + 10) >> 4);
+ crypto_int64 b5 = 2097151 & (load_3(b + 13) >> 1);
+ crypto_int64 b6 = 2097151 & (load_4(b + 15) >> 6);
+ crypto_int64 b7 = 2097151 & (load_3(b + 18) >> 3);
+ crypto_int64 b8 = 2097151 & load_3(b + 21);
+ crypto_int64 b9 = 2097151 & (load_4(b + 23) >> 5);
+ crypto_int64 b10 = 2097151 & (load_3(b + 26) >> 2);
+ crypto_int64 b11 = (load_4(b + 28) >> 7);
+ crypto_int64 c0 = 2097151 & load_3(c);
+ crypto_int64 c1 = 2097151 & (load_4(c + 2) >> 5);
+ crypto_int64 c2 = 2097151 & (load_3(c + 5) >> 2);
+ crypto_int64 c3 = 2097151 & (load_4(c + 7) >> 7);
+ crypto_int64 c4 = 2097151 & (load_4(c + 10) >> 4);
+ crypto_int64 c5 = 2097151 & (load_3(c + 13) >> 1);
+ crypto_int64 c6 = 2097151 & (load_4(c + 15) >> 6);
+ crypto_int64 c7 = 2097151 & (load_3(c + 18) >> 3);
+ crypto_int64 c8 = 2097151 & load_3(c + 21);
+ crypto_int64 c9 = 2097151 & (load_4(c + 23) >> 5);
+ crypto_int64 c10 = 2097151 & (load_3(c + 26) >> 2);
+ crypto_int64 c11 = (load_4(c + 28) >> 7);
+ crypto_int64 s0;
+ crypto_int64 s1;
+ crypto_int64 s2;
+ crypto_int64 s3;
+ crypto_int64 s4;
+ crypto_int64 s5;
+ crypto_int64 s6;
+ crypto_int64 s7;
+ crypto_int64 s8;
+ crypto_int64 s9;
+ crypto_int64 s10;
+ crypto_int64 s11;
+ crypto_int64 s12;
+ crypto_int64 s13;
+ crypto_int64 s14;
+ crypto_int64 s15;
+ crypto_int64 s16;
+ crypto_int64 s17;
+ crypto_int64 s18;
+ crypto_int64 s19;
+ crypto_int64 s20;
+ crypto_int64 s21;
+ crypto_int64 s22;
+ crypto_int64 s23;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+ crypto_int64 carry10;
+ crypto_int64 carry11;
+ crypto_int64 carry12;
+ crypto_int64 carry13;
+ crypto_int64 carry14;
+ crypto_int64 carry15;
+ crypto_int64 carry16;
+ crypto_int64 carry17;
+ crypto_int64 carry18;
+ crypto_int64 carry19;
+ crypto_int64 carry20;
+ crypto_int64 carry21;
+ crypto_int64 carry22;
+
+ s0 = c0 + a0*b0;
+ s1 = c1 + a0*b1 + a1*b0;
+ s2 = c2 + a0*b2 + a1*b1 + a2*b0;
+ s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0;
+ s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0;
+ s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0;
+ s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0;
+ s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0;
+ s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0;
+ s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0;
+ s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0;
+ s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0;
+ s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1;
+ s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2;
+ s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3;
+ s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4;
+ s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5;
+ s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6;
+ s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7;
+ s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8;
+ s20 = a9*b11 + a10*b10 + a11*b9;
+ s21 = a10*b11 + a11*b10;
+ s22 = a11*b11;
+ s23 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+ carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+ carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+ carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+ carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+ carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+ carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ s[0] = s0 >> 0;
+ s[1] = s0 >> 8;
+ s[2] = (s0 >> 16) | (s1 << 5);
+ s[3] = s1 >> 3;
+ s[4] = s1 >> 11;
+ s[5] = (s1 >> 19) | (s2 << 2);
+ s[6] = s2 >> 6;
+ s[7] = (s2 >> 14) | (s3 << 7);
+ s[8] = s3 >> 1;
+ s[9] = s3 >> 9;
+ s[10] = (s3 >> 17) | (s4 << 4);
+ s[11] = s4 >> 4;
+ s[12] = s4 >> 12;
+ s[13] = (s4 >> 20) | (s5 << 1);
+ s[14] = s5 >> 7;
+ s[15] = (s5 >> 15) | (s6 << 6);
+ s[16] = s6 >> 2;
+ s[17] = s6 >> 10;
+ s[18] = (s6 >> 18) | (s7 << 3);
+ s[19] = s7 >> 5;
+ s[20] = s7 >> 13;
+ s[21] = s8 >> 0;
+ s[22] = s8 >> 8;
+ s[23] = (s8 >> 16) | (s9 << 5);
+ s[24] = s9 >> 3;
+ s[25] = s9 >> 11;
+ s[26] = (s9 >> 19) | (s10 << 2);
+ s[27] = s10 >> 6;
+ s[28] = (s10 >> 14) | (s11 << 7);
+ s[29] = s11 >> 1;
+ s[30] = s11 >> 9;
+ s[31] = s11 >> 17;
+}
diff --git a/plugin/auth_ed25519/ref10/sc_reduce.c b/plugin/auth_ed25519/ref10/sc_reduce.c
new file mode 100644
index 00000000000..d01f5a5737e
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sc_reduce.c
@@ -0,0 +1,275 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ result |= ((crypto_uint64) in[3]) << 24;
+ return result;
+}
+
+/*
+Input:
+ s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = s mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+ Overwrites s in place.
+*/
+
+void sc_reduce(unsigned char *s)
+{
+ crypto_int64 s0 = 2097151 & load_3(s);
+ crypto_int64 s1 = 2097151 & (load_4(s + 2) >> 5);
+ crypto_int64 s2 = 2097151 & (load_3(s + 5) >> 2);
+ crypto_int64 s3 = 2097151 & (load_4(s + 7) >> 7);
+ crypto_int64 s4 = 2097151 & (load_4(s + 10) >> 4);
+ crypto_int64 s5 = 2097151 & (load_3(s + 13) >> 1);
+ crypto_int64 s6 = 2097151 & (load_4(s + 15) >> 6);
+ crypto_int64 s7 = 2097151 & (load_3(s + 18) >> 3);
+ crypto_int64 s8 = 2097151 & load_3(s + 21);
+ crypto_int64 s9 = 2097151 & (load_4(s + 23) >> 5);
+ crypto_int64 s10 = 2097151 & (load_3(s + 26) >> 2);
+ crypto_int64 s11 = 2097151 & (load_4(s + 28) >> 7);
+ crypto_int64 s12 = 2097151 & (load_4(s + 31) >> 4);
+ crypto_int64 s13 = 2097151 & (load_3(s + 34) >> 1);
+ crypto_int64 s14 = 2097151 & (load_4(s + 36) >> 6);
+ crypto_int64 s15 = 2097151 & (load_3(s + 39) >> 3);
+ crypto_int64 s16 = 2097151 & load_3(s + 42);
+ crypto_int64 s17 = 2097151 & (load_4(s + 44) >> 5);
+ crypto_int64 s18 = 2097151 & (load_3(s + 47) >> 2);
+ crypto_int64 s19 = 2097151 & (load_4(s + 49) >> 7);
+ crypto_int64 s20 = 2097151 & (load_4(s + 52) >> 4);
+ crypto_int64 s21 = 2097151 & (load_3(s + 55) >> 1);
+ crypto_int64 s22 = 2097151 & (load_4(s + 57) >> 6);
+ crypto_int64 s23 = (load_4(s + 60) >> 3);
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+ crypto_int64 carry10;
+ crypto_int64 carry11;
+ crypto_int64 carry12;
+ crypto_int64 carry13;
+ crypto_int64 carry14;
+ crypto_int64 carry15;
+ crypto_int64 carry16;
+
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ s[0] = s0 >> 0;
+ s[1] = s0 >> 8;
+ s[2] = (s0 >> 16) | (s1 << 5);
+ s[3] = s1 >> 3;
+ s[4] = s1 >> 11;
+ s[5] = (s1 >> 19) | (s2 << 2);
+ s[6] = s2 >> 6;
+ s[7] = (s2 >> 14) | (s3 << 7);
+ s[8] = s3 >> 1;
+ s[9] = s3 >> 9;
+ s[10] = (s3 >> 17) | (s4 << 4);
+ s[11] = s4 >> 4;
+ s[12] = s4 >> 12;
+ s[13] = (s4 >> 20) | (s5 << 1);
+ s[14] = s5 >> 7;
+ s[15] = (s5 >> 15) | (s6 << 6);
+ s[16] = s6 >> 2;
+ s[17] = s6 >> 10;
+ s[18] = (s6 >> 18) | (s7 << 3);
+ s[19] = s7 >> 5;
+ s[20] = s7 >> 13;
+ s[21] = s8 >> 0;
+ s[22] = s8 >> 8;
+ s[23] = (s8 >> 16) | (s9 << 5);
+ s[24] = s9 >> 3;
+ s[25] = s9 >> 11;
+ s[26] = (s9 >> 19) | (s10 << 2);
+ s[27] = s10 >> 6;
+ s[28] = (s10 >> 14) | (s11 << 7);
+ s[29] = s11 >> 1;
+ s[30] = s11 >> 9;
+ s[31] = s11 >> 17;
+}
diff --git a/plugin/auth_ed25519/ref10/sign.c b/plugin/auth_ed25519/ref10/sign.c
new file mode 100644
index 00000000000..0cf1edd153d
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sign.c
@@ -0,0 +1,39 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+#include "sc.h"
+
+int crypto_sign(
+ unsigned char *sm,
+ const unsigned char *m,unsigned long long mlen,
+ const unsigned char *pw,unsigned long long pwlen
+)
+{
+ unsigned char az[64];
+ unsigned char nonce[64];
+ unsigned char hram[64];
+ ge_p3 A, R;
+
+ crypto_hash_sha512(az,pw,pwlen);
+ az[0] &= 248;
+ az[31] &= 63;
+ az[31] |= 64;
+
+ memmove(sm + 64,m,mlen);
+ memmove(sm + 32,az + 32,32);
+ crypto_hash_sha512(nonce,sm + 32,mlen + 32);
+
+ ge_scalarmult_base(&A,az);
+ ge_p3_tobytes(sm + 32,&A);
+
+ sc_reduce(nonce);
+ ge_scalarmult_base(&R,nonce);
+ ge_p3_tobytes(sm,&R);
+
+ crypto_hash_sha512(hram,sm,mlen + 64);
+ sc_reduce(hram);
+ sc_muladd(sm + 32,hram,az,nonce);
+
+ return 0;
+}
diff --git a/plugin/auth_ed25519/ref10/sqrtm1.h b/plugin/auth_ed25519/ref10/sqrtm1.h
new file mode 100644
index 00000000000..d8caa23b6a6
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sqrtm1.h
@@ -0,0 +1 @@
+-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482
diff --git a/plugin/auth_ed25519/ref10/verify.c b/plugin/auth_ed25519/ref10/verify.c
new file mode 100644
index 00000000000..a0e23afedeb
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/verify.c
@@ -0,0 +1,40 @@
+#include "crypto_verify.h"
+
+int crypto_verify(const unsigned char *x,const unsigned char *y)
+{
+ unsigned int differentbits = 0;
+#define F(i) differentbits |= x[i] ^ y[i];
+ F(0)
+ F(1)
+ F(2)
+ F(3)
+ F(4)
+ F(5)
+ F(6)
+ F(7)
+ F(8)
+ F(9)
+ F(10)
+ F(11)
+ F(12)
+ F(13)
+ F(14)
+ F(15)
+ F(16)
+ F(17)
+ F(18)
+ F(19)
+ F(20)
+ F(21)
+ F(22)
+ F(23)
+ F(24)
+ F(25)
+ F(26)
+ F(27)
+ F(28)
+ F(29)
+ F(30)
+ F(31)
+ return (1 & ((differentbits - 1) >> 8)) - 1;
+}
diff --git a/plugin/auth_ed25519/server_ed25519.c b/plugin/auth_ed25519/server_ed25519.c
new file mode 100644
index 00000000000..753d4cb58c3
--- /dev/null
+++ b/plugin/auth_ed25519/server_ed25519.c
@@ -0,0 +1,146 @@
+/*
+ Copyright (c) 2017, 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
+ 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 02110-1335 USA */
+
+#include <mysql/plugin_auth.h>
+#include "common.h"
+
+#if !defined(__attribute__) && !defined(__GNUC__)
+#define __attribute__(A)
+#endif
+
+#define PASSWORD_LEN_BUF 44 /* base64 of 32 bytes */
+#define PASSWORD_LEN 43 /* we won't store the last byte, padding '=' */
+
+#define CRYPTO_LONGS (CRYPTO_BYTES/sizeof(long))
+#define NONCE_LONGS (NONCE_BYTES/sizeof(long))
+
+/************************** SERVER *************************************/
+
+static int loaded= 0;
+
+static int auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned int i;
+ 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_AUTH_USER_CREDENTIALS;
+ memcpy(pw, info->auth_string, PASSWORD_LEN);
+ pw[PASSWORD_LEN]= '=';
+ if (base64_decode(pw, PASSWORD_LEN_BUF, pk, NULL, 0) != CRYPTO_PUBLICKEYBYTES)
+ return CR_AUTH_USER_CREDENTIALS;
+
+ info->password_used= PASSWORD_USED_YES;
+
+ /* prepare random nonce */
+ for (i=CRYPTO_LONGS; i < CRYPTO_LONGS + NONCE_LONGS; i++)
+ nonce[i]= thd_rnd(info->thd) * ~0UL;
+
+ /* send it */
+ if (vio->write_packet(vio, reply + CRYPTO_BYTES, NONCE_BYTES))
+ return CR_AUTH_HANDSHAKE;
+
+ /* read the signature */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) != CRYPTO_BYTES)
+ return CR_AUTH_HANDSHAKE;
+ memcpy(reply, pkt, CRYPTO_BYTES);
+
+ if (crypto_sign_open(reply, CRYPTO_BYTES + NONCE_BYTES, pk))
+ return CR_ERROR;
+
+ return CR_OK;
+}
+
+static struct st_mysql_auth info =
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "client_ed25519",
+ auth
+};
+
+static int init(void *p __attribute__((unused)))
+{
+ loaded= 1;
+ return 0;
+}
+
+static int deinit(void *p __attribute__((unused)))
+{
+ loaded= 0;
+ return 0;
+}
+
+maria_declare_plugin(ed25519)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &info,
+ "ed25519",
+ "Sergei Golubchik",
+ "Elliptic curve ED25519 based authentication",
+ PLUGIN_LICENSE_GPL,
+ init,
+ deinit,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
+/************************** UDF ****************************************/
+MYSQL_PLUGIN_EXPORT
+char *ed25519_password(UDF_INIT *initid __attribute__((unused)),
+ UDF_ARGS *args, char *result, unsigned long *length,
+ char *is_null, char *error __attribute__((unused)))
+{
+ unsigned char pk[CRYPTO_PUBLICKEYBYTES];
+
+ if ((*is_null= !args->args[0]))
+ return NULL;
+
+ *length= PASSWORD_LEN;
+ crypto_sign_keypair(pk, (unsigned char*)args->args[0], args->lengths[0]);
+ base64_encode(pk, CRYPTO_PUBLICKEYBYTES, result);
+ return result;
+}
+
+/*
+ At least one of _init/_deinit is needed unless the server is started
+ with --allow_suspicious_udfs.
+*/
+MYSQL_PLUGIN_EXPORT
+my_bool ed25519_password_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
+ {
+ strcpy(message,"Wrong arguments to ed25519_password()");
+ return 1;
+ }
+ if (!loaded)
+ {
+ /* cannot work unless the plugin is loaded, we need services. */
+ strcpy(message,"Authentication plugin ed25519 is not loaded");
+ return 1;
+ }
+ initid->max_length= PASSWORD_LEN_BUF;
+ return 0;
+}
diff --git a/plugin/auth_examples/CMakeLists.txt b/plugin/auth_examples/CMakeLists.txt
index 53e38ffa907..7eed0f722e2 100644
--- a/plugin/auth_examples/CMakeLists.txt
+++ b/plugin/auth_examples/CMakeLists.txt
@@ -30,4 +30,4 @@ MYSQL_ADD_PLUGIN(qa_auth_client qa_auth_client.c
MYSQL_ADD_PLUGIN(auth_0x0100 auth_0x0100.c MODULE_ONLY COMPONENT Test)
MYSQL_ADD_PLUGIN(mysql_clear_password clear_password_client.c
- MODULE_ONLY COMPONENT SharedLibraries)
+ MODULE_ONLY CLIENT COMPONENT ClientPlugins)
diff --git a/plugin/auth_gssapi/CMakeLists.txt b/plugin/auth_gssapi/CMakeLists.txt
new file mode 100644
index 00000000000..7d9e58e165f
--- /dev/null
+++ b/plugin/auth_gssapi/CMakeLists.txt
@@ -0,0 +1,45 @@
+IF (WIN32)
+ SET(USE_SSPI 1)
+ENDIF()
+
+IF(USE_SSPI)
+ SET(GSSAPI_LIBS secur32)
+ ADD_DEFINITIONS(-DPLUGIN_SSPI)
+ SET(GSSAPI_CLIENT sspi_client.cc)
+ SET(GSSAPI_SERVER sspi_server.cc)
+ SET(GSSAPI_ERRMSG sspi_errmsg.cc)
+ELSE()
+ SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+ FIND_PACKAGE(GSSAPI)
+ IF(GSSAPI_FOUND)
+ INCLUDE_DIRECTORIES(${GSSAPI_INCS})
+ ADD_DEFINITIONS(-DPLUGIN_GSSAPI)
+ SET(GSSAPI_CLIENT gssapi_client.cc)
+ SET(GSSAPI_SERVER gssapi_server.cc)
+ SET(GSSAPI_ERRMSG gssapi_errmsg.cc)
+
+ SET(CMAKE_REQUIRED_INCLUDES ${GSSAPI_INCS})
+ SET(CMAKE_REQUIRED_LIBRARIES ${GSSAPI_LIBS})
+ INCLUDE(CheckCXXSymbolExists)
+ CHECK_CXX_SYMBOL_EXISTS(krb5_free_unparsed_name "krb5.h" HAVE_KRB5_FREE_UNPARSED_NAME)
+ IF(HAVE_KRB5_FREE_UNPARSED_NAME)
+ ADD_DEFINITIONS(-DHAVE_KRB5_FREE_UNPARSED_NAME=1)
+ ENDIF()
+
+ ELSE()
+ # Can't build plugin
+ RETURN()
+ ENDIF()
+ENDIF ()
+
+
+MYSQL_ADD_PLUGIN(auth_gssapi server_plugin.cc ${GSSAPI_SERVER} ${GSSAPI_ERRMSG}
+ LINK_LIBRARIES ${GSSAPI_LIBS}
+ COMPONENT gssapi-server
+ MODULE_ONLY)
+
+MYSQL_ADD_PLUGIN(auth_gssapi_client client_plugin.cc ${GSSAPI_CLIENT} ${GSSAPI_ERRMSG}
+ LINK_LIBRARIES ${GSSAPI_LIBS}
+ COMPONENT gssapi-client
+ CLIENT
+ MODULE_ONLY)
diff --git a/plugin/auth_gssapi/README.md b/plugin/auth_gssapi/README.md
new file mode 100644
index 00000000000..ea8deaafa94
--- /dev/null
+++ b/plugin/auth_gssapi/README.md
@@ -0,0 +1,129 @@
+# GSSAPI/SSPI authentication for MariaDB
+
+This article gives instructions on configuring GSSAPI authentication plugin
+for MariaDB for passwordless login.
+
+On Unix systems, GSSAPI is usually synonymous with Kerberos authentication.
+Windows has slightly different but very similar API called SSPI, that along with Kerberos, also supports NTLM authentication.
+
+This plugin includes support for Kerberos on Unix, but also can be used as for Windows authentication with or without domain
+environment.
+
+## Server-side preparations on Unix
+To use the plugin, some preparation need to be done on the server side on Unixes.
+MariaDB server will need read access to the Kerberos keytab file, that contains service principal name for the MariaDB server.
+
+
+If you are using **Unix Kerberos KDC (MIT,Heimdal)**
+
+- Create service principal using kadmin tool
+
+```
+kadmin -q "addprinc -randkey mariadb/host.domain.com"
+```
+
+(replace host.domain.com with fully qualified DNS name for the server host)
+
+- Export the newly created user to the keytab file
+
+```
+kadmin -q "ktadd -k /path/to/mariadb.keytab mariadb/host.domain.com"
+```
+
+More details can be found [here](http://www.microhowto.info/howto/create_a_service_principal_using_mit_kerberos.html)
+and [here](http://www.microhowto.info/howto/add_a_host_or_service_principal_to_a_keytab_using_mit_kerberos.html)
+
+If you are using **Windows Active Directory KDC**
+you can need to create keytab using ktpass.exe tool on Windows, map principal user to an existing domain user like this
+
+```
+ktpass.exe /princ mariadb/host.domain.com@DOMAIN.COM /mapuser someuser /pass MyPas$w0rd /out mariadb.keytab /crypto all /ptype KRB5_NT_PRINCIPAL /mapop set
+```
+
+and then transfer the keytab file to the Unix server. See [Microsoft documentation](https://technet.microsoft.com/en-us/library/cc753771.aspx) for details.
+
+
+## Server side preparations on Windows.
+Usually nothing need to be done. MariaDB server should to run on a domain joined machine, either as NetworkService account
+(which is default if it runs as service) or run under any other domain account credentials.
+Creating service principal is not required here (but you can still do it using [_setspn_](https://technet.microsoft.com/en-us/library/cc731241.aspx) tool)
+
+
+# Installing plugin
+- Start the server
+
+- On Unix, edit my the my.cnf/my.ini configuration file, set the parameter gssapi-keytab-path to point to previously
+created keytab path.
+
+```
+ gssapi-keytab-path=/path/to/mariadb.keytab
+```
+
+- Optionally on Unix, in case the service principal name differs from default mariadb/host.domain.com@REALM,
+configure alternative principal name with
+
+```
+ gssapi-principal-name=alternative/principalname@REALM
+```
+
+- In mysql command line client, execute
+
+```
+ INSTALL SONAME 'auth_gssapi'
+```
+
+#Creating users
+
+Now, you can create a user for GSSAPI/SSPI authentication. CREATE USER command, for Kerberos user
+would be like this (*long* form, see below for short one)
+
+```
+CREATE USER usr1 IDENTIFIED WITH gssapi AS 'usr1@EXAMPLE.COM';
+```
+
+(replace with real username and realm)
+
+The part after AS is mechanism specific, and needs to be ``machine\\usr1`` for Windows users identified with NTLM.
+
+You may also use alternative *short* form of CREATE USER
+
+```
+CREATE USER usr1 IDENTIFIED WITH gssapi;
+```
+
+If this syntax is used, realm part is *not* used for comparison
+thus 'usr1@EXAMPLE.COM', 'usr1@EXAMPLE.CO.UK' and 'mymachine\usr1' will all identify as 'usr1'.
+
+#Login as GSSAPI user with command line clients
+
+Using command line client, do
+
+```
+mysql --plugin-dir=/path/to/plugin-dir -u usr1
+```
+
+#Plugin variables
+- **gssapi-keytab-path** (Unix only) - Path to the server keytab file
+- **gssapi-principal-name** - name of the service principal.
+- **gssapi-mech-name** (Windows only) - Name of the SSPI package used by server. Can be either 'Kerberos' or 'Negotiate'.
+ Defaults to 'Negotiate' (both Kerberos and NTLM users can connect)
+ Set it to 'Kerberos', to prevent less secure NTLM in domain environments, but leave it as default(Negotiate)
+ to allow non-domain environment (e.g if server does not run in domain environment).
+
+
+#Implementation
+
+Overview of the protocol between client and server
+
+1. Server : Construct gssapi-principal-name if not set in my.cnf. On Unixes defaults to hostbased name for service "mariadb". On Windows to user's or machine's domain names.
+Acquire credentials for gssapi-principal-name with ```gss_acquire_cred() / AcquireSecurityCredentials()```.
+Send packet with principal name and mech ```"gssapi-principal-name\0gssapi-mech-name\0"``` to client ( on Unix, empty string used for gssapi-mech)
+
+2. Client: execute ```gss_init_sec_context() / InitializeSecurityContext()``` passing gssapi-principal-name / gssapi-mech-name parameters.
+Send resulting GSSAPI blob to server.
+
+3. Server : receive blob from client, execute ```gss_accept_sec_context()/ AcceptSecurityContext()```, send resulting blob back to client
+
+4. Perform 2. and 3. can until both client and server decide that authentication is done, or until some error occurred. If authentication was successful, GSSAPI context (an opaque structure) is generated on both client and server sides.
+
+5. Server : Client name is extracted from the context, and compared to the name provided by client(with or without realm). If name matches, plugin returns success.
diff --git a/plugin/auth_gssapi/client_plugin.cc b/plugin/auth_gssapi/client_plugin.cc
new file mode 100644
index 00000000000..0ab619a08e6
--- /dev/null
+++ b/plugin/auth_gssapi/client_plugin.cc
@@ -0,0 +1,112 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ @file
+
+ GSSAPI authentication plugin, client side
+*/
+#include <string.h>
+#include <stdarg.h>
+#include <mysqld_error.h>
+#include <mysql/client_plugin.h>
+#include <mysql.h>
+#include <stdio.h>
+#include "common.h"
+
+extern int auth_client(char *principal_name,
+ char *mech,
+ MYSQL *mysql,
+ MYSQL_PLUGIN_VIO *vio);
+
+static void parse_server_packet(char *packet, size_t packet_len, char *spn, char *mech)
+{
+ size_t spn_len;
+ spn_len = strnlen(packet, packet_len);
+ strncpy(spn, packet, PRINCIPAL_NAME_MAX);
+ if (spn_len == packet_len - 1)
+ {
+ /* Mechanism not included into packet */
+ *mech = 0;
+ }
+ else
+ {
+ strncpy(mech, packet + spn_len + 1, MECH_NAME_MAX);
+ }
+}
+
+/**
+ Set client error message.
+ */
+void log_client_error(MYSQL *mysql, const char *format, ...)
+{
+ NET *net= &mysql->net;
+ va_list args;
+
+ net->last_errno= ER_UNKNOWN_ERROR;
+ va_start(args, format);
+ vsnprintf(net->last_error, sizeof(net->last_error) - 1,
+ format, args);
+ va_end(args);
+ memcpy(net->sqlstate, "HY000", sizeof(net->sqlstate));
+}
+
+/**
+ The main client function of the GSSAPI plugin.
+ */
+static int gssapi_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ int packet_len;
+ unsigned char *packet;
+ char spn[PRINCIPAL_NAME_MAX + 1];
+ char mech[MECH_NAME_MAX + 1];
+
+ /* read from server for service principal name */
+ packet_len= vio->read_packet(vio, &packet);
+ if (packet_len < 0)
+ {
+ return CR_ERROR;
+ }
+ parse_server_packet((char *)packet, (size_t)packet_len, spn, mech);
+ return auth_client(spn, mech, mysql, vio);
+}
+
+
+/* register client plugin */
+mysql_declare_client_plugin(AUTHENTICATION)
+ "auth_gssapi_client",
+ "Shuang Qiu, Robbie Harwood, Vladislav Vaintroub",
+ "GSSAPI/SSPI based authentication",
+ {0, 1, 0},
+ "BSD",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gssapi_auth_client
+mysql_end_client_plugin;
diff --git a/plugin/auth_gssapi/cmake/FindGSSAPI.cmake b/plugin/auth_gssapi/cmake/FindGSSAPI.cmake
new file mode 100644
index 00000000000..67309eed1ee
--- /dev/null
+++ b/plugin/auth_gssapi/cmake/FindGSSAPI.cmake
@@ -0,0 +1,98 @@
+# - Try to detect the GSSAPI support
+# Once done this will define
+#
+# GSSAPI_FOUND - system supports GSSAPI
+# GSSAPI_INCS - the GSSAPI include directory
+# GSSAPI_LIBS - the libraries needed to use GSSAPI
+# GSSAPI_FLAVOR - the type of API - MIT or HEIMDAL
+
+# Copyright (c) 2006, Pino Toscano, <toscano.pino@tiscali.it>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+if(GSSAPI_LIBS AND GSSAPI_FLAVOR)
+
+ # in cache already
+ set(GSSAPI_FOUND TRUE)
+
+else(GSSAPI_LIBS AND GSSAPI_FLAVOR)
+
+ find_program(KRB5_CONFIG NAMES krb5-config heimdal-krb5-config PATHS
+ /opt/local/bin /usr/lib/mit/bin
+ ONLY_CMAKE_FIND_ROOT_PATH # this is required when cross compiling with cmake 2.6 and ignored with cmake 2.4, Alex
+ )
+ mark_as_advanced(KRB5_CONFIG)
+
+ #reset vars
+ set(GSSAPI_INCS)
+ set(GSSAPI_LIBS)
+ set(GSSAPI_FLAVOR)
+
+ if(KRB5_CONFIG)
+
+ set(HAVE_KRB5_GSSAPI TRUE)
+ exec_program(${KRB5_CONFIG} ARGS --libs gssapi RETURN_VALUE _return_VALUE OUTPUT_VARIABLE GSSAPI_LIBS)
+ if(_return_VALUE)
+ message(STATUS "GSSAPI configure check failed.")
+ set(HAVE_KRB5_GSSAPI FALSE)
+ endif(_return_VALUE)
+
+ exec_program(${KRB5_CONFIG} ARGS --cflags gssapi RETURN_VALUE _return_VALUE OUTPUT_VARIABLE GSSAPI_INCS)
+ string(REGEX REPLACE "(\r?\n)+$" "" GSSAPI_INCS "${GSSAPI_INCS}")
+ string(REGEX REPLACE " *-I" ";" GSSAPI_INCS "${GSSAPI_INCS}")
+
+ exec_program(${KRB5_CONFIG} ARGS --vendor RETURN_VALUE _return_VALUE OUTPUT_VARIABLE gssapi_flavor_tmp)
+ set(GSSAPI_FLAVOR_MIT)
+ if(gssapi_flavor_tmp MATCHES ".*Massachusetts.*")
+ set(GSSAPI_FLAVOR "MIT")
+ else(gssapi_flavor_tmp MATCHES ".*Massachusetts.*")
+ set(GSSAPI_FLAVOR "HEIMDAL")
+ endif(gssapi_flavor_tmp MATCHES ".*Massachusetts.*")
+
+ if(NOT HAVE_KRB5_GSSAPI)
+ if (gssapi_flavor_tmp MATCHES "Sun Microsystems.*")
+ message(STATUS "Solaris Kerberos does not have GSSAPI; this is normal.")
+ set(GSSAPI_LIBS)
+ set(GSSAPI_INCS)
+ else(gssapi_flavor_tmp MATCHES "Sun Microsystems.*")
+ message(WARNING "${KRB5_CONFIG} failed unexpectedly.")
+ endif(gssapi_flavor_tmp MATCHES "Sun Microsystems.*")
+ endif(NOT HAVE_KRB5_GSSAPI)
+
+ if(GSSAPI_LIBS) # GSSAPI_INCS can be also empty, so don't rely on that
+ set(GSSAPI_FOUND TRUE CACHE STRING "")
+ message(STATUS "Found GSSAPI: ${GSSAPI_LIBS}")
+
+ set(GSSAPI_INCS ${GSSAPI_INCS} CACHE STRING "")
+ set(GSSAPI_LIBS ${GSSAPI_LIBS} CACHE STRING "")
+ set(GSSAPI_FLAVOR ${GSSAPI_FLAVOR} CACHE STRING "")
+
+ mark_as_advanced(GSSAPI_INCS GSSAPI_LIBS GSSAPI_FLAVOR)
+
+ endif(GSSAPI_LIBS)
+
+ endif(KRB5_CONFIG)
+
+endif(GSSAPI_LIBS AND GSSAPI_FLAVOR)
diff --git a/plugin/auth_gssapi/common.h b/plugin/auth_gssapi/common.h
new file mode 100644
index 00000000000..c04241acff9
--- /dev/null
+++ b/plugin/auth_gssapi/common.h
@@ -0,0 +1,4 @@
+/** Maximal length of the target name */
+#define PRINCIPAL_NAME_MAX 256
+/** Maximal length of the mech string */
+#define MECH_NAME_MAX 30
diff --git a/plugin/auth_gssapi/gssapi_client.cc b/plugin/auth_gssapi/gssapi_client.cc
new file mode 100644
index 00000000000..a05ea158e4d
--- /dev/null
+++ b/plugin/auth_gssapi/gssapi_client.cc
@@ -0,0 +1,127 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <gssapi/gssapi.h>
+#include <string.h>
+#include <stdio.h>
+#include <mysql/plugin_auth.h>
+#include <mysqld_error.h>
+#include <mysql.h>
+#include "gssapi_errmsg.h"
+
+extern void log_client_error(MYSQL *mysql,const char *fmt,...);
+
+
+/* This sends the error to the client */
+static void log_error(MYSQL *mysql, OM_uint32 major, OM_uint32 minor, const char *msg)
+{
+ if (GSS_ERROR(major))
+ {
+ char sysmsg[1024];
+ gssapi_errmsg(major, minor, sysmsg, sizeof(sysmsg));
+ log_client_error(mysql,
+ "Client GSSAPI error (major %u, minor %u) : %s - %s",
+ major, minor, msg, sysmsg);
+ }
+ else
+ {
+ log_client_error(mysql, "Client GSSAPI error : %s", msg);
+ }
+}
+
+int auth_client(char *principal_name, char *mech, MYSQL *mysql, MYSQL_PLUGIN_VIO *vio)
+{
+
+ int ret= CR_ERROR;
+ OM_uint32 major= 0, minor= 0;
+ gss_ctx_id_t ctxt= GSS_C_NO_CONTEXT;
+ gss_name_t service_name= GSS_C_NO_NAME;
+
+ if (principal_name && principal_name[0])
+ {
+ /* import principal from plain text */
+ gss_buffer_desc principal_name_buf;
+ principal_name_buf.length= strlen(principal_name);
+ principal_name_buf.value= (void *) principal_name;
+ major= gss_import_name(&minor, &principal_name_buf, GSS_C_NT_USER_NAME, &service_name);
+ if (GSS_ERROR(major))
+ {
+ log_error(mysql, major, minor, "gss_import_name");
+ return CR_ERROR;
+ }
+ }
+
+ gss_buffer_desc input= {0,0};
+ do
+ {
+ gss_buffer_desc output= {0,0};
+ major= gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ctxt, service_name,
+ GSS_C_NO_OID, 0, 0, GSS_C_NO_CHANNEL_BINDINGS,
+ &input, NULL, &output, NULL, NULL);
+ if (output.length)
+ {
+ /* send credential */
+ if(vio->write_packet(vio, (unsigned char *)output.value, output.length))
+ {
+ /* Server error packet contains detailed message. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ gss_release_buffer (&minor, &output);
+ goto cleanup;
+ }
+ }
+ gss_release_buffer (&minor, &output);
+
+ if (GSS_ERROR(major))
+ {
+ log_error(mysql, major, minor,"gss_init_sec_context");
+ goto cleanup;
+ }
+
+ if (major & GSS_S_CONTINUE_NEEDED)
+ {
+ int len= vio->read_packet(vio, (unsigned char **) &input.value);
+ if (len <= 0)
+ {
+ /* Server error packet contains detailed message. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ goto cleanup;
+ }
+ input.length= len;
+ }
+ } while (major & GSS_S_CONTINUE_NEEDED);
+
+ ret= CR_OK;
+
+cleanup:
+ if (service_name != GSS_C_NO_NAME)
+ gss_release_name(&minor, &service_name);
+ if (ctxt != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor, &ctxt, GSS_C_NO_BUFFER);
+
+ return ret;
+}
diff --git a/plugin/auth_gssapi/gssapi_errmsg.cc b/plugin/auth_gssapi/gssapi_errmsg.cc
new file mode 100644
index 00000000000..8ea4cab5b02
--- /dev/null
+++ b/plugin/auth_gssapi/gssapi_errmsg.cc
@@ -0,0 +1,75 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <gssapi.h>
+#include <string.h>
+void gssapi_errmsg(OM_uint32 major, OM_uint32 minor, char *buf, size_t size)
+{
+ OM_uint32 message_context;
+ OM_uint32 status_code;
+ OM_uint32 maj_status;
+ OM_uint32 min_status;
+ gss_buffer_desc status_string;
+ char *p= buf;
+ char *end= buf + size - 1;
+ int types[] = {GSS_C_GSS_CODE,GSS_C_MECH_CODE};
+
+ for(int i= 0; i < 2;i++)
+ {
+ message_context= 0;
+ status_code= types[i] == GSS_C_GSS_CODE?major:minor;
+
+ if(!status_code)
+ continue;
+ do
+ {
+ maj_status = gss_display_status(
+ &min_status,
+ status_code,
+ types[i],
+ GSS_C_NO_OID,
+ &message_context,
+ &status_string);
+
+ if(maj_status)
+ break;
+
+ if(p + status_string.length + 2 < end)
+ {
+ memcpy(p,status_string.value, status_string.length);
+ p += status_string.length;
+ *p++ = '.';
+ *p++ = ' ';
+ }
+
+ gss_release_buffer(&min_status, &status_string);
+ }
+ while (message_context != 0);
+ }
+ *p= 0;
+}
diff --git a/plugin/auth_gssapi/gssapi_errmsg.h b/plugin/auth_gssapi/gssapi_errmsg.h
new file mode 100644
index 00000000000..26db8439e04
--- /dev/null
+++ b/plugin/auth_gssapi/gssapi_errmsg.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+extern void gssapi_errmsg(OM_uint32 major, OM_uint32 minor, char *buf, size_t size);
diff --git a/plugin/auth_gssapi/gssapi_server.cc b/plugin/auth_gssapi/gssapi_server.cc
new file mode 100644
index 00000000000..50c34ecc573
--- /dev/null
+++ b/plugin/auth_gssapi/gssapi_server.cc
@@ -0,0 +1,253 @@
+#include <my_config.h>
+#include <gssapi/gssapi.h>
+#include <stdio.h>
+#include <mysql/plugin_auth.h>
+#include <my_sys.h>
+#include <mysqld_error.h>
+#include <log.h>
+#include "server_plugin.h"
+#include "gssapi_errmsg.h"
+
+static gss_name_t service_name = GSS_C_NO_NAME;
+
+/* This sends the error to the client */
+static void log_error( OM_uint32 major, OM_uint32 minor, const char *msg)
+{
+ if (GSS_ERROR(major))
+ {
+ char sysmsg[1024];
+ gssapi_errmsg(major, minor, sysmsg, sizeof(sysmsg));
+ my_printf_error(ER_UNKNOWN_ERROR,"Server GSSAPI error (major %u, minor %u) : %s -%s",
+ MYF(0), major, minor, msg, sysmsg);
+ }
+ else
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "Server GSSAPI error : %s", MYF(0), msg);
+ }
+}
+
+
+/*
+ Generate default principal service name formatted as principal name "mariadb/server.fqdn@REALM"
+*/
+#include <krb5.h>
+#ifndef HAVE_KRB5_FREE_UNPARSED_NAME
+#define krb5_free_unparsed_name(a,b) krb5_xfree(b)
+#endif
+static char* get_default_principal_name()
+{
+ static char default_name[1024];
+ char *unparsed_name= NULL;
+ krb5_context context= NULL;
+ krb5_principal principal= NULL;
+ krb5_keyblock *key= NULL;
+
+ if(krb5_init_context(&context))
+ {
+ my_printf_error(0, "GSSAPI plugin : krb5_init_context failed",
+ ME_ERROR_LOG | ME_WARNING);
+ goto cleanup;
+ }
+
+ if (krb5_sname_to_principal(context, NULL, "mariadb", KRB5_NT_SRV_HST, &principal))
+ {
+ my_printf_error(0, "GSSAPI plugin : krb5_sname_to_principal failed",
+ ME_ERROR_LOG | ME_WARNING);
+ goto cleanup;
+ }
+
+ if (krb5_unparse_name(context, principal, &unparsed_name))
+ {
+ my_printf_error(0, "GSSAPI plugin : krb5_unparse_name failed",
+ ME_ERROR_LOG | ME_WARNING);
+ goto cleanup;
+ }
+
+ /* Check for entry in keytab */
+ if (krb5_kt_read_service_key(context, NULL, principal, 0, (krb5_enctype)0, &key))
+ {
+ my_printf_error(0, "GSSAPI plugin : default principal '%s' not found in keytab",
+ ME_ERROR_LOG | ME_WARNING, unparsed_name);
+ goto cleanup;
+ }
+
+ strncpy(default_name, unparsed_name, sizeof(default_name)-1);
+
+cleanup:
+ if (key)
+ krb5_free_keyblock(context, key);
+ if (unparsed_name)
+ krb5_free_unparsed_name(context, unparsed_name);
+ if (principal)
+ krb5_free_principal(context, principal);
+ if (context)
+ krb5_free_context(context);
+
+ return default_name;
+}
+
+
+int plugin_init()
+{
+ gss_buffer_desc principal_name_buf;
+ OM_uint32 major= 0, minor= 0;
+ gss_cred_id_t cred= GSS_C_NO_CREDENTIAL;
+
+ if(srv_keytab_path && srv_keytab_path[0])
+ {
+ setenv("KRB5_KTNAME", srv_keytab_path, 1);
+ }
+
+ if(!srv_principal_name || !srv_principal_name[0])
+ srv_principal_name= get_default_principal_name();
+
+ /* import service principal from plain text */
+ if(srv_principal_name && srv_principal_name[0])
+ {
+ my_printf_error(0, "GSSAPI plugin : using principal name '%s'",
+ ME_ERROR_LOG | ME_NOTE, srv_principal_name);
+ principal_name_buf.length= strlen(srv_principal_name);
+ principal_name_buf.value= srv_principal_name;
+ major= gss_import_name(&minor, &principal_name_buf, GSS_C_NT_USER_NAME, &service_name);
+ if(GSS_ERROR(major))
+ {
+ log_error(major, minor, "gss_import_name");
+ return -1;
+ }
+ }
+ else
+ {
+ service_name= GSS_C_NO_NAME;
+ }
+
+ /* Check if SPN configuration is OK */
+ major= gss_acquire_cred(&minor, service_name, GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL,
+ NULL);
+
+ if (GSS_ERROR(major))
+ {
+ log_error(major, minor, "gss_acquire_cred failed");
+ return -1;
+ }
+ gss_release_cred(&minor, &cred);
+
+ return 0;
+}
+
+int plugin_deinit()
+{
+ if (service_name != GSS_C_NO_NAME)
+ {
+ OM_uint32 minor;
+ gss_release_name(&minor, &service_name);
+ }
+ return 0;
+}
+
+
+int auth_server(MYSQL_PLUGIN_VIO *vio,const char *user, size_t userlen, int use_full_name)
+{
+
+ int rc= CR_ERROR; /* return code */
+
+ /* GSSAPI related fields */
+ OM_uint32 major= 0, minor= 0, flags= 0;
+ gss_cred_id_t cred= GSS_C_NO_CREDENTIAL; /* credential identifier */
+ gss_ctx_id_t ctxt= GSS_C_NO_CONTEXT; /* context identifier */
+ gss_name_t client_name;
+ gss_buffer_desc client_name_buf, input, output;
+ char *client_name_str;
+
+ /* server acquires credential */
+ major= gss_acquire_cred(&minor, service_name, GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL,
+ NULL);
+
+ if (GSS_ERROR(major))
+ {
+ log_error(major, minor, "gss_acquire_cred failed");
+ goto cleanup;
+ }
+
+ input.length= 0;
+ input.value= NULL;
+ do
+ {
+ /* receive token from peer */
+ int len= vio->read_packet(vio, (unsigned char **) &input.value);
+ if (len < 0)
+ {
+ log_error(0, 0, "fail to read token from client");
+ goto cleanup;
+ }
+
+ input.length= len;
+ major= gss_accept_sec_context(&minor, &ctxt, cred, &input,
+ GSS_C_NO_CHANNEL_BINDINGS, &client_name,
+ NULL, &output, &flags, NULL, NULL);
+ if (GSS_ERROR(major))
+ {
+
+ log_error(major, minor, "gss_accept_sec_context");
+ rc= CR_ERROR;
+ goto cleanup;
+ }
+
+ /* send token to peer */
+ if (output.length)
+ {
+ if (vio->write_packet(vio, (const uchar *) output.value, output.length))
+ {
+ gss_release_buffer(&minor, &output);
+ log_error(major, minor, "communication error(write)");
+ goto cleanup;
+ }
+ gss_release_buffer(&minor, &output);
+ }
+ } while (major & GSS_S_CONTINUE_NEEDED);
+
+ /* extract plain text client name */
+ major= gss_display_name(&minor, client_name, &client_name_buf, NULL);
+ if (GSS_ERROR(major))
+ {
+ log_error(major, minor, "gss_display_name");
+ goto cleanup;
+ }
+
+ client_name_str= (char *)client_name_buf.value;
+
+ /*
+ * Compare input user name with the actual one. Return success if
+ * the names match exactly, or if use_full_name parameter is not set
+ * up to the '@' separator.
+ */
+ if ((userlen == client_name_buf.length) ||
+ (!use_full_name
+ && userlen < client_name_buf.length
+ && client_name_str[userlen] == '@'))
+ {
+ if (strncmp(client_name_str, user, userlen) == 0)
+ {
+ rc= CR_OK;
+ }
+ }
+
+ if(rc != CR_OK)
+ {
+ my_printf_error(ER_ACCESS_DENIED_ERROR,
+ "GSSAPI name mismatch, requested '%s', actual name '%.*s'",
+ MYF(0), user, (int)client_name_buf.length, client_name_str);
+ }
+
+ gss_release_buffer(&minor, &client_name_buf);
+
+
+cleanup:
+ if (ctxt != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor, &ctxt, GSS_C_NO_BUFFER);
+ if (cred != GSS_C_NO_CREDENTIAL)
+ gss_release_cred(&minor, &cred);
+
+ return(rc);
+}
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.result b/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.result
new file mode 100644
index 00000000000..3044f984ffa
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.result
@@ -0,0 +1,20 @@
+INSTALL SONAME 'auth_gssapi';
+Warnings:
+Note 1105 SSPI: using principal name 'localhost', mech 'Negotiate'
+CREATE USER 'GSSAPI_SHORTNAME' IDENTIFIED WITH gssapi;
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+GSSAPI_SHORTNAME@localhost GSSAPI_SHORTNAME@%
+DROP USER 'GSSAPI_SHORTNAME';
+CREATE USER nosuchuser IDENTIFIED WITH gssapi;
+ERROR 28000: GSSAPI name mismatch, requested 'nosuchuser', actual name 'GSSAPI_SHORTNAME'
+DROP USER nosuchuser;
+CREATE USER usr1 IDENTIFIED WITH gssapi as 'GSSAPI_FULLNAME';
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+usr1@localhost usr1@%
+DROP USER usr1;
+CREATE USER nosuchuser IDENTIFIED WITH gssapi AS 'nosuchuser@EXAMPLE.COM';
+ERROR 28000: GSSAPI name mismatch, requested 'nosuchuser@EXAMPLE.COM', actual name 'GSSAPI_FULLNAME'
+DROP USER nosuchuser;
+UNINSTALL SONAME 'auth_gssapi';
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.test b/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.test
new file mode 100644
index 00000000000..2307aa3934a
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.test
@@ -0,0 +1,46 @@
+--replace_regex /name '[^']+'/name 'localhost'/
+INSTALL SONAME 'auth_gssapi';
+
+#
+# CREATE USER without 'AS' clause
+#
+--replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME
+eval CREATE USER '$GSSAPI_SHORTNAME' IDENTIFIED WITH 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';
+
+CREATE USER nosuchuser IDENTIFIED WITH gssapi;
+--disable_query_log
+--replace_regex /actual name '.*'/actual name 'GSSAPI_SHORTNAME'/
+--error ER_ACCESS_DENIED_ERROR
+connect (con1,localhost,nosuchuser,,);
+--enable_query_log
+DROP USER nosuchuser;
+
+#
+# CREATE USER with 'AS' clause
+#
+--replace_result $GSSAPI_FULLNAME GSSAPI_FULLNAME
+eval CREATE USER usr1 IDENTIFIED WITH gssapi as '$GSSAPI_FULLNAME';
+connect (con1,localhost,usr1,,);
+--replace_result $GSSAPI_FULLNAME GSSAPI_FULLNAME
+SELECT USER(),CURRENT_USER();
+disconnect con1;
+connection default;
+DROP USER usr1;
+
+CREATE USER nosuchuser IDENTIFIED WITH gssapi AS 'nosuchuser@EXAMPLE.COM';
+--disable_query_log
+--replace_regex /actual name '.*'/actual name 'GSSAPI_FULLNAME'/
+--error ER_ACCESS_DENIED_ERROR
+connect (con1,localhost,nosuchuser,,);
+--enable_query_log
+DROP USER nosuchuser;
+
+UNINSTALL SONAME 'auth_gssapi'; \ No newline at end of file
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.opt b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.opt
new file mode 100644
index 00000000000..3077d70c9c3
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.opt
@@ -0,0 +1 @@
+--loose-gssapi-keytab-path=$GSSAPI_KEYTAB_PATH --loose-gssapi-principal-name=$GSSAPI_PRINCIPAL_NAME
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm
new file mode 100644
index 00000000000..aa225536a1e
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm
@@ -0,0 +1,49 @@
+package My::Suite::AuthGSSAPI;
+
+@ISA = qw(My::Suite);
+
+return "No AUTH_GSSAPI plugin" unless $ENV{AUTH_GSSAPI_SO};
+
+return "Not run for embedded server" if $::opt_embedded_server;
+
+# Following environment variables may need to be set
+if ($^O eq "MSWin32")
+{
+ chomp(my $whoami =`whoami /UPN 2>NUL` || `whoami`);
+ my $fullname = $whoami;
+ $fullname =~ s/\\/\\\\/; # SQL escaping for backslash
+ $ENV{'GSSAPI_FULLNAME'} = $fullname;
+ $ENV{'GSSAPI_SHORTNAME'} = $ENV{'USERNAME'};
+}
+else
+{
+ if (!$ENV{'GSSAPI_FULLNAME'})
+ {
+ my $s = `klist 2>/dev/null |grep 'Default principal: '`;
+ if ($s)
+ {
+ chomp($s);
+ my $fullname = substr($s,19);
+ $ENV{'GSSAPI_FULLNAME'} = $fullname;
+ }
+ }
+ $ENV{'GSSAPI_SHORTNAME'} = (split /@/, $ENV{'GSSAPI_FULLNAME'}) [0];
+}
+
+
+if (!$ENV{'GSSAPI_FULLNAME'} || !$ENV{'GSSAPI_SHORTNAME'})
+{
+ return "Environment variable GSSAPI_SHORTNAME and GSSAPI_FULLNAME need to be set"
+}
+
+if ($::opt_verbose)
+{
+ foreach $var ('GSSAPI_SHORTNAME','GSSAPI_FULLNAME','GSSAPI_KEYTAB_PATH','GSSAPI_PRINCIPAL_NAME')
+ {
+ print "$var=$ENV{$var}\n";
+ }
+}
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/auth_gssapi/server_plugin.cc b/plugin/auth_gssapi/server_plugin.cc
new file mode 100644
index 00000000000..0c0bcbbbb72
--- /dev/null
+++ b/plugin/auth_gssapi/server_plugin.cc
@@ -0,0 +1,183 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+ Vladislav Vaintroub & MariaDB Corporation
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ @file
+
+ GSSAPI authentication plugin, server side
+*/
+#include <my_sys.h>
+#include <mysqld_error.h>
+#include <mysql/plugin_auth.h>
+#include "server_plugin.h"
+#include "common.h"
+
+/* First packet sent from server to client, contains srv_principal_name\0mech\0 */
+static char first_packet[PRINCIPAL_NAME_MAX + MECH_NAME_MAX +2];
+static int first_packet_len;
+
+/*
+ Target name in GSSAPI/SSPI , for Kerberos it is service principal name
+ (often user principal name of the server user will work)
+*/
+char *srv_principal_name;
+char *srv_keytab_path;
+char *srv_mech_name=(char *)"";
+unsigned long srv_mech;
+
+/**
+ The main server function of the GSSAPI plugin.
+ */
+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);
+}
+
+static int initialize_plugin(void *unused)
+{
+ int rc;
+ rc = plugin_init();
+ if (rc)
+ return rc;
+
+ strcpy(first_packet, srv_principal_name);
+ strcpy(first_packet + strlen(srv_principal_name) + 1,srv_mech_name);
+ first_packet_len = strlen(srv_principal_name) + strlen(srv_mech_name) + 2;
+
+ return 0;
+}
+
+static int deinitialize_plugin(void *unused)
+{
+ return plugin_deinit();
+}
+
+/* system variable */
+static MYSQL_SYSVAR_STR(keytab_path, srv_keytab_path,
+ PLUGIN_VAR_RQCMDARG|PLUGIN_VAR_READONLY,
+ "Keytab file path for Kerberos authentication",
+ NULL,
+ NULL,
+ "");
+static MYSQL_SYSVAR_STR(principal_name, srv_principal_name,
+ PLUGIN_VAR_RQCMDARG|PLUGIN_VAR_READONLY,
+ "GSSAPI target name - service principal name for Kerberos authentication.",
+ NULL,
+ NULL,
+ "");
+#ifdef PLUGIN_SSPI
+static const char* mech_names[] = {
+ "Kerberos",
+ "Negotiate",
+ "",
+ NULL
+};
+static TYPELIB mech_name_typelib = {
+ array_elements(mech_names) - 1,
+ "mech_name_typelib",
+ mech_names,
+ NULL
+};
+static MYSQL_SYSVAR_ENUM(mech_name, srv_mech,
+ PLUGIN_VAR_RQCMDARG|PLUGIN_VAR_READONLY,
+ "GSSAPI mechanism",
+ NULL,
+ NULL,
+ 2,&mech_name_typelib);
+#endif
+
+static struct st_mysql_sys_var *system_variables[]= {
+ MYSQL_SYSVAR(principal_name),
+#ifdef PLUGIN_SSPI
+ MYSQL_SYSVAR(mech_name),
+#endif
+#ifdef PLUGIN_GSSAPI
+ MYSQL_SYSVAR(keytab_path),
+#endif
+ NULL
+};
+
+/* Register authentication plugin */
+static struct st_mysql_auth server_handler= {
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "auth_gssapi_client",
+ gssapi_auth
+};
+
+maria_declare_plugin(gssapi_server)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &server_handler,
+ "gssapi",
+ "Shuang Qiu, Robbie Harwood, Vladislav Vaintroub",
+ "Plugin for GSSAPI/SSPI based authentication.",
+ PLUGIN_LICENSE_BSD,
+ initialize_plugin,
+ deinitialize_plugin, /* destructor */
+ 0x0100, /* version */
+ NULL, /* status variables */
+ system_variables, /* system variables */
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/auth_gssapi/server_plugin.h b/plugin/auth_gssapi/server_plugin.h
new file mode 100644
index 00000000000..1348835e653
--- /dev/null
+++ b/plugin/auth_gssapi/server_plugin.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Plugin variables*/
+#include <mysql/plugin_auth.h>
+typedef enum
+{
+ PLUGIN_MECH_KERBEROS = 0,
+ PLUGIN_MECH_SPNEGO = 1,
+ PLUGIN_MECH_DEFAULT = 2
+}PLUGIN_MECH;
+
+extern unsigned long srv_mech;
+extern char *srv_principal_name;
+extern char *srv_mech_name;
+extern char *srv_keytab_path;
+/*
+ Check, with GSSAPI/SSPI username of logged on user.
+
+ Depending on use_full_name parameter, compare either full name
+ (principal name like user@real), or local name (first component)
+*/
+int plugin_init();
+int plugin_deinit();
+
+int auth_server(MYSQL_PLUGIN_VIO *vio, const char *username, size_t username_len, int use_full_name);
diff --git a/plugin/auth_gssapi/sspi.h b/plugin/auth_gssapi/sspi.h
new file mode 100644
index 00000000000..34b8a56a32e
--- /dev/null
+++ b/plugin/auth_gssapi/sspi.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define SECURITY_WIN32
+#include <windows.h>
+#include <sspi.h>
+#include <SecExt.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#define SSPI_MAX_TOKEN_SIZE 50000
+#define SEC_ERROR(err) (err < 0)
+extern void sspi_errmsg(int err, char *buf, size_t size); \ No newline at end of file
diff --git a/plugin/auth_gssapi/sspi_client.cc b/plugin/auth_gssapi/sspi_client.cc
new file mode 100644
index 00000000000..34c1ce2e7ee
--- /dev/null
+++ b/plugin/auth_gssapi/sspi_client.cc
@@ -0,0 +1,183 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define SECURITY_WIN32
+#include <windows.h>
+#include <sspi.h>
+#include <SecExt.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <mysql/plugin_auth.h>
+#include <mysql.h>
+#include <mysqld_error.h>
+
+#include "sspi.h"
+
+extern void log_client_error(MYSQL *mysql, const char *fmt, ...);
+static void log_error(MYSQL *mysql, SECURITY_STATUS err, const char *msg)
+{
+ if (err)
+ {
+ char buf[1024];
+ sspi_errmsg(err, buf, sizeof(buf));
+ log_client_error(mysql, "SSPI client error 0x%x - %s - %s", err, msg, buf);
+ }
+ else
+ {
+ log_client_error(mysql, "SSPI client error %s", msg);
+ }
+}
+
+
+/** Client side authentication*/
+int auth_client(char *principal_name, char *mech, MYSQL *mysql, MYSQL_PLUGIN_VIO *vio)
+{
+
+ int ret;
+ CredHandle cred;
+ CtxtHandle ctxt;
+ ULONG attribs = 0;
+ TimeStamp lifetime;
+ SECURITY_STATUS sspi_err;
+
+ SecBufferDesc inbuf_desc;
+ SecBuffer inbuf;
+ SecBufferDesc outbuf_desc;
+ SecBuffer outbuf;
+ PBYTE out = NULL;
+
+ ret= CR_ERROR;
+ SecInvalidateHandle(&ctxt);
+ SecInvalidateHandle(&cred);
+
+ if (!mech || strcmp(mech, "Negotiate") != 0)
+ {
+ mech= "Kerberos";
+ }
+
+ sspi_err = AcquireCredentialsHandle(
+ NULL,
+ mech,
+ SECPKG_CRED_OUTBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred,
+ &lifetime);
+
+ if (SEC_ERROR(sspi_err))
+ {
+ log_error(mysql, sspi_err, "AcquireCredentialsHandle");
+ return CR_ERROR;
+ }
+
+ out = (PBYTE)malloc(SSPI_MAX_TOKEN_SIZE);
+ if (!out)
+ {
+ log_error(mysql, SEC_E_OK, "memory allocation error");
+ goto cleanup;
+ }
+
+ /* Prepare buffers */
+ inbuf_desc.ulVersion = SECBUFFER_VERSION;
+ inbuf_desc.cBuffers = 1;
+ inbuf_desc.pBuffers = &inbuf;
+ inbuf.BufferType = SECBUFFER_TOKEN;
+ inbuf.cbBuffer = 0;
+ inbuf.pvBuffer = NULL;
+
+ outbuf_desc.ulVersion = SECBUFFER_VERSION;
+ outbuf_desc.cBuffers = 1;
+ outbuf_desc.pBuffers = &outbuf;
+ outbuf.BufferType = SECBUFFER_TOKEN;
+ outbuf.pvBuffer = out;
+
+ do
+ {
+ outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
+ sspi_err= InitializeSecurityContext(
+ &cred,
+ SecIsValidHandle(&ctxt) ? &ctxt : NULL,
+ principal_name,
+ 0,
+ 0,
+ SECURITY_NATIVE_DREP,
+ inbuf.cbBuffer ? &inbuf_desc : NULL,
+ 0,
+ &ctxt,
+ &outbuf_desc,
+ &attribs,
+ &lifetime);
+ if (SEC_ERROR(sspi_err))
+ {
+ log_error(mysql, sspi_err, "InitializeSecurityContext");
+ goto cleanup;
+ }
+ if (sspi_err != SEC_E_OK && sspi_err != SEC_I_CONTINUE_NEEDED)
+ {
+ log_error(mysql, sspi_err, "Unexpected response from InitializeSecurityContext");
+ goto cleanup;
+ }
+
+ if (outbuf.cbBuffer)
+ {
+ /* send credential to server */
+ if (vio->write_packet(vio, (unsigned char *)outbuf.pvBuffer, outbuf.cbBuffer))
+ {
+ /* Server error packet contains detailed message. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ goto cleanup;
+ }
+ }
+
+ if (sspi_err == SEC_I_CONTINUE_NEEDED)
+ {
+ int len= vio->read_packet(vio, (unsigned char **)&inbuf.pvBuffer);
+ if (len <= 0)
+ {
+ /* Server side error is in the last server packet. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ goto cleanup;
+ }
+ inbuf.cbBuffer= len;
+ }
+ } while (sspi_err == SEC_I_CONTINUE_NEEDED);
+
+ ret= CR_OK;
+
+cleanup:
+
+ if (SecIsValidHandle(&ctxt))
+ DeleteSecurityContext(&ctxt);
+ if (SecIsValidHandle(&cred))
+ FreeCredentialsHandle(&cred);
+ free(out);
+ return ret;
+} \ No newline at end of file
diff --git a/plugin/auth_gssapi/sspi_errmsg.cc b/plugin/auth_gssapi/sspi_errmsg.cc
new file mode 100644
index 00000000000..961ef51f42e
--- /dev/null
+++ b/plugin/auth_gssapi/sspi_errmsg.cc
@@ -0,0 +1,150 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <windows.h>
+#include <stdio.h>
+
+#define ERRSYM(x) {x, #x}
+static struct {
+ int error;
+ const char *sym;
+} error_symbols[] =
+{
+ ERRSYM(SEC_E_OK),
+ ERRSYM(SEC_E_INSUFFICIENT_MEMORY),
+ ERRSYM(SEC_E_INVALID_HANDLE),
+ ERRSYM(SEC_E_UNSUPPORTED_FUNCTION),
+ ERRSYM(SEC_E_TARGET_UNKNOWN),
+ ERRSYM(SEC_E_INTERNAL_ERROR),
+ ERRSYM(SEC_E_SECPKG_NOT_FOUND),
+ ERRSYM(SEC_E_NOT_OWNER),
+ ERRSYM(SEC_E_CANNOT_INSTALL),
+ ERRSYM(SEC_E_INVALID_TOKEN),
+ ERRSYM(SEC_E_CANNOT_PACK),
+ ERRSYM(SEC_E_QOP_NOT_SUPPORTED),
+ ERRSYM(SEC_E_NO_IMPERSONATION),
+ ERRSYM(SEC_E_LOGON_DENIED),
+ ERRSYM(SEC_E_UNKNOWN_CREDENTIALS),
+ ERRSYM(SEC_E_NO_CREDENTIALS),
+ ERRSYM(SEC_E_MESSAGE_ALTERED),
+ ERRSYM(SEC_E_OUT_OF_SEQUENCE),
+ ERRSYM(SEC_E_NO_AUTHENTICATING_AUTHORITY),
+ ERRSYM(SEC_E_BAD_PKGID),
+ ERRSYM(SEC_E_CONTEXT_EXPIRED),
+ ERRSYM(SEC_E_INCOMPLETE_MESSAGE),
+ ERRSYM(SEC_E_INCOMPLETE_CREDENTIALS),
+ ERRSYM(SEC_E_BUFFER_TOO_SMALL),
+ ERRSYM(SEC_E_WRONG_PRINCIPAL),
+ ERRSYM(SEC_E_TIME_SKEW),
+ ERRSYM(SEC_E_UNTRUSTED_ROOT),
+ ERRSYM(SEC_E_ILLEGAL_MESSAGE),
+ ERRSYM(SEC_E_CERT_UNKNOWN),
+ ERRSYM(SEC_E_CERT_EXPIRED),
+ ERRSYM(SEC_E_ENCRYPT_FAILURE),
+ ERRSYM(SEC_E_DECRYPT_FAILURE),
+ ERRSYM(SEC_E_ALGORITHM_MISMATCH),
+ ERRSYM(SEC_E_SECURITY_QOS_FAILED),
+ ERRSYM(SEC_E_UNFINISHED_CONTEXT_DELETED),
+ ERRSYM(SEC_E_NO_TGT_REPLY),
+ ERRSYM(SEC_E_NO_IP_ADDRESSES),
+ ERRSYM(SEC_E_WRONG_CREDENTIAL_HANDLE),
+ ERRSYM(SEC_E_CRYPTO_SYSTEM_INVALID),
+ ERRSYM(SEC_E_MAX_REFERRALS_EXCEEDED),
+ ERRSYM(SEC_E_MUST_BE_KDC),
+ ERRSYM(SEC_E_STRONG_CRYPTO_NOT_SUPPORTED),
+ ERRSYM(SEC_E_TOO_MANY_PRINCIPALS),
+ ERRSYM(SEC_E_NO_PA_DATA),
+ ERRSYM(SEC_E_PKINIT_NAME_MISMATCH),
+ ERRSYM(SEC_E_SMARTCARD_LOGON_REQUIRED),
+ ERRSYM(SEC_E_SHUTDOWN_IN_PROGRESS),
+ ERRSYM(SEC_E_KDC_INVALID_REQUEST),
+ ERRSYM(SEC_E_KDC_UNABLE_TO_REFER),
+ ERRSYM(SEC_E_KDC_UNKNOWN_ETYPE),
+ ERRSYM(SEC_E_UNSUPPORTED_PREAUTH),
+ ERRSYM(SEC_E_DELEGATION_REQUIRED),
+ ERRSYM(SEC_E_BAD_BINDINGS),
+ ERRSYM(SEC_E_MULTIPLE_ACCOUNTS),
+ ERRSYM(SEC_E_NO_KERB_KEY),
+ ERRSYM(SEC_E_CERT_WRONG_USAGE),
+ ERRSYM(SEC_E_DOWNGRADE_DETECTED),
+ ERRSYM(SEC_E_SMARTCARD_CERT_REVOKED),
+ ERRSYM(SEC_E_ISSUING_CA_UNTRUSTED),
+ ERRSYM(SEC_E_REVOCATION_OFFLINE_C),
+ ERRSYM(SEC_E_PKINIT_CLIENT_FAILURE),
+ ERRSYM(SEC_E_SMARTCARD_CERT_EXPIRED),
+ ERRSYM(SEC_E_NO_S4U_PROT_SUPPORT),
+ ERRSYM(SEC_E_CROSSREALM_DELEGATION_FAILURE),
+ ERRSYM(SEC_E_REVOCATION_OFFLINE_KDC),
+ ERRSYM(SEC_E_ISSUING_CA_UNTRUSTED_KDC),
+ ERRSYM(SEC_E_KDC_CERT_EXPIRED),
+ ERRSYM(SEC_E_KDC_CERT_REVOKED),
+ ERRSYM(SEC_E_INVALID_PARAMETER),
+ ERRSYM(SEC_E_DELEGATION_POLICY),
+ ERRSYM(SEC_E_POLICY_NLTM_ONLY),
+ ERRSYM(SEC_E_NO_CONTEXT),
+ ERRSYM(SEC_E_PKU2U_CERT_FAILURE),
+ ERRSYM(SEC_E_MUTUAL_AUTH_FAILED),
+ ERRSYM(SEC_E_NO_SPM),
+ ERRSYM(SEC_E_NOT_SUPPORTED),
+ {0,0}
+};
+
+void sspi_errmsg(int err, char *buf, size_t size)
+{
+ buf[size - 1] = 0;
+ size_t len;
+
+ for (size_t i= 0; error_symbols[i].sym; i++)
+ {
+ if (error_symbols[i].error == err)
+ {
+ size_t len= strlen(error_symbols[i].sym);
+ if (len + 2 < size)
+ {
+ memcpy(buf, error_symbols[i].sym, len);
+ buf[len]= ' ';
+ buf += len + 1;
+ size-= len + 1;
+ }
+ break;
+ }
+ }
+
+ len = FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
+ err, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ buf, size, NULL);
+
+ if(len > 0)
+ {
+ /* Trim trailing \n\r*/
+ char *p;
+ for(p= buf + len;p > buf && (*p == '\n' || *p=='\r' || *p == 0);p--)
+ *p= 0;
+ }
+}
diff --git a/plugin/auth_gssapi/sspi_server.cc b/plugin/auth_gssapi/sspi_server.cc
new file mode 100644
index 00000000000..fe90a195d88
--- /dev/null
+++ b/plugin/auth_gssapi/sspi_server.cc
@@ -0,0 +1,317 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "sspi.h"
+#include "common.h"
+#include "server_plugin.h"
+#include <mysql/plugin_auth.h>
+#include <my_sys.h>
+#include <mysqld_error.h>
+#include <log.h>
+
+
+/* This sends the error to the client */
+static void log_error(SECURITY_STATUS err, const char *msg)
+{
+ if (err)
+ {
+ char buf[1024];
+ sspi_errmsg(err, buf, sizeof(buf));
+ my_printf_error(ER_UNKNOWN_ERROR, "SSPI server error 0x%x - %s - %s", 0, err, msg, buf);
+ }
+ else
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "SSPI server error %s", 0, msg);
+ }
+
+}
+
+static char INVALID_KERBEROS_PRINCIPAL[] = "localhost";
+
+static char *get_default_principal_name()
+{
+ static char default_principal[PRINCIPAL_NAME_MAX +1];
+ ULONG size= sizeof(default_principal);
+
+ if (GetUserNameEx(NameUserPrincipal,default_principal,&size))
+ return default_principal;
+
+ size= sizeof(default_principal);
+ if (GetUserNameEx(NameServicePrincipal,default_principal,&size))
+ return default_principal;
+
+ char domain[PRINCIPAL_NAME_MAX+1];
+ char host[PRINCIPAL_NAME_MAX+1];
+ size= sizeof(domain);
+ if (GetComputerNameEx(ComputerNameDnsDomain,domain,&size) && size > 0)
+ {
+ size= sizeof(host);
+ if (GetComputerNameEx(ComputerNameDnsHostname,host,&size))
+ {
+ _snprintf(default_principal,sizeof(default_principal),"%s$@%s",host, domain);
+ return default_principal;
+ }
+ }
+ /* Unable to retrieve useful name, return something */
+ return INVALID_KERBEROS_PRINCIPAL;
+}
+
+
+/* Extract client name from SSPI context */
+static int get_client_name_from_context(CtxtHandle *ctxt,
+ char *name,
+ size_t name_len,
+ int use_full_name)
+{
+ SecPkgContext_NativeNames native_names;
+ SECURITY_STATUS sspi_ret;
+ char *p;
+
+ sspi_ret= QueryContextAttributes(ctxt, SECPKG_ATTR_NATIVE_NAMES, &native_names);
+ if (sspi_ret == SEC_E_OK)
+ {
+ /* Extract user from Kerberos principal name user@realm */
+ if(!use_full_name)
+ {
+ p = strrchr(native_names.sClientName,'@');
+ if(p)
+ *p = 0;
+ }
+ strncpy(name, native_names.sClientName, name_len);
+
+ if (native_names.sClientName)
+ FreeContextBuffer(native_names.sClientName);
+ if (native_names.sServerName)
+ FreeContextBuffer(native_names.sServerName);
+
+ return CR_OK;
+ }
+
+ sspi_ret= ImpersonateSecurityContext(ctxt);
+ if (sspi_ret == SEC_E_OK)
+ {
+ ULONG len= name_len;
+ if (!GetUserNameEx(NameSamCompatible, name, &len))
+ {
+ log_error(GetLastError(), "GetUserNameEx");
+ RevertSecurityContext(ctxt);
+ return CR_ERROR;
+ }
+ RevertSecurityContext(ctxt);
+
+ /* Extract user from Windows name realm\user */
+ if (!use_full_name)
+ {
+ p = strrchr(name, '\\');
+ if (p)
+ {
+ p++;
+ memmove(name, p, name + len + 1 - p);
+ }
+ }
+ return CR_OK;
+ }
+
+ log_error(sspi_ret, "ImpersonateSecurityContext");
+ return CR_ERROR;
+}
+
+
+int auth_server(MYSQL_PLUGIN_VIO *vio, const char *user, size_t user_len, int compare_full_name)
+{
+ int ret;
+ SECURITY_STATUS sspi_ret;
+ ULONG attribs = 0;
+ TimeStamp lifetime;
+ CredHandle cred;
+ CtxtHandle ctxt;
+
+ SecBufferDesc inbuf_desc;
+ SecBuffer inbuf;
+ SecBufferDesc outbuf_desc;
+ SecBuffer outbuf;
+ void* out= NULL;
+ char client_name[MYSQL_USERNAME_LENGTH + 1];
+
+ ret= CR_ERROR;
+ SecInvalidateHandle(&cred);
+ SecInvalidateHandle(&ctxt);
+
+ out= malloc(SSPI_MAX_TOKEN_SIZE);
+ if (!out)
+ {
+ log_error(SEC_E_OK, "memory allocation failed");
+ goto cleanup;
+ }
+ sspi_ret= AcquireCredentialsHandle(
+ srv_principal_name,
+ srv_mech_name,
+ SECPKG_CRED_INBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred,
+ &lifetime);
+
+ if (SEC_ERROR(sspi_ret))
+ {
+ log_error(sspi_ret, "AcquireCredentialsHandle failed");
+ goto cleanup;
+ }
+
+ inbuf.cbBuffer= 0;
+ inbuf.BufferType= SECBUFFER_TOKEN;
+ inbuf.pvBuffer= NULL;
+ inbuf_desc.ulVersion= SECBUFFER_VERSION;
+ inbuf_desc.cBuffers= 1;
+ inbuf_desc.pBuffers= &inbuf;
+
+ outbuf.BufferType= SECBUFFER_TOKEN;
+ outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
+ outbuf.pvBuffer= out;
+
+ outbuf_desc.ulVersion= SECBUFFER_VERSION;
+ outbuf_desc.cBuffers= 1;
+ outbuf_desc.pBuffers= &outbuf;
+
+ do
+ {
+ /* Read SSPI blob from client. */
+ int len= vio->read_packet(vio, (unsigned char **)&inbuf.pvBuffer);
+ if (len < 0)
+ {
+ log_error(SEC_E_OK, "communication error(read)");
+ goto cleanup;
+ }
+ inbuf.cbBuffer= len;
+ outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
+ sspi_ret= AcceptSecurityContext(
+ &cred,
+ SecIsValidHandle(&ctxt) ? &ctxt : NULL,
+ &inbuf_desc,
+ attribs,
+ SECURITY_NATIVE_DREP,
+ &ctxt,
+ &outbuf_desc,
+ &attribs,
+ &lifetime);
+
+ if (SEC_ERROR(sspi_ret))
+ {
+ log_error(sspi_ret, "AcceptSecurityContext");
+ goto cleanup;
+ }
+ if (sspi_ret != SEC_E_OK && sspi_ret != SEC_I_CONTINUE_NEEDED)
+ {
+ log_error(sspi_ret, "AcceptSecurityContext unexpected return value");
+ goto cleanup;
+ }
+ if (outbuf.cbBuffer)
+ {
+ /* Send generated blob to client. */
+ if (vio->write_packet(vio, (unsigned char *)outbuf.pvBuffer, outbuf.cbBuffer))
+ {
+ log_error(SEC_E_OK, "communicaton error(write)");
+ goto cleanup;
+ }
+ }
+ } while (sspi_ret == SEC_I_CONTINUE_NEEDED);
+
+ /* Authentication done, now extract and compare user name. */
+ ret= get_client_name_from_context(&ctxt, client_name, MYSQL_USERNAME_LENGTH, compare_full_name);
+ if (ret != CR_OK)
+ goto cleanup;
+
+ /* Always compare case-insensitive on Windows. */
+ ret= _stricmp(client_name, user) == 0 ? CR_OK : CR_ERROR;
+ if (ret != CR_OK)
+ {
+ my_printf_error(ER_ACCESS_DENIED_ERROR,
+ "GSSAPI name mismatch, requested '%s', actual name '%s'",
+ MYF(0), user, client_name);
+ }
+
+cleanup:
+ if (SecIsValidHandle(&ctxt))
+ DeleteSecurityContext(&ctxt);
+
+ if (SecIsValidHandle(&cred))
+ FreeCredentialsHandle(&cred);
+
+ free(out);
+ return ret;
+}
+
+int plugin_init()
+{
+ CredHandle cred;
+ SECURITY_STATUS ret;
+
+ /*
+ Use negotiate by default, which accepts raw kerberos
+ and also NTLM.
+ */
+ if (srv_mech == PLUGIN_MECH_DEFAULT)
+ srv_mech= PLUGIN_MECH_SPNEGO;
+
+ if(srv_mech == PLUGIN_MECH_KERBEROS)
+ srv_mech_name= "Kerberos";
+ else if(srv_mech == PLUGIN_MECH_SPNEGO )
+ srv_mech_name= "Negotiate";
+
+ if(!srv_principal_name[0])
+ {
+ srv_principal_name= get_default_principal_name();
+ }
+ my_printf_error(ER_UNKNOWN_ERROR, "SSPI: using principal name '%s', mech '%s'",
+ ME_ERROR_LOG | ME_NOTE, srv_principal_name, srv_mech_name);
+
+ ret = AcquireCredentialsHandle(
+ srv_principal_name,
+ srv_mech_name,
+ SECPKG_CRED_INBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred,
+ NULL);
+ if (SEC_ERROR(ret))
+ {
+ log_error(ret, "AcquireCredentialsHandle");
+ return -1;
+ }
+ FreeCredentialsHandle(&cred);
+ return 0;
+}
+
+int plugin_deinit()
+{
+ return 0;
+}
diff --git a/plugin/auth_pam/CMakeLists.txt b/plugin/auth_pam/CMakeLists.txt
index 51317527c77..606fef002e7 100644
--- a/plugin/auth_pam/CMakeLists.txt
+++ b/plugin/auth_pam/CMakeLists.txt
@@ -8,6 +8,7 @@ IF(HAVE_PAM_APPL_H)
IF(HAVE_STRNDUP)
ADD_DEFINITIONS(-DHAVE_STRNDUP)
ENDIF(HAVE_STRNDUP)
+ FIND_LIBRARY(PAM_LIBRARY pam)
MYSQL_ADD_PLUGIN(auth_pam auth_pam.c LINK_LIBRARIES pam MODULE_ONLY)
ENDIF(HAVE_PAM_APPL_H)
diff --git a/plugin/auth_pam/auth_pam.c b/plugin/auth_pam/auth_pam.c
index 3b3aa2c1d25..fae73aea690 100644
--- a/plugin/auth_pam/auth_pam.c
+++ b/plugin/auth_pam/auth_pam.c
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2011, 2012, Monty Program Ab
+ Copyright (c) 2011, 2019, 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
@@ -17,6 +17,7 @@
#define _GNU_SOURCE 1 /* for strndup */
#include <mysql/plugin_auth.h>
+#include <stdio.h>
#include <string.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
@@ -44,6 +45,15 @@ char *strndup(const char *from, size_t length)
}
#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)
{
@@ -91,14 +101,20 @@ static int conv(int n, const struct pam_message **msg,
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: conv: recv(%.*s)\n", pkt_len, pkt));
/* allocate and copy the reply to the response array */
- (*resp)[i].resp = strndup((char*)pkt, pkt_len);
+ if (!((*resp)[i].resp= strndup((char*) pkt, pkt_len)))
+ return PAM_CONV_ERR;
param->ptr = param->buf + 1;
}
}
@@ -117,7 +133,7 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
{
pam_handle_t *pamh = NULL;
int status;
- const char *new_username;
+ 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*) &param };
@@ -125,7 +141,7 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
/*
get the service name, as specified in
- CREATE USER ... IDENTIFIED WITH pam_auth AS "service"
+ CREATE USER ... IDENTIFIED WITH pam AS "service"
*/
const char *service = info->auth_string && info->auth_string[0]
? info->auth_string : "mysql";
@@ -133,17 +149,27 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
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 && strcmp(new_username, info->user_name))
+ if (new_username &&
+ (winbind_hack ? strcasecmp : strcmp)(new_username, info->user_name))
strncpy(info->authenticated_as, new_username,
- sizeof(info->authenticated_as));
+ 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;
}
@@ -162,8 +188,22 @@ static MYSQL_SYSVAR_BOOL(use_cleartext_plugin, use_cleartext_plugin,
"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
};
@@ -189,6 +229,6 @@ maria_declare_plugin(pam)
NULL,
vars,
"1.0",
- MariaDB_PLUGIN_MATURITY_BETA
+ MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;
diff --git a/plugin/auth_pam/mapper/pam_user_map.c b/plugin/auth_pam/mapper/pam_user_map.c
index e73ab6de544..e1d11acabb9 100644
--- a/plugin/auth_pam/mapper/pam_user_map.c
+++ b/plugin/auth_pam/mapper/pam_user_map.c
@@ -6,36 +6,151 @@
gcc pam_user_map.c -shared -lpam -fPIC -o pam_user_map.so
Install as appropriate (for example, in /lib/security/).
- Add to your /etc/pam.d/mysql (preferrably, at the end) this line:
+ Add to your /etc/pam.d/mysql (preferably, at the end) this line:
=========================================================
auth required pam_user_map.so
=========================================================
And create /etc/security/user_map.conf with the desired mapping
in the format: orig_user_name: mapped_user_name
+ @user's_group_name: mapped_user_name
=========================================================
-#comments and emty lines are ignored
+#comments and empty lines are ignored
john: jack
bob: admin
top: accounting
+@group_ro: readonly
=========================================================
+If something doesn't work as expected you can get verbose
+comments with the 'debug' option like this
+=========================================================
+auth required pam_user_map.so debug
+=========================================================
+These comments are written to the syslog as 'authpriv.debug'
+and usually end up in /var/log/secure file.
*/
+#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
#include <syslog.h>
+#include <grp.h>
+#include <pwd.h>
+
+#include <security/pam_ext.h>
#include <security/pam_modules.h>
#define FILENAME "/etc/security/user_map.conf"
#define skip(what) while (*s && (what)) s++
+#define GROUP_BUFFER_SIZE 100
+
+
+static int populate_user_groups(const char *user, gid_t **groups)
+{
+ gid_t user_group_id;
+ gid_t *loc_groups= *groups;
+ int ng;
+
+ {
+ struct passwd *pw= getpwnam(user);
+ if (!pw)
+ return 0;
+ user_group_id= pw->pw_gid;
+ }
+
+ ng= GROUP_BUFFER_SIZE;
+ if (getgrouplist(user, user_group_id, loc_groups, &ng) < 0)
+ {
+ /* The rare case when the user is present in more than */
+ /* GROUP_BUFFER_SIZE groups. */
+ loc_groups= (gid_t *) malloc(ng * sizeof (gid_t));
+ if (!loc_groups)
+ return 0;
+
+ (void) getgrouplist(user, user_group_id, loc_groups, &ng);
+ *groups= loc_groups;
+ }
+
+ return ng;
+}
+
+
+static int user_in_group(const gid_t *user_groups, int ng,const char *group)
+{
+ gid_t group_id;
+ const gid_t *groups_end = user_groups + ng;
+
+ {
+ struct group *g= getgrnam(group);
+ if (!g)
+ return 0;
+ group_id= g->gr_gid;
+ }
+
+ for (; user_groups < groups_end; user_groups++)
+ {
+ if (*user_groups == group_id)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void print_groups(pam_handle_t *pamh, const gid_t *user_groups, int ng)
+{
+ char buf[256];
+ char *c_buf= buf, *buf_end= buf+sizeof(buf)-2;
+ struct group *gr;
+ int cg;
+
+ for (cg=0; cg < ng; cg++)
+ {
+ char *c;
+ if (c_buf == buf_end)
+ break;
+ *(c_buf++)= ',';
+ if (!(gr= getgrgid(user_groups[cg])) ||
+ !(c= gr->gr_name))
+ continue;
+ while (*c)
+ {
+ if (c_buf == buf_end)
+ break;
+ *(c_buf++)= *(c++);
+ }
+ }
+ c_buf[0]= c_buf[1]= 0;
+ pam_syslog(pamh, LOG_DEBUG, "User belongs to %d %s [%s].\n",
+ ng, (ng == 1) ? "group" : "groups", buf+1);
+}
+
+
+static const char debug_keyword[]= "debug";
+#define SYSLOG_DEBUG if (mode_debug) pam_syslog
+
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
int argc, const char *argv[])
{
+ int mode_debug= 0;
int pam_err, line= 0;
const char *username;
char buf[256];
FILE *f;
+ gid_t group_buffer[GROUP_BUFFER_SIZE];
+ gid_t *groups= group_buffer;
+ int n_groups= -1;
+
+ for (; argc > 0; argc--)
+ {
+ if (strcasecmp(argv[argc-1], debug_keyword) == 0)
+ mode_debug= 1;
+ }
+
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "Opening file '%s'.\n", FILENAME);
f= fopen(FILENAME, "r");
if (f == NULL)
@@ -46,44 +161,87 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
pam_err = pam_get_item(pamh, PAM_USER, (const void**)&username);
if (pam_err != PAM_SUCCESS)
+ {
+ pam_syslog(pamh, LOG_ERR, "Cannot get username.\n");
goto ret;
+ }
+
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "Incoming username '%s'.\n", username);
while (fgets(buf, sizeof(buf), f) != NULL)
{
char *s= buf, *from, *to, *end_from, *end_to;
+ int check_group;
+ int cmp_result;
+
line++;
skip(isspace(*s));
if (*s == '#' || *s == 0) continue;
+ if ((check_group= *s == '@'))
+ {
+ if (n_groups < 0)
+ {
+ n_groups= populate_user_groups(username, &groups);
+ if (mode_debug)
+ print_groups(pamh, groups, n_groups);
+ }
+ s++;
+ }
from= s;
- skip(isalnum(*s) || (*s == '_'));
+ skip(isalnum(*s) || (*s == '_') || (*s == '.') || (*s == '-') ||
+ (*s == '$') || (*s == '\\') || (*s == '/'));
end_from= s;
skip(isspace(*s));
if (end_from == from || *s++ != ':') goto syntax_error;
skip(isspace(*s));
to= s;
- skip(isalnum(*s) || (*s == '_'));
+ skip(isalnum(*s) || (*s == '_') || (*s == '.') || (*s == '-') ||
+ (*s == '$'));
end_to= s;
if (end_to == to) goto syntax_error;
*end_from= *end_to= 0;
- if (strcmp(username, from) == 0)
+
+ if (check_group)
+ {
+ cmp_result= user_in_group(groups, n_groups, from);
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "Check if user is in group '%s': %s\n",
+ from, cmp_result ? "YES":"NO");
+ }
+ else
+ {
+ cmp_result= (strcmp(username, from) == 0);
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "Check if username '%s': %s\n",
+ from, cmp_result ? "YES":"NO");
+ }
+ if (cmp_result)
{
pam_err= pam_set_item(pamh, PAM_USER, to);
+ SYSLOG_DEBUG(pamh, LOG_DEBUG,
+ (pam_err == PAM_SUCCESS) ? "User mapped as '%s'\n" :
+ "Couldn't map as '%s'\n", to);
goto ret;
}
}
- pam_err= PAM_SUCCESS;
+
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "User not found in the list.\n");
+ pam_err= PAM_AUTH_ERR;
goto ret;
syntax_error:
pam_syslog(pamh, LOG_ERR, "Syntax error at %s:%d", FILENAME, line);
pam_err= PAM_SYSTEM_ERR;
ret:
+ if (groups != group_buffer)
+ free(groups);
+
fclose(f);
+
return pam_err;
}
+
int pam_sm_setcred(pam_handle_t *pamh, int flags,
int argc, const char *argv[])
{
diff --git a/plugin/auth_pipe/CMakeLists.txt b/plugin/auth_pipe/CMakeLists.txt
new file mode 100644
index 00000000000..bbc44d0f5e2
--- /dev/null
+++ b/plugin/auth_pipe/CMakeLists.txt
@@ -0,0 +1,3 @@
+IF(WIN32)
+ MYSQL_ADD_PLUGIN(auth_named_pipe auth_pipe.c)
+ENDIF()
diff --git a/plugin/auth_pipe/auth_pipe.c b/plugin/auth_pipe/auth_pipe.c
new file mode 100644
index 00000000000..ed41b94cfca
--- /dev/null
+++ b/plugin/auth_pipe/auth_pipe.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 2015 Vladislav Vaintroub, Georg Richter 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file
+
+ auth_pipe authentication plugin.
+
+ Authentication is successful if the connection is done via a named pipe
+ pipe peer name matches mysql user name
+*/
+
+#include <mysql/plugin_auth.h>
+#include <string.h>
+#include <lmcons.h>
+
+
+/**
+ This authentication callback obtains user name using named pipe impersonation
+*/
+static int pipe_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned char *pkt;
+ MYSQL_PLUGIN_VIO_INFO vio_info;
+ char username[UNLEN + 1];
+ size_t username_length;
+ int ret;
+
+ /* 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= PASSWORD_USED_NO_MENTION;
+ vio->info(vio, &vio_info);
+ if (vio_info.protocol != MYSQL_VIO_PIPE)
+ return CR_ERROR;
+
+ /* Impersonate the named pipe peer, and retrieve the user name */
+ if (!ImpersonateNamedPipeClient(vio_info.handle))
+ return CR_ERROR;
+
+ username_length= sizeof(username) - 1;
+ ret= CR_ERROR;
+ if (GetUserName(username, &username_length))
+ {
+ /* Always compare names case-insensitive on Windows.*/
+ if (_stricmp(username, info->user_name) == 0)
+ ret= CR_OK;
+ }
+ RevertToSelf();
+
+ return ret;
+}
+
+static struct st_mysql_auth pipe_auth_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ 0,
+ pipe_auth
+};
+
+maria_declare_plugin(auth_named_pipe)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &pipe_auth_handler,
+ "named_pipe",
+ "Vladislav Vaintroub, Georg Richter",
+ "Windows named pipe based authentication",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/auth_socket/CMakeLists.txt b/plugin/auth_socket/CMakeLists.txt
index f95eb8a31da..eafa82bda99 100644
--- a/plugin/auth_socket/CMakeLists.txt
+++ b/plugin/auth_socket/CMakeLists.txt
@@ -65,6 +65,5 @@ ENDIF()
ENDIF()
IF(ok)
- MYSQL_ADD_PLUGIN(auth_socket auth_socket.c MODULE_ONLY)
+ MYSQL_ADD_PLUGIN(auth_socket auth_socket.c)
ENDIF()
-
diff --git a/plugin/auth_socket/auth_socket.c b/plugin/auth_socket/auth_socket.c
index 134f72c9a7d..c31f78a4500 100644
--- a/plugin/auth_socket/auth_socket.c
+++ b/plugin/auth_socket/auth_socket.c
@@ -105,24 +105,7 @@ static struct st_mysql_auth socket_auth_handler=
socket_auth
};
-mysql_declare_plugin(socket_auth)
-{
- MYSQL_AUTHENTICATION_PLUGIN,
- &socket_auth_handler,
- "unix_socket",
- "Sergei Golubchik",
- "Unix Socket based authentication",
- PLUGIN_LICENSE_GPL,
- NULL,
- NULL,
- 0x0100,
- NULL,
- NULL,
- NULL,
- 0,
-}
-mysql_declare_plugin_end;
-maria_declare_plugin(socket_auth)
+maria_declare_plugin(auth_socket)
{
MYSQL_AUTHENTICATION_PLUGIN,
&socket_auth_handler,
@@ -136,7 +119,7 @@ maria_declare_plugin(socket_auth)
NULL,
NULL,
"1.0",
- MariaDB_PLUGIN_MATURITY_BETA
+ MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;
diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt
new file mode 100644
index 00000000000..49f6b54a24c
--- /dev/null
+++ b/plugin/aws_key_management/CMakeLists.txt
@@ -0,0 +1,185 @@
+# 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)
+ IF(VERBOSE OR "${PLUGIN_AWS_KEY_MANAGEMENT}" MATCHES "^(STATIC|DYNAMIC)$")
+ MESSAGE(STATUS "Can't build aws_key_management - ${msg}")
+ ENDIF()
+ IF(TARGET aws_key_management)
+ MESSAGE(FATAL_ERROR "Error configuring aws_key_management - aborting")
+ ENDIF()
+ 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()
+
+MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc DISABLED
+ COMPONENT aws-key-management)
+
+IF(NOT TARGET aws_key_management)
+ RETURN()
+ELSE()
+ SET(NON_DISTRIBUTABLE_WARNING "Apache 2.0" PARENT_SCOPE)
+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()
+
+
+
+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)
+ 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)
+ IF(NOT UUID_LIBRARIES)
+ SKIP_AWS_PLUGIN("AWS C++ SDK requires uuid development package")
+ ENDIF()
+ FIND_PACKAGE(OpenSSL)
+ 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
+ # We increase the version for macs however, so the newest mac could built it.
+ IF(APPLE)
+ SET(GIT_TAG "1.0.100")
+ ELSEIF(_OPENSSL_VERSION VERSION_EQUAL "1.1")
+ SET(GIT_TAG "1.0.114")
+ ELSE()
+ SET(GIT_TAG "1.0.8")
+ 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
+ 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()
+
+TARGET_LINK_LIBRARIES(aws_key_management ${AWS_SDK_LIBS} ${AWS_CPP_SDK_DEPENDENCIES})
diff --git a/plugin/aws_key_management/aws_key_management_plugin.cc b/plugin/aws_key_management/aws_key_management_plugin.cc
new file mode 100644
index 00000000000..e396be8cbdf
--- /dev/null
+++ b/plugin/aws_key_management/aws_key_management_plugin.cc
@@ -0,0 +1,750 @@
+/*
+ Copyright (c) 2016 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+#include <my_global.h>
+#include <typelib.h>
+#include <mysql/plugin_encryption.h>
+#include <my_crypt.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <mysqld_error.h>
+#include <my_sys.h>
+#include <map>
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <iterator>
+#include <sstream>
+#include <fstream>
+
+#ifndef _WIN32
+#include <dirent.h>
+#endif
+
+#include <aws/core/Aws.h>
+#include <aws/core/client/AWSError.h>
+#include <aws/core/utils/logging/AWSLogging.h>
+#include <aws/core/utils/logging/ConsoleLogSystem.h>
+#include <aws/kms/KMSClient.h>
+#include <aws/kms/model/DecryptRequest.h>
+#include <aws/kms/model/DecryptResult.h>
+#include <aws/kms/model/GenerateDataKeyWithoutPlaintextRequest.h>
+#include <aws/kms/model/GenerateDataKeyWithoutPlaintextResult.h>
+#include <aws/core/utils/Outcome.h>
+
+using namespace std;
+using namespace Aws::KMS;
+using namespace Aws::KMS::Model;
+using namespace Aws::Utils::Logging;
+
+
+/* Plaintext key info struct */
+struct KEY_INFO
+{
+ unsigned int key_id;
+ unsigned int key_version;
+ unsigned int length;
+ unsigned char data[MY_AES_MAX_KEY_LENGTH];
+ bool load_failed; /* if true, do not attempt to reload?*/
+public:
+ KEY_INFO() : key_id(0), key_version(0), length(0), load_failed(false){};
+};
+#define KEY_ID_AND_VERSION(key_id,version) ((longlong)key_id << 32 | version)
+
+/* Cache for the latest version, per key id */
+static std::map<uint, uint> latest_version_cache;
+
+/* Cache for plaintext keys */
+static std::map<ulonglong, KEY_INFO> key_info_cache;
+
+static const char *key_spec_names[]={ "AES_128", "AES_256", 0 };
+
+/* Plugin variables */
+static char* master_key_id;
+static char* region;
+static unsigned long key_spec;
+static unsigned long log_level;
+static int rotate_key;
+static int request_timeout;
+
+#ifndef DBUG_OFF
+#define WITH_AWS_MOCK 1
+#else
+#define WITH_AWS_MOCK 0
+#endif
+
+#if WITH_AWS_MOCK
+static char mock;
+#endif
+
+
+/* AWS functionality*/
+static int read_and_decrypt_key(const char *path, KEY_INFO *info);
+static int generate_and_save_datakey(uint key_id, uint version);
+
+static int extract_id_and_version(const char *name, uint *id, uint *ver);
+static unsigned int get_latest_key_version(unsigned int key_id);
+static unsigned int get_latest_key_version_nolock(unsigned int key_id);
+static int load_key(KEY_INFO *info);
+static std::mutex mtx;
+
+
+static Aws::KMS::KMSClient *client;
+
+#if WITH_AWS_MOCK
+/*
+ Mock routines to test plugin without actual AWS KMS interaction
+ we only need to mock 2 functions - generating encrypted key, and decrypt
+
+ This mock functions do no-op encryption, i.e encrypt and decrypt of
+ a buffer return the buffer itself.
+*/
+
+/*
+ Generate random "encrypted" key. We do not encrypt anything in mock mode.
+*/
+static int mock_generate_encrypted_key(Aws::Utils::ByteBuffer *result)
+{
+ size_t len = key_spec == 0?16 : 32;
+ *result = Aws::Utils::ByteBuffer(len);
+ my_random_bytes(result->GetUnderlyingData(), (int)len);
+ return 0;
+}
+
+
+static int mock_decrypt(Aws::Utils::ByteBuffer input, Aws::Utils::ByteBuffer* output, Aws::String *errmsg)
+{
+ /* We do not encrypt or decrypt in mock mode.*/
+ *output = input;
+ return 0;
+}
+#endif
+
+/* Redirect AWS trace to error log */
+class MySQLLogSystem : public Aws::Utils::Logging::FormattedLogSystem
+{
+public:
+
+ using Base = FormattedLogSystem;
+ MySQLLogSystem(LogLevel logLevel) :
+ Base(logLevel)
+ {
+ }
+ virtual LogLevel GetLogLevel(void) const override
+ {
+ return (LogLevel)log_level;
+ }
+ virtual ~MySQLLogSystem()
+ {
+ }
+
+protected:
+ virtual void ProcessFormattedStatement(Aws::String&& statement) override
+ {
+#ifdef _WIN32
+ /*
+ On Windows, we can't use C runtime functions to write to stdout,
+ because we compile with static C runtime, so plugin has a stdout
+ different from server. Thus we're using WriteFile().
+ */
+ DWORD nSize= (DWORD)statement.size();
+ DWORD nWritten;
+ const char *s= statement.c_str();
+ HANDLE h= GetStdHandle(STD_OUTPUT_HANDLE);
+
+ WriteFile(h, s, nSize, &nWritten, NULL);
+#else
+ printf("%s", statement.c_str());
+#endif
+ }
+};
+
+/* Get list of files in current directory */
+static vector<string> traverse_current_directory()
+{
+ vector<string> v;
+#ifdef _WIN32
+ WIN32_FIND_DATA find_data;
+ HANDLE h= FindFirstFile("*.*", &find_data);
+ if (h == INVALID_HANDLE_VALUE)
+ return v;
+ do
+ {
+ v.push_back(find_data.cFileName);
+ }
+ while (FindNextFile(h, &find_data));
+ FindClose(h);
+#else
+ DIR *dir = opendir(".");
+ if (!dir)
+ return v;
+ struct dirent *e;
+ while ((e= readdir(dir)))
+ v.push_back(e->d_name);
+ closedir(dir);
+#endif
+ return v;
+}
+
+Aws::SDKOptions sdkOptions;
+
+static int aws_init()
+{
+
+#ifdef HAVE_YASSL
+ sdkOptions.cryptoOptions.initAndCleanupOpenSSL = true;
+#else
+ /* Server initialized OpenSSL already, thus AWS must skip it */
+ sdkOptions.cryptoOptions.initAndCleanupOpenSSL = false;
+#endif
+
+ Aws::InitAPI(sdkOptions);
+ InitializeAWSLogging(Aws::MakeShared<MySQLLogSystem>("aws_key_management_plugin", (Aws::Utils::Logging::LogLevel) log_level));
+
+ Aws::Client::ClientConfiguration clientConfiguration;
+ if (region && region[0])
+ {
+ clientConfiguration.region = region;
+ }
+ if (request_timeout)
+ {
+ clientConfiguration.requestTimeoutMs= request_timeout;
+ clientConfiguration.connectTimeoutMs= request_timeout;
+ }
+ client = new KMSClient(clientConfiguration);
+ if (!client)
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "Can not initialize KMS client", ME_ERROR_LOG | ME_WARNING);
+ return -1;
+ }
+ return 0;
+}
+
+static int init()
+{
+#if WITH_AWS_MOCK
+ if(mock)
+ return 0;
+#endif
+ return aws_init();
+}
+
+/*
+ Plugin initialization.
+
+ Create KMS client and scan datadir to find out which keys and versions
+ are present.
+*/
+static int plugin_init(void *p)
+{
+ if (init())
+ return -1;
+
+ vector<string> files= traverse_current_directory();
+ for (size_t i=0; i < files.size(); i++)
+ {
+
+ KEY_INFO info;
+ if (extract_id_and_version(files[i].c_str(), &info.key_id, &info.key_version) == 0)
+ {
+ key_info_cache[KEY_ID_AND_VERSION(info.key_id, info.key_version)]= info;
+ latest_version_cache[info.key_id]= max(info.key_version, latest_version_cache[info.key_id]);
+ }
+ }
+ return 0;
+}
+
+
+static void aws_shutdown()
+{
+ delete client;
+ ShutdownAWSLogging();
+ Aws::ShutdownAPI(sdkOptions);
+}
+
+
+static void shutdown()
+{
+#if WITH_AWS_MOCK
+ if(mock)
+ return;
+#endif
+ aws_shutdown();
+}
+
+
+static int plugin_deinit(void *p)
+{
+ latest_version_cache.clear();
+ key_info_cache.clear();
+ shutdown();
+ return 0;
+}
+
+/* Generate filename to store the ciphered key */
+static void format_keyfile_name(char *buf, size_t size, uint key_id, uint version)
+{
+ snprintf(buf, size, "aws-kms-key.%u.%u", key_id, version);
+}
+
+/* Extract key id and version from file name */
+static int extract_id_and_version(const char *name, uint *id, uint *ver)
+{
+ int len;
+ int n= sscanf(name, "aws-kms-key.%u.%u%n", id, ver, &len);
+ if (n == 2 && *id > 0 && *ver > 0 && len == (int)strlen(name))
+ return 0;
+ return 1;
+}
+
+/*
+ Decrypt key stored in aws-kms-key.<id>.<version>
+ Cache the decrypted key.
+*/
+static int load_key(KEY_INFO *info)
+{
+ int ret;
+ char path[256];
+
+ format_keyfile_name(path, sizeof(path), info->key_id, info->key_version);
+ ret= read_and_decrypt_key(path, info);
+ if (ret)
+ info->load_failed= true;
+
+ latest_version_cache[info->key_id]= max(latest_version_cache[info->key_id], info->key_version);
+ key_info_cache[KEY_ID_AND_VERSION(info->key_id, info->key_version)]= *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,
+ 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,
+ info->key_id, info->key_version);
+ }
+ return ret;
+}
+
+
+/*
+ Get latest version for the key.
+
+ If key is not decrypted yet, this function also decrypt the key
+ and error will be returned if decryption fails.
+
+ The reason for that is that Innodb crashes
+ in case errors are returned by get_key(),
+
+ A new key will be created if it does not exist, provided there is
+ valid master_key_id.
+*/
+static unsigned int get_latest_key_version(unsigned int key_id)
+{
+ unsigned int ret;
+ mtx.lock();
+ ret= get_latest_key_version_nolock(key_id);
+ mtx.unlock();
+ return ret;
+}
+
+static unsigned int get_latest_key_version_nolock(unsigned int key_id)
+{
+ KEY_INFO info;
+ uint ver;
+
+ ver= latest_version_cache[key_id];
+ if (ver > 0)
+ {
+ info= key_info_cache[KEY_ID_AND_VERSION(key_id, ver)];
+ }
+ if (info.load_failed)
+ {
+ /* Decryption failed previously, don't retry */
+ return(ENCRYPTION_KEY_VERSION_INVALID);
+ }
+ else if (ver > 0)
+ {
+ /* Key exists already, return it*/
+ if (info.length > 0)
+ return(ver);
+ }
+ else // (ver == 0)
+ {
+ /* Generate a new key, version 1 */
+ if (generate_and_save_datakey(key_id, 1) != 0)
+ return(ENCRYPTION_KEY_VERSION_INVALID);
+ info.key_id= key_id;
+ info.key_version= 1;
+ info.length= 0;
+ }
+
+ if (load_key(&info))
+ return(ENCRYPTION_KEY_VERSION_INVALID);
+ return(info.key_version);
+}
+
+/* Decrypt Byte buffer with AWS. */
+static int aws_decrypt(Aws::Utils::ByteBuffer input, Aws::Utils::ByteBuffer* output, Aws::String *errmsg)
+{
+ DecryptRequest request;
+ request.SetCiphertextBlob(input);
+ DecryptOutcome outcome = client->Decrypt(request);
+ if (!outcome.IsSuccess())
+ {
+ *errmsg = outcome.GetError().GetMessage();
+ return -1;
+ }
+ *output= outcome.GetResult().GetPlaintext();
+ return 0;
+}
+
+
+static int decrypt(Aws::Utils::ByteBuffer input, Aws::Utils::ByteBuffer* output, Aws::String *errmsg)
+{
+#if WITH_AWS_MOCK
+ if(mock)
+ return mock_decrypt(input,output, errmsg);
+#endif
+ return aws_decrypt(input, output, errmsg);
+}
+
+/*
+ Decrypt a file with KMS
+*/
+static int read_and_decrypt_key(const char *path, KEY_INFO *info)
+{
+
+ /* Read file content into memory */
+ 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);
+ 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);
+ return(-1);
+ }
+ std::vector<char> contents(pos);
+ ifs.seekg(0, ios::beg);
+ ifs.read(&contents[0], pos);
+
+ /* Decrypt data the with AWS */
+
+ Aws::Utils::ByteBuffer input((unsigned char *)contents.data(), pos);
+ Aws::Utils::ByteBuffer plaintext;
+ Aws::String errmsg;
+
+ if (decrypt(input, &plaintext, &errmsg))
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: Decrypt failed for %s : %s", ME_ERROR_LOG, path,
+ errmsg.c_str());
+ return -1;
+ }
+
+ size_t len = plaintext.GetLength();
+
+ if (len > sizeof(info->data))
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: encoding key too large for %s", ME_ERROR_LOG, path);
+ return(ENCRYPTION_KEY_BUFFER_TOO_SMALL);
+ }
+ memcpy(info->data, plaintext.GetUnderlyingData(), len);
+ info->length= len;
+ return(0);
+}
+
+
+int aws_generate_encrypted_key(Aws::Utils::ByteBuffer *result)
+{
+ if (!master_key_id[0])
+ {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Can't generate encryption key, because 'aws_key_management_master_key_id' parameter is not set",
+ MYF(0));
+ return(-1);
+ }
+ GenerateDataKeyWithoutPlaintextRequest request;
+ request.SetKeyId(master_key_id);
+ request.SetKeySpec(DataKeySpecMapper::GetDataKeySpecForName(key_spec_names[key_spec]));
+
+ GenerateDataKeyWithoutPlaintextOutcome outcome;
+ outcome= client->GenerateDataKeyWithoutPlaintext(request);
+ if (!outcome.IsSuccess())
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin : GenerateDataKeyWithoutPlaintext failed : %s - %s", ME_ERROR_LOG,
+ outcome.GetError().GetExceptionName().c_str(),
+ outcome.GetError().GetMessage().c_str());
+ return(-1);
+ }
+ *result = outcome.GetResult().GetCiphertextBlob();
+ return 0;
+}
+
+
+static int generate_encrypted_key(Aws::Utils::ByteBuffer *output)
+{
+#if WITH_AWS_MOCK
+ if(mock)
+ return mock_generate_encrypted_key(output);
+#endif
+ return aws_generate_encrypted_key(output);
+}
+
+/* Generate a new datakey and store it a file */
+static int generate_and_save_datakey(uint keyid, uint version)
+{
+ Aws::Utils::ByteBuffer byteBuffer;
+
+ if (generate_encrypted_key(&byteBuffer))
+ return -1;
+
+ string out;
+ char filename[20];
+ format_keyfile_name(filename, sizeof(filename), keyid, 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);
+ return(-1);
+ }
+ size_t len= 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);
+ 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,
+ keyid, version);
+ return(0);
+}
+
+/* Key rotation for a single key */
+static int rotate_single_key(uint key_id)
+{
+ uint ver;
+ ver= latest_version_cache[key_id];
+
+ if (!ver)
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "key %u does not exist", MYF(ME_JUST_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);
+ return -1;
+ }
+ else
+ {
+ KEY_INFO info;
+ info.key_id= key_id;
+ info.key_version = ver + 1;
+ 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);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Key rotation for all key ids */
+static int rotate_all_keys()
+{
+ int ret= 0;
+ for (map<uint, uint>::iterator it= latest_version_cache.begin(); it != latest_version_cache.end(); it++)
+ {
+ ret= rotate_single_key(it->first);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+static void update_rotate(MYSQL_THD, struct st_mysql_sys_var *, void *, const void *val)
+{
+ 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));
+ return;
+ }
+ mtx.lock();
+ rotate_key= *(int *)val;
+ switch (rotate_key)
+ {
+ case 0:
+ break;
+ case -1:
+ rotate_all_keys();
+ break;
+ default:
+ rotate_single_key(rotate_key);
+ break;
+ }
+ rotate_key= 0;
+ mtx.unlock();
+}
+
+static unsigned int get_key(
+ unsigned int key_id,
+ unsigned int version,
+ unsigned char* dstbuf,
+ unsigned int* buflen)
+{
+ KEY_INFO info;
+
+ mtx.lock();
+ info= key_info_cache[KEY_ID_AND_VERSION(key_id, version)];
+ if (info.length == 0 && !info.load_failed)
+ {
+ info.key_id= key_id;
+ info.key_version= version;
+ load_key(&info);
+ }
+ mtx.unlock();
+ if (info.load_failed)
+ return(ENCRYPTION_KEY_VERSION_INVALID);
+ if (*buflen < info.length)
+ {
+ *buflen= info.length;
+ return(ENCRYPTION_KEY_BUFFER_TOO_SMALL);
+ }
+ *buflen= info.length;
+ memcpy(dstbuf, info.data, info.length);
+ return(0);
+}
+
+
+/* Plugin defs */
+struct st_mariadb_encryption aws_key_management_plugin= {
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ get_latest_key_version,
+ get_key,
+ // use default encrypt/decrypt functions
+ 0, 0, 0, 0, 0
+};
+
+
+static TYPELIB key_spec_typelib =
+{
+ array_elements(key_spec_names) - 1, "",
+ key_spec_names, NULL
+};
+
+const char *log_level_names[] =
+{
+ "Off",
+ "Fatal",
+ "Error",
+ "Warn",
+ "Info",
+ "Debug",
+ "Trace",
+ 0
+};
+
+static TYPELIB log_level_typelib =
+{
+ array_elements(log_level_names) - 1, "",
+ log_level_names, NULL
+};
+
+static MYSQL_SYSVAR_STR(master_key_id, master_key_id,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "Key id for master encryption key. Used to create new datakeys. If not set, no new keys will be created",
+ NULL, NULL, "");
+
+static MYSQL_SYSVAR_ENUM(key_spec, key_spec,
+ PLUGIN_VAR_RQCMDARG,
+ "Encryption algorithm used to create new keys.",
+ NULL, NULL, 0, &key_spec_typelib);
+
+
+static MYSQL_SYSVAR_ENUM(log_level, log_level,
+ PLUGIN_VAR_RQCMDARG,
+ "Logging for AWS API",
+ NULL, NULL, 0, &log_level_typelib);
+
+
+static MYSQL_SYSVAR_INT(rotate_key, rotate_key,
+ PLUGIN_VAR_RQCMDARG,
+ "Set this variable to key id to perform rotation of the key. Specify -1 to rotate all keys",
+ NULL, update_rotate, 0, -1, INT_MAX, 1);
+
+
+static MYSQL_SYSVAR_INT(request_timeout, request_timeout,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Timeout in milliseconds for create HTTPS connection or execute AWS request. Specify 0 to use SDK default.",
+ NULL, NULL, 0, 0, INT_MAX, 1);
+
+static MYSQL_SYSVAR_STR(region, region,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "AWS region. For example us-east-1, or eu-central-1. If no value provided, SDK default is used.",
+ NULL, NULL, "");
+
+#if WITH_AWS_MOCK
+static MYSQL_SYSVAR_BOOL(mock, mock,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Mock AWS KMS calls (for testing).",
+ NULL, NULL, 0);
+#endif
+
+static struct st_mysql_sys_var* settings[]= {
+ MYSQL_SYSVAR(master_key_id),
+ MYSQL_SYSVAR(key_spec),
+ MYSQL_SYSVAR(rotate_key),
+ MYSQL_SYSVAR(log_level),
+ MYSQL_SYSVAR(request_timeout),
+ MYSQL_SYSVAR(region),
+#if WITH_AWS_MOCK
+ MYSQL_SYSVAR(mock),
+#endif
+ NULL
+};
+
+/*
+ Plugin library descriptor
+*/
+maria_declare_plugin(aws_key_management)
+{
+ MariaDB_ENCRYPTION_PLUGIN,
+ &aws_key_management_plugin,
+ "aws_key_management",
+ "MariaDB Corporation",
+ "AWS key management plugin",
+ PLUGIN_LICENSE_GPL,
+ plugin_init,
+ plugin_deinit,
+ 0x0100,
+ NULL,
+ settings,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/cracklib_password_check/CMakeLists.txt b/plugin/cracklib_password_check/CMakeLists.txt
new file mode 100644
index 00000000000..81db865eae0
--- /dev/null
+++ b/plugin/cracklib_password_check/CMakeLists.txt
@@ -0,0 +1,13 @@
+INCLUDE (CheckIncludeFiles)
+INCLUDE (CheckLibraryExists)
+
+CHECK_LIBRARY_EXISTS(crack FascistCheckUser "" HAVE_LIBCRACK)
+
+SET(CMAKE_REQUIRED_DEFINITIONS -Dsize_t=int) # debian hack, debian bug.
+CHECK_INCLUDE_FILES (crack.h HAVE_CRACK_H)
+
+IF (HAVE_ALLOCA_H AND HAVE_CRACK_H AND HAVE_LIBCRACK AND HAVE_MEMCPY)
+ MYSQL_ADD_PLUGIN(cracklib_password_check cracklib_password_check.c
+ LINK_LIBRARIES crack MODULE_ONLY
+ COMPONENT cracklib-password-check)
+ENDIF()
diff --git a/plugin/cracklib_password_check/cracklib_password_check.c b/plugin/cracklib_password_check/cracklib_password_check.c
new file mode 100644
index 00000000000..f8de9907dfd
--- /dev/null
+++ b/plugin/cracklib_password_check/cracklib_password_check.c
@@ -0,0 +1,84 @@
+/* Copyright (c) 2014, Sergei Golubchik and 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
+ 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_config.h>
+#include <mysql/plugin_password_validation.h>
+#include <crack.h>
+#include <string.h>
+#include <alloca.h>
+#include <my_sys.h>
+#include <mysqld_error.h>
+
+static char *dictionary;
+
+static int crackme(MYSQL_LEX_STRING *username, MYSQL_LEX_STRING *password)
+{
+ char *user= alloca(username->length + 1);
+ char *host;
+ const char *res;
+
+ memcpy(user, username->str, username->length);
+ user[username->length]= 0;
+ if ((host= strchr(user, '@')))
+ *host++= 0;
+
+ if ((res= FascistCheckUser(password->str, dictionary, user, host)))
+ {
+ my_printf_error(ER_NOT_VALID_PASSWORD, "cracklib: %s",
+ MYF(ME_JUST_WARNING), res);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static MYSQL_SYSVAR_STR(dictionary, dictionary, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Path to a cracklib dictionary", NULL, NULL, 0);
+
+/* optional user-friendly nicety */
+void set_default_dictionary_path() __attribute__((constructor));
+void set_default_dictionary_path()
+{
+ MYSQL_SYSVAR_NAME(dictionary).def_val = GetDefaultCracklibDict();
+}
+
+static struct st_mysql_sys_var* sysvars[]= {
+ MYSQL_SYSVAR(dictionary),
+ NULL
+};
+
+static struct st_mariadb_password_validation info=
+{
+ MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION,
+ crackme
+};
+
+maria_declare_plugin(cracklib_password_check)
+{
+ MariaDB_PASSWORD_VALIDATION_PLUGIN,
+ &info,
+ "cracklib_password_check",
+ "Sergei Golubchik",
+ "Password validation via CrackLib",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ sysvars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/daemon_example/CMakeLists.txt b/plugin/daemon_example/CMakeLists.txt
index bb3d9a86a7b..57a1135e695 100644
--- a/plugin/daemon_example/CMakeLists.txt
+++ b/plugin/daemon_example/CMakeLists.txt
@@ -13,7 +13,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
-MYSQL_ADD_PLUGIN(daemon_example daemon_example.cc
+MYSQL_ADD_PLUGIN(daemon_example daemon_example.cc RECOMPILE_FOR_EMBEDDED
MODULE_ONLY MODULE_OUTPUT_NAME "libdaemon_example" COMPONENT Test)
-INSTALL(FILES daemon_example.ini DESTINATION ${INSTALL_PLUGINDIR} COMPONENT Test)
+INSTALL(FILES daemon_example.ini DESTINATION ${INSTALL_PLUGINDIR}
+ COMPONENT Test)
diff --git a/plugin/daemon_example/daemon_example.cc b/plugin/daemon_example/daemon_example.cc
index e3fe4730a12..87f48a1fa69 100644
--- a/plugin/daemon_example/daemon_example.cc
+++ b/plugin/daemon_example/daemon_example.cc
@@ -129,7 +129,7 @@ static int daemon_example_plugin_init(void *p __attribute__ ((unused)))
(void *)con) != 0)
{
fprintf(stderr,"Could not create heartbeat thread!\n");
- exit(0);
+ DBUG_RETURN(1);
}
plugin->data= (void *)con;
@@ -195,23 +195,6 @@ struct st_mysql_daemon daemon_example_plugin=
Plugin library descriptor
*/
-mysql_declare_plugin(daemon_example)
-{
- MYSQL_DAEMON_PLUGIN,
- &daemon_example_plugin,
- "daemon_example",
- "Brian Aker",
- "Daemon example, creates a heartbeat beat file in mysql-heartbeat.log",
- PLUGIN_LICENSE_GPL,
- daemon_example_plugin_init, /* Plugin Init */
- daemon_example_plugin_deinit, /* Plugin Deinit */
- 0x0100 /* 1.0 */,
- NULL, /* status variables */
- NULL, /* system variables */
- NULL, /* config options */
- 0, /* flags */
-}
-mysql_declare_plugin_end;
maria_declare_plugin(daemon_example)
{
MYSQL_DAEMON_PLUGIN,
diff --git a/plugin/debug_key_management/CMakeLists.txt b/plugin/debug_key_management/CMakeLists.txt
new file mode 100644
index 00000000000..eeb8a3bf4d2
--- /dev/null
+++ b/plugin/debug_key_management/CMakeLists.txt
@@ -0,0 +1,2 @@
+MYSQL_ADD_PLUGIN(DEBUG_KEY_MANAGEMENT debug_key_management_plugin.cc
+ MODULE_ONLY COMPONENT Test)
diff --git a/plugin/debug_key_management/debug_key_management_plugin.cc b/plugin/debug_key_management/debug_key_management_plugin.cc
new file mode 100644
index 00000000000..74ab3522e20
--- /dev/null
+++ b/plugin/debug_key_management/debug_key_management_plugin.cc
@@ -0,0 +1,100 @@
+/*
+ Copyright (c) 2015 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ Debug key management plugin.
+ It's used to debug the encryption code with a fixed keys that change
+ only on user request.
+
+ It does not support different key ids, the only valid key id is 1.
+
+ THIS IS AN EXAMPLE ONLY! ENCRYPTION KEYS ARE HARD-CODED AND *NOT* SECRET!
+ DO NOT USE THIS PLUGIN IN PRODUCTION! EVER!
+*/
+
+#include <my_global.h>
+#include <mysql/plugin_encryption.h>
+#include <string.h>
+#include <myisampack.h>
+
+#define KEY_SIZE 16
+
+static uint key_version;
+
+static MYSQL_SYSVAR_UINT(version, key_version, PLUGIN_VAR_RQCMDARG,
+ "Latest key version", NULL, NULL, 1, 0, UINT_MAX, 1);
+
+static struct st_mysql_sys_var* sysvars[] = {
+ MYSQL_SYSVAR(version),
+ NULL
+};
+
+static unsigned int get_latest_key_version(unsigned int keyid)
+{
+ if (keyid != 1)
+ return ENCRYPTION_KEY_VERSION_INVALID;
+
+ return key_version;
+}
+
+static unsigned int get_key(unsigned int keyid, unsigned int version,
+ unsigned char* dstbuf, unsigned *buflen)
+{
+ if (keyid != 1)
+ return ENCRYPTION_KEY_VERSION_INVALID;
+
+ if (*buflen < KEY_SIZE)
+ {
+ *buflen= KEY_SIZE;
+ return ENCRYPTION_KEY_BUFFER_TOO_SMALL;
+ }
+ *buflen= KEY_SIZE;
+ if (!dstbuf)
+ return 0;
+
+ memset(dstbuf, 0, KEY_SIZE);
+ mi_int4store(dstbuf, version);
+ return 0;
+}
+
+struct st_mariadb_encryption debug_key_management_plugin= {
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ get_latest_key_version,
+ get_key,
+ // use default encrypt/decrypt functions
+ 0, 0, 0, 0, 0
+};
+
+/*
+ Plugin library descriptor
+*/
+maria_declare_plugin(debug_key_management)
+{
+ MariaDB_ENCRYPTION_PLUGIN,
+ &debug_key_management_plugin,
+ "debug_key_management",
+ "Sergei Golubchik",
+ "Debug key management plugin",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ sysvars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL
+}
+maria_declare_plugin_end;
diff --git a/plugin/disks/CMakeLists.txt b/plugin/disks/CMakeLists.txt
new file mode 100644
index 00000000000..446c64d0fdd
--- /dev/null
+++ b/plugin/disks/CMakeLists.txt
@@ -0,0 +1,5 @@
+IF("${CMAKE_SYSTEM}" MATCHES "Linux")
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql)
+ MYSQL_ADD_PLUGIN(DISKS information_schema_disks.cc MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
+ENDIF()
+
diff --git a/plugin/disks/README.txt b/plugin/disks/README.txt
new file mode 100644
index 00000000000..b49db3c03b5
--- /dev/null
+++ b/plugin/disks/README.txt
@@ -0,0 +1,86 @@
+Information Schema Disks
+------------------------
+This is a proof-of-concept information schema plugin that allows the
+disk space situation to be monitored. When installed, it can be used
+as follows:
+
+ > select * from information_schema.disks;
+ +-----------+-----------------------+-----------+----------+-----------+
+ | Disk | Path | Total | Used | Available |
+ +-----------+-----------------------+-----------+----------+-----------+
+ | /dev/sda3 | / | 47929956 | 30666304 | 14805864 |
+ | /dev/sda1 | /boot/efi | 191551 | 3461 | 188090 |
+ | /dev/sda4 | /home | 174679768 | 80335392 | 85448120 |
+ | /dev/sdb1 | /mnt/hdd | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Music | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Videos | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/hdd | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Pictures | 961301832 | 83764 | 912363644 |
+ | /dev/sda3 | /var/lib/docker/aufs | 47929956 | 30666304 | 14805864 |
+ +-----------+-----------------------+-----------+----------+-----------+
+ 9 rows in set (0.00 sec)
+
+- 'Disk' is the name of the disk itself.
+- 'Path' is the mount point of the disk.
+- 'Total' is the total space in KiB.
+- 'Used' is the used amount of space in KiB, and
+- 'Available' is the amount of space in KiB available to non-root users.
+
+Note that as the amount of space available to root may be more that what
+is available to non-root users, 'available' + 'used' may be less than 'total'.
+
+All paths to which a particular disk has been mounted are reported. The
+rationale is that someone might want to take different action e.g. depending
+on which disk is relevant for a particular path. This leads to the same disk
+being reported multiple times. An alternative to this would be to have two
+tables; disks and mounts.
+
+ > select * from information_schema.disks;
+ +-----------+-----------+----------+-----------+
+ | Disk | Total | Used | Available |
+ +-----------+-----------+----------+-----------+
+ | /dev/sda3 | 47929956 | 30666304 | 14805864 |
+ | /dev/sda1 | 191551 | 3461 | 188090 |
+ | /dev/sda4 | 174679768 | 80335392 | 85448120 |
+ | /dev/sdb1 | 961301832 | 83764 | 912363644 |
+ +-----------+-----------+----------+-----------+
+
+ > select * from information_schema.mounts;
+ +-----------------------+-----------+
+ | Path | Disk |
+ +-----------------------+-----------+
+ | / | /dev/sda3 |
+ | /boot/efi | /dev/sda1 |
+ | /home | /dev/sda4 |
+ | /mnt/hdd | /dev/sdb1 |
+ | /home/wikman/Music | /dev/sdb1 |
+ ...
+
+
+Installation
+------------
+
+- Use "install plugin" or "install soname" command:
+
+ MariaDB [(none)]> install plugin disks soname 'disks.so';
+
+ or
+
+ MariaDB [(none)]> install soname 'disks.so';
+
+Usage
+-----
+The plugin appears as the table 'disks' in 'information_schema'.
+
+ MariaDB [(none)]> select * from information_schema.disks;
+ +-----------+-----------------------+-----------+----------+-----------+
+ | Disk | Path | Total | Used | Available |
+ +-----------+-----------------------+-----------+----------+-----------+
+ | /dev/sda3 | / | 47929956 | 30666308 | 14805860 |
+ | /dev/sda1 | /boot/efi | 191551 | 3461 | 188090 |
+ | /dev/sda4 | /home | 174679768 | 80348148 | 85435364 |
+ | /dev/sdb1 | /mnt/hdd | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Music | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Videos | 961301832 | 83764 | 912363644 |
+ ...
+
diff --git a/plugin/disks/information_schema_disks.cc b/plugin/disks/information_schema_disks.cc
new file mode 100644
index 00000000000..7f7f4f06711
--- /dev/null
+++ b/plugin/disks/information_schema_disks.cc
@@ -0,0 +1,155 @@
+/*
+ Copyright (c) 2017, 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
+ 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 02110-1335 USA */
+
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <mntent.h>
+#include <sql_class.h>
+#include <table.h>
+
+bool schema_table_store_record(THD *thd, TABLE *table);
+
+namespace
+{
+
+struct st_mysql_information_schema disks_table_info = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+ST_FIELD_INFO disks_table_fields[]=
+{
+ { "Disk", PATH_MAX, MYSQL_TYPE_STRING, 0, 0 ,0, 0 },
+ { "Path", PATH_MAX, MYSQL_TYPE_STRING, 0, 0 ,0, 0 },
+ { "Total", 32, MYSQL_TYPE_LONG, 0, 0 ,0 ,0 }, // Total amount available
+ { "Used", 32, MYSQL_TYPE_LONG, 0, 0 ,0 ,0 }, // Amount of space used
+ { "Available", 32, MYSQL_TYPE_LONG, 0, 0 ,0 ,0 }, // Amount available to users other than root.
+ { 0, 0, MYSQL_TYPE_NULL, 0, 0, 0, 0 }
+};
+
+int disks_table_add_row(THD* pThd,
+ TABLE* pTable,
+ const char* zDisk,
+ const char* zPath,
+ const struct statvfs& info)
+{
+ // From: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/statvfs.h.html
+ //
+ // f_frsize Fundamental file system block size.
+ // f_blocks Total number of blocks on file system in units of f_frsize.
+ // f_bfree Total number of free blocks.
+ // f_bavail Number of free blocks available to non-privileged process.
+
+ size_t total = (info.f_frsize * info.f_blocks) / 1024;
+ size_t used = (info.f_frsize * (info.f_blocks - info.f_bfree)) / 1024;
+ size_t avail = (info.f_frsize * info.f_bavail) / 1024;
+
+ pTable->field[0]->store(zDisk, strlen(zDisk), system_charset_info);
+ pTable->field[1]->store(zPath, strlen(zPath), system_charset_info);
+ pTable->field[2]->store(total);
+ pTable->field[3]->store(used);
+ pTable->field[4]->store(avail);
+
+ // 0 means success.
+ return (schema_table_store_record(pThd, pTable) != 0) ? 1 : 0;
+}
+
+int disks_table_add_row(THD* pThd, TABLE* pTable, const char* zDisk, const char* zPath)
+{
+ int rv = 0;
+
+ struct statvfs info;
+
+ if (statvfs(zPath, &info) == 0) // We ignore failures.
+ {
+ rv = disks_table_add_row(pThd, pTable, zDisk, zPath, info);
+ }
+
+ return rv;
+}
+
+int disks_fill_table(THD* pThd, TABLE_LIST* pTables, Item* pCond)
+{
+ int rv = 1;
+ TABLE* pTable = pTables->table;
+
+ FILE* pFile = setmntent("/etc/mtab", "r");
+
+ if (pFile)
+ {
+ const size_t BUFFER_SIZE = 4096; // 4K should be sufficient.
+
+ char* pBuffer = new (std::nothrow) char [BUFFER_SIZE];
+
+ if (pBuffer)
+ {
+ rv = 0;
+
+ struct mntent ent;
+ struct mntent* pEnt;
+
+ while ((rv == 0) && (pEnt = getmntent_r(pFile, &ent, pBuffer, BUFFER_SIZE)))
+ {
+ // We only report the ones that refer to physical disks.
+ if (pEnt->mnt_fsname[0] == '/')
+ {
+ rv = disks_table_add_row(pThd, pTable, pEnt->mnt_fsname, pEnt->mnt_dir);
+ }
+ }
+
+ delete [] pBuffer;
+ }
+ else
+ {
+ rv = 1;
+ }
+
+ endmntent(pFile);
+ }
+
+ return rv;
+}
+
+int disks_table_init(void *ptr)
+{
+ ST_SCHEMA_TABLE* pSchema_table = (ST_SCHEMA_TABLE*)ptr;
+
+ pSchema_table->fields_info = disks_table_fields;
+ pSchema_table->fill_table = disks_fill_table;
+ return 0;
+}
+
+}
+
+extern "C"
+{
+
+maria_declare_plugin(disks)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &disks_table_info, /* type-specific descriptor */
+ "DISKS", /* table name */
+ "Johan Wikman", /* author */
+ "Disk space information", /* description */
+ PLUGIN_LICENSE_GPL, /* license type */
+ disks_table_init, /* init function */
+ NULL, /* deinit function */
+ 0x0100, /* version = 1.0 */
+ NULL, /* no status variables */
+ NULL, /* no system variables */
+ "1.0", /* String version representation */
+ MariaDB_PLUGIN_MATURITY_BETA /* Maturity (see include/mysql/plugin.h)*/
+}
+mysql_declare_plugin_end;
+
+}
diff --git a/plugin/disks/mysql-test/disks/disks.result b/plugin/disks/mysql-test/disks/disks.result
new file mode 100644
index 00000000000..bd6befc5e11
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/disks.result
@@ -0,0 +1,12 @@
+show create table information_schema.disks;
+Table Create Table
+DISKS CREATE TEMPORARY TABLE `DISKS` (
+ `Disk` varchar(4096) NOT NULL DEFAULT '',
+ `Path` varchar(4096) NOT NULL DEFAULT '',
+ `Total` int(32) NOT NULL DEFAULT '0',
+ `Used` int(32) NOT NULL DEFAULT '0',
+ `Available` int(32) NOT NULL DEFAULT '0'
+) ENGINE=MEMORY DEFAULT CHARSET=utf8
+select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks;
+sum(Total) > sum(Available) sum(Total)>sum(Used)
+1 1
diff --git a/plugin/disks/mysql-test/disks/disks.test b/plugin/disks/mysql-test/disks/disks.test
new file mode 100644
index 00000000000..13a0762ae01
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/disks.test
@@ -0,0 +1,2 @@
+show create table information_schema.disks;
+select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks;
diff --git a/plugin/disks/mysql-test/disks/suite.opt b/plugin/disks/mysql-test/disks/suite.opt
new file mode 100644
index 00000000000..afbbe2b0163
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$DISKS_SO
diff --git a/plugin/disks/mysql-test/disks/suite.pm b/plugin/disks/mysql-test/disks/suite.pm
new file mode 100644
index 00000000000..c64ef3b3133
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/suite.pm
@@ -0,0 +1,10 @@
+package My::Suite::Disks;
+
+@ISA = qw(My::Suite);
+
+return "No Disks plugin" unless $ENV{DISKS_SO};
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/example_key_management/CMakeLists.txt b/plugin/example_key_management/CMakeLists.txt
new file mode 100644
index 00000000000..fe893e5368e
--- /dev/null
+++ b/plugin/example_key_management/CMakeLists.txt
@@ -0,0 +1,2 @@
+MYSQL_ADD_PLUGIN(EXAMPLE_KEY_MANAGEMENT example_key_management_plugin.cc
+ MODULE_ONLY COMPONENT Test)
diff --git a/plugin/example_key_management/example_key_management_plugin.cc b/plugin/example_key_management/example_key_management_plugin.cc
new file mode 100644
index 00000000000..665e3128e52
--- /dev/null
+++ b/plugin/example_key_management/example_key_management_plugin.cc
@@ -0,0 +1,170 @@
+/*
+ Copyright (c) 2014 Google Inc.
+ Copyright (c) 2014, 2015 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ Example key management plugin. It demonstrates how to return
+ keys on request, how to change them. That the engine can have
+ different pages in the same tablespace encrypted with different keys
+ and what the background re-encryption thread does.
+
+ THIS IS AN EXAMPLE ONLY! ENCRYPTION KEYS ARE HARD-CODED AND *NOT* SECRET!
+ DO NOT USE THIS PLUGIN IN PRODUCTION! EVER!
+*/
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <mysql/plugin_encryption.h>
+#include <my_crypt.h>
+
+/* rotate key randomly between 45 and 90 seconds */
+#define KEY_ROTATION_MIN 45
+#define KEY_ROTATION_MAX 90
+
+static time_t key_version = 0;
+static time_t next_key_version = 0;
+static pthread_mutex_t mutex;
+
+
+/* Random double value in 0..1 range */
+static double double_rnd()
+{
+ return ((double)rand()) / RAND_MAX;
+}
+
+
+static unsigned int
+get_latest_key_version(unsigned int key_id)
+{
+ time_t now = time(0);
+ pthread_mutex_lock(&mutex);
+ if (now >= next_key_version)
+ {
+ key_version = now;
+ unsigned int interval = KEY_ROTATION_MAX - KEY_ROTATION_MIN;
+ next_key_version = (time_t) (now + KEY_ROTATION_MIN +
+ double_rnd() * interval);
+ }
+ pthread_mutex_unlock(&mutex);
+
+ return (unsigned int) key_version;
+}
+
+static unsigned int
+get_key(unsigned int key_id, unsigned int version,
+ unsigned char* dstbuf, unsigned *buflen)
+{
+ if (*buflen < MY_MD5_HASH_SIZE)
+ {
+ *buflen= MY_MD5_HASH_SIZE;
+ return ENCRYPTION_KEY_BUFFER_TOO_SMALL;
+ }
+ *buflen= MY_MD5_HASH_SIZE;
+ if (!dstbuf)
+ return 0;
+
+ my_md5_multi(dstbuf, (const char*)&key_id, sizeof(key_id),
+ (const char*)&version, sizeof(version), NULL);
+
+ return 0;
+}
+
+/*
+ for the sake of an example, let's use different encryption algorithms/modes
+ for different keys versions:
+*/
+static inline enum my_aes_mode mode(unsigned int key_version)
+{
+ return key_version & 1 ? MY_AES_ECB : MY_AES_CBC;
+}
+
+int ctx_init(void *ctx, const unsigned char* key, unsigned int klen, const
+ unsigned char* iv, unsigned int ivlen, int flags, unsigned int
+ key_id, unsigned int key_version)
+{
+ return my_aes_crypt_init(ctx, mode(key_version), flags, key, klen, iv, ivlen);
+}
+
+static unsigned int get_length(unsigned int slen, unsigned int key_id,
+ unsigned int key_version)
+{
+ return my_aes_get_size(mode(key_version), slen);
+}
+
+static int example_key_management_plugin_init(void *p)
+{
+ /* init */
+ pthread_mutex_init(&mutex, NULL);
+ get_latest_key_version(1);
+
+ return 0;
+}
+
+static int example_key_management_plugin_deinit(void *p)
+{
+ pthread_mutex_destroy(&mutex);
+ return 0;
+}
+
+
+static int ctx_update(void *ctx, const unsigned char *src, unsigned int slen,
+ unsigned char *dst, unsigned int *dlen)
+{
+ return my_aes_crypt_update(ctx, src, slen, dst, dlen);
+}
+
+
+int ctx_finish(void *ctx, unsigned char *dst, unsigned int *dlen)
+{
+ return my_aes_crypt_finish(ctx, dst, dlen);
+}
+
+static uint ctx_size(unsigned int , unsigned int key_version)
+{
+ return my_aes_ctx_size(mode(key_version));
+}
+
+struct st_mariadb_encryption example_key_management_plugin= {
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ get_latest_key_version,
+ get_key,
+ ctx_size,
+ ctx_init,
+ ctx_update,
+ ctx_finish,
+ get_length
+};
+
+/*
+ Plugin library descriptor
+*/
+maria_declare_plugin(example_key_management)
+{
+ MariaDB_ENCRYPTION_PLUGIN,
+ &example_key_management_plugin,
+ "example_key_management",
+ "Jonas Oreland",
+ "Example key management plugin",
+ PLUGIN_LICENSE_GPL,
+ example_key_management_plugin_init,
+ example_key_management_plugin_deinit,
+ 0x0100 /* 1.0 */,
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL
+}
+maria_declare_plugin_end;
diff --git a/plugin/feedback/CMakeLists.txt b/plugin/feedback/CMakeLists.txt
index 3e14ef3918b..2103250e5a6 100644
--- a/plugin/feedback/CMakeLists.txt
+++ b/plugin/feedback/CMakeLists.txt
@@ -1,4 +1,5 @@
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql
+ ${PCRE_INCLUDES}
${SSL_INCLUDE_DIRS})
SET(FEEDBACK_SOURCES feedback.cc sender_thread.cc
@@ -13,10 +14,10 @@ IF(HAVE_NETDB_H)
ENDIF(HAVE_NETDB_H)
IF(WIN32)
- MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES}
- LINK_LIBRARIES ${SSL_LIBRARIES}
- STATIC_ONLY DEFAULT)
-ELSE(WIN32)
- MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES}
- LINK_LIBRARIES ${SSL_LIBRARIES})
+ SET(MAYBE_STATIC_ONLY STATIC_ONLY)
ENDIF(WIN32)
+
+MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES}
+ LINK_LIBRARIES ${SSL_LIBRARIES}
+ ${MAYBE_STATIC_ONLY} RECOMPILE_FOR_EMBEDDED DEFAULT)
+
diff --git a/plugin/feedback/feedback.cc b/plugin/feedback/feedback.cc
index 01fcdd935bb..75e6e8ddf17 100644
--- a/plugin/feedback/feedback.cc
+++ b/plugin/feedback/feedback.cc
@@ -103,25 +103,28 @@ static COND* make_cond(THD *thd, TABLE_LIST *tables, LEX_STRING *filter)
nrc.init();
nrc.resolve_in_table_list_only(tables);
- res= new Item_cond_or();
+ res= new (thd->mem_root) Item_cond_or(thd);
if (!res)
return OOM;
for (; filter->str; filter++)
{
- Item_field *fld= new Item_field(&nrc, db, table, field);
- Item_string *pattern= new Item_string(filter->str, filter->length, cs);
- Item_string *escape= new Item_string("\\", 1, cs);
+ Item_field *fld= new (thd->mem_root) Item_field(thd, &nrc, db, table,
+ field);
+ Item_string *pattern= new (thd->mem_root) Item_string(thd, filter->str,
+ filter->length, cs);
+ Item_string *escape= new (thd->mem_root) Item_string(thd, "\\", 1, cs);
if (!fld || !pattern || !escape)
return OOM;
- Item_func_like *like= new Item_func_like(fld, pattern, escape, 0);
+ Item_func_like *like= new (thd->mem_root) Item_func_like(thd, fld, pattern,
+ escape, 0);
if (!like)
return OOM;
- res->add(like);
+ res->add(like, thd->mem_root);
}
if (res->fix_fields(thd, (Item**)&res))
@@ -221,7 +224,8 @@ int fill_feedback(THD *thd, TABLE_LIST *tables, COND *unused)
tables->schema_table= i_s_feedback;
res= res || fill_plugin_version(thd, tables)
|| fill_misc_data(thd, tables)
- || fill_linux_info(thd, tables);
+ || fill_linux_info(thd, tables)
+ || fill_collation_statistics(thd, tables);
return res;
}
@@ -437,7 +441,7 @@ maria_declare_plugin(feedback)
NULL,
feedback::settings,
"1.1",
- MariaDB_PLUGIN_MATURITY_BETA
+ MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;
#endif
diff --git a/plugin/feedback/feedback.h b/plugin/feedback/feedback.h
index a5ddbc47956..0fffeb922d5 100644
--- a/plugin/feedback/feedback.h
+++ b/plugin/feedback/feedback.h
@@ -22,6 +22,7 @@ int fill_feedback(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_plugin_version(THD *thd, TABLE_LIST *tables);
int fill_misc_data(THD *thd, TABLE_LIST *tables);
int fill_linux_info(THD *thd, TABLE_LIST *tables);
+int fill_collation_statistics(THD *thd, TABLE_LIST *tables);
static const int SERVER_UID_SIZE= 29;
extern char server_uid_buf[SERVER_UID_SIZE+1], *user_info;
diff --git a/plugin/feedback/sender_thread.cc b/plugin/feedback/sender_thread.cc
index 1adfdb54e99..e22550998a7 100644
--- a/plugin/feedback/sender_thread.cc
+++ b/plugin/feedback/sender_thread.cc
@@ -16,6 +16,7 @@
#include "feedback.h"
#include <sql_acl.h>
#include <sql_parse.h>
+#include <sql_show.h>
#include <time.h>
namespace feedback {
@@ -100,7 +101,7 @@ static int prepare_for_fill(TABLE_LIST *tables)
thd->mysys_var->current_cond= &sleep_condition;
thd->mysys_var->current_mutex= &sleep_mutex;
thd->proc_info="feedback";
- thd->command=COM_SLEEP;
+ thd->set_command(COM_SLEEP);
thd->system_thread= SYSTEM_THREAD_EVENT_WORKER; // whatever
thd->set_time();
thd->init_for_queries();
@@ -120,7 +121,7 @@ static int prepare_for_fill(TABLE_LIST *tables)
strlen(i_s_feedback->table_name),
0, TL_READ);
tables->schema_table= i_s_feedback;
- tables->table= i_s_feedback->create_table(thd, tables);
+ tables->table= create_schema_table(thd, tables);
if (!tables->table)
return 1;
@@ -204,7 +205,7 @@ static void send_report(const char *when)
/*
otherwise, prepare the THD and TABLE_LIST,
create and fill the temporary table with data just like
- SELECT * FROM IFROEMATION_SCHEMA.feedback is doing,
+ SELECT * FROM INFORMATION_SCHEMA.FEEDBACK is doing,
read and concatenate table data into a String.
*/
if (!(thd= new THD()))
@@ -261,7 +262,7 @@ ret:
the effect of the background thread on SHOW STATUS.
*/
mysql_mutex_lock(&LOCK_thread_count);
- bzero(&thd->status_var, sizeof(thd->status_var));
+ thd->set_status_var_init();
thread_count--;
thd->killed= KILL_CONNECTION;
mysql_cond_broadcast(&COND_thread_count);
diff --git a/plugin/feedback/url_http.cc b/plugin/feedback/url_http.cc
index c1a19053770..6ae94d5b9c4 100644
--- a/plugin/feedback/url_http.cc
+++ b/plugin/feedback/url_http.cc
@@ -217,7 +217,7 @@ int Url_http::send(const char* data, size_t data_length)
{
enum enum_ssl_init_error ssl_init_error= SSL_INITERR_NOERROR;
ulong ssl_error= 0;
- if (!(ssl_fd= new_VioSSLConnectorFd(0, 0, 0, 0, 0, &ssl_init_error)) ||
+ if (!(ssl_fd= new_VioSSLConnectorFd(0, 0, 0, 0, 0, &ssl_init_error, 0, 0)) ||
sslconnect(ssl_fd, vio, send_timeout, &ssl_error))
{
const char *err;
diff --git a/plugin/feedback/utils.cc b/plugin/feedback/utils.cc
index cbab0e2ed4e..684d95a3dbf 100644
--- a/plugin/feedback/utils.cc
+++ b/plugin/feedback/utils.cc
@@ -19,9 +19,6 @@
#include <unistd.h>
#endif
-#include <base64.h>
-#include <sha1.h>
-
#if defined (_WIN32)
#define HAVE_SYS_UTSNAME_H
@@ -353,8 +350,10 @@ int prepare_linux_info()
*/
int fill_linux_info(THD *thd, TABLE_LIST *tables)
{
+#if defined(HAVE_SYS_UTSNAME_H) || defined(TARGET_OS_LINUX)
TABLE *table= tables->table;
CHARSET_INFO *cs= system_charset_info;
+#endif
#ifdef HAVE_SYS_UTSNAME_H
if (have_ubuf)
@@ -390,6 +389,25 @@ int fill_misc_data(THD *thd, TABLE_LIST *tables)
return 0;
}
+int fill_collation_statistics(THD *thd, TABLE_LIST *tables)
+{
+ TABLE *table= tables->table;
+ for (uint id= 1; id < MY_ALL_CHARSETS_SIZE; id++)
+ {
+ ulonglong count;
+ if (my_collation_is_known_id(id) &&
+ (count= my_collation_statistics_get_use_count(id)))
+ {
+ char name[MY_CS_NAME_SIZE + 32];
+ size_t namelen= my_snprintf(name, sizeof(name),
+ "Collation used %s",
+ get_charset_name(id));
+ INSERT2(name, namelen, (count, UNSIGNED));
+ }
+ }
+ return 0;
+};
+
/**
calculates the server unique identifier
@@ -399,8 +417,7 @@ int fill_misc_data(THD *thd, TABLE_LIST *tables)
int calculate_server_uid(char *dest)
{
uchar rawbuf[2 + 6];
- uchar shabuf[SHA1_HASH_SIZE];
- SHA1_CONTEXT ctx;
+ uchar shabuf[MY_SHA1_HASH_SIZE];
int2store(rawbuf, mysqld_port);
if (my_gethwaddr(rawbuf + 2))
@@ -409,9 +426,7 @@ int calculate_server_uid(char *dest)
return 1;
}
- mysql_sha1_reset(&ctx);
- mysql_sha1_input(&ctx, rawbuf, sizeof(rawbuf));
- mysql_sha1_result(&ctx, shabuf);
+ my_sha1((uint8*) shabuf, (char*) rawbuf, sizeof(rawbuf));
assert(base64_needed_encoded_length(sizeof(shabuf)) <= SERVER_UID_SIZE);
base64_encode(shabuf, sizeof(shabuf), dest);
diff --git a/plugin/file_key_management/CMakeLists.txt b/plugin/file_key_management/CMakeLists.txt
new file mode 100644
index 00000000000..c2f13fb9f63
--- /dev/null
+++ b/plugin/file_key_management/CMakeLists.txt
@@ -0,0 +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})
diff --git a/plugin/file_key_management/file_key_management_plugin.cc b/plugin/file_key_management/file_key_management_plugin.cc
new file mode 100644
index 00000000000..b5dcbd71f1e
--- /dev/null
+++ b/plugin/file_key_management/file_key_management_plugin.cc
@@ -0,0 +1,201 @@
+/* Copyright (c) 2002, 2012, eperi GmbH.
+
+ 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <typelib.h>
+#include "parser.h"
+#include <mysql/plugin_encryption.h>
+#include <string.h>
+
+static char* filename;
+static char* filekey;
+static unsigned long encryption_algorithm;
+
+static const char *encryption_algorithm_names[]=
+{
+ "aes_cbc",
+#ifdef HAVE_EncryptAes128Ctr
+ "aes_ctr",
+#endif
+ 0
+};
+
+static TYPELIB encryption_algorithm_typelib=
+{
+ array_elements(encryption_algorithm_names)-1,"",
+ encryption_algorithm_names, NULL
+};
+
+
+static MYSQL_SYSVAR_STR(filename, filename,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Path and name of the key file.",
+ NULL, NULL, "");
+
+static MYSQL_SYSVAR_STR(filekey, filekey,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Key to encrypt / decrypt the keyfile.",
+ NULL, NULL, "");
+
+#ifdef HAVE_EncryptAes128Ctr
+#define recommendation ", aes_ctr is the recommended one"
+#else
+#define recommendation ""
+#endif
+static MYSQL_SYSVAR_ENUM(encryption_algorithm, encryption_algorithm,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Encryption algorithm to use" recommendation ".",
+ NULL, NULL, 0, &encryption_algorithm_typelib);
+
+static struct st_mysql_sys_var* settings[] = {
+ MYSQL_SYSVAR(filename),
+ MYSQL_SYSVAR(filekey),
+ MYSQL_SYSVAR(encryption_algorithm),
+ NULL
+};
+
+std::map<unsigned int,keyentry> keys;
+
+static keyentry *get_key(unsigned int key_id)
+{
+ keyentry &key= keys[key_id];
+ if (key.id == 0)
+ return 0;
+ return &key;
+}
+
+/* the version is always the same, no automatic key rotation */
+static unsigned int get_latest_version(uint key_id)
+{
+ return get_key(key_id) ? 1 : ENCRYPTION_KEY_VERSION_INVALID;
+}
+
+static unsigned int get_key_from_key_file(unsigned int key_id,
+ unsigned int key_version, unsigned char* dstbuf, unsigned *buflen)
+{
+ if (key_version != 1)
+ return ENCRYPTION_KEY_VERSION_INVALID;
+
+ keyentry* entry = get_key(key_id);
+
+ if (entry == NULL)
+ return ENCRYPTION_KEY_VERSION_INVALID;
+
+ if (*buflen < entry->length)
+ {
+ *buflen= entry->length;
+ return ENCRYPTION_KEY_BUFFER_TOO_SMALL;
+ }
+
+ *buflen= entry->length;
+ if (dstbuf)
+ memcpy(dstbuf, entry->key, entry->length);
+
+ return 0;
+}
+
+// let's simplify the condition below
+#ifndef HAVE_EncryptAes128Gcm
+#define MY_AES_GCM MY_AES_CTR
+#ifndef HAVE_EncryptAes128Ctr
+#define MY_AES_CTR MY_AES_CBC
+#endif
+#endif
+
+static inline enum my_aes_mode mode(int flags)
+{
+ /*
+ If encryption_algorithm is AES_CTR then
+ if no-padding, use AES_CTR
+ else use AES_GCM (like CTR but appends a "checksum" block)
+ else
+ use AES_CBC
+ */
+ if (encryption_algorithm)
+ if (flags & ENCRYPTION_FLAG_NOPAD)
+ return MY_AES_CTR;
+ else
+ return MY_AES_GCM;
+ else
+ return MY_AES_CBC;
+}
+
+static int ctx_init(void *ctx, const unsigned char* key, unsigned int klen,
+ const unsigned char* iv, unsigned int ivlen, int flags,
+ unsigned int key_id, unsigned int key_version)
+{
+ return my_aes_crypt_init(ctx, mode(flags), flags, key, klen, iv, ivlen);
+}
+
+static int ctx_update(void *ctx, const unsigned char *src, unsigned int slen,
+ unsigned char *dst, unsigned int *dlen)
+{
+ return my_aes_crypt_update(ctx, src, slen, dst, dlen);
+}
+
+
+static int ctx_finish(void *ctx, unsigned char *dst, unsigned int *dlen)
+{
+ return my_aes_crypt_finish(ctx, dst, dlen);
+}
+
+static unsigned int get_length(unsigned int slen, unsigned int key_id,
+ unsigned int key_version)
+{
+ return my_aes_get_size(mode(0), slen);
+}
+
+static uint ctx_size(uint, uint)
+{
+ return my_aes_ctx_size(mode(0));
+}
+
+struct st_mariadb_encryption file_key_management_plugin= {
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ get_latest_version,
+ get_key_from_key_file,
+ ctx_size,
+ ctx_init,
+ ctx_update,
+ ctx_finish,
+ get_length
+};
+
+static int file_key_management_plugin_init(void *p)
+{
+ Parser parser(filename, filekey);
+ return parser.parse(&keys);
+}
+
+/*
+ Plugin library descriptor
+*/
+maria_declare_plugin(file_key_management)
+{
+ MariaDB_ENCRYPTION_PLUGIN,
+ &file_key_management_plugin,
+ "file_key_management",
+ "Denis Endro eperi GmbH",
+ "File-based key management plugin",
+ PLUGIN_LICENSE_GPL,
+ file_key_management_plugin_init,
+ NULL,
+ 0x0100 /* 1.0 */,
+ NULL, /* status variables */
+ settings,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/file_key_management/parser.cc b/plugin/file_key_management/parser.cc
new file mode 100644
index 00000000000..83895fe2808
--- /dev/null
+++ b/plugin/file_key_management/parser.cc
@@ -0,0 +1,409 @@
+/* Copyright (C) 2014 eperi GmbH.
+ Copyright (C) 2015 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/******************************************************************//**
+ @file Parser.cc
+ A class to parse the key file
+
+How it works...
+The location and usage can be configured via the configuration file.
+Example
+
+[mysqld]
+...
+file_key_management_filename = /home/mdb/keys.enc
+file_key_management_filekey = secret
+...
+
+The keys are read from a file.
+The filename is set up via the file_key_management_filename
+configuration value.
+file_key_management_filename is used to configure the absolute
+path to this file.
+
+Examples:
+file_key_management_filename = \\\\unc\\keys.enc (windows share)
+file_key_management_filename = e:/tmp/keys.enc (windows path)
+file_key_management_filename = /tmp/keys.enc (linux path)
+
+The key file contains AES keys as hex-encoded strings.
+Supported are keys of size 128, 192 or 256 bits.
+Example:
+1;F5502320F8429037B8DAEF761B189D12
+2;770A8A65DA156D24EE2A093277530142770A8A65DA156D24EE2A093277530142
+
+1 is the key identifier which can be used for table creation,
+it is followed by a AES key
+
+The key file could be encrypted and the key to decrypt the file can
+be given with the optional file_key_management_filekey
+parameter.
+
+The file key can also be located if FILE: is prepended to the
+key. Then the following part is interpreted as absolute path to the
+file containing the file key (which must be a text - not binary - string).
+
+Example:
+
+file_key_management_filekey = FILE:y:/secret256.enc
+
+If the key file can not be read at server startup, for example if the
+file key is not present, the plugin will not start
+access to encrypted tables will not be possible.
+
+Open SSL command line utility can be used to create an encrypted key file.
+Example:
+openssl enc -aes-256-cbc -md sha1 -k "secret" -in keys.txt -out keys.enc
+***********************************************************************/
+
+#include "parser.h"
+#include <m_string.h>
+#include <mysys_err.h>
+
+#define FILE_PREFIX "FILE:"
+#define MAX_KEY_FILE_SIZE 1024*1024
+#define MAX_SECRET_SIZE 256
+
+/*
+ The values below are what one gets after
+ openssl enc -aes-256-cbc -md sha1 -k "secret" -in keys.txt -out keys.enc
+*/
+#define OpenSSL_prefix "Salted__"
+#define OpenSSL_prefix_len (sizeof(OpenSSL_prefix) - 1)
+#define OpenSSL_salt_len 8
+#define OpenSSL_key_len 32
+#define OpenSSL_iv_len 16
+
+/**
+ Calculate key and iv from a given salt and secret as in the
+ openssl command-line tool
+
+ @param salt [in] the given salt as extracted from the encrypted file
+ @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,
+ unsigned char *key, unsigned char *iv)
+{
+ unsigned char digest[MY_SHA1_HASH_SIZE];
+ int key_left = OpenSSL_key_len;
+ int iv_left = OpenSSL_iv_len;
+ const size_t ilen= strlen(input);
+ const size_t slen= OpenSSL_salt_len; // either this or explicit (size_t) casts below
+
+ my_sha1_multi(digest, input, ilen, salt, slen, NullS);
+
+ while (iv_left)
+ {
+ int left= MY_SHA1_HASH_SIZE;
+ if (key_left)
+ {
+ int store = MY_MIN(key_left, MY_SHA1_HASH_SIZE);
+ memcpy(&key[OpenSSL_key_len - key_left], digest, store);
+
+ key_left -= store;
+ left -= store;
+ }
+
+ if (iv_left && left)
+ {
+ int store= MY_MIN(iv_left, left);
+ memcpy(&iv[OpenSSL_iv_len - iv_left], &digest[MY_SHA1_HASH_SIZE - left], store);
+
+ iv_left -= store;
+ }
+
+ if (iv_left)
+ my_sha1_multi(digest, digest, MY_SHA1_HASH_SIZE,
+ input, ilen, salt, slen, NullS);
+ }
+}
+
+
+bool Parser::parse(std::map<uint,keyentry> *keys)
+{
+ const char *secret= filekey;
+ char buf[MAX_SECRET_SIZE + 1];
+
+ //If secret starts with FILE: interpret the secret as a filename.
+ if (strncmp(filekey, FILE_PREFIX,sizeof(FILE_PREFIX) -1) == 0)
+ {
+ if (read_filekey(filekey + sizeof(FILE_PREFIX) - 1, buf))
+ return 1;
+ secret= buf;
+ }
+
+ return parse_file(keys, secret);
+}
+
+
+/*
+ secret is limited to MAX_SECRET_SIZE characters
+*/
+
+bool Parser::read_filekey(const char *filekey, char *secret)
+{
+ int f= open(filekey, O_RDONLY|O_BINARY);
+ if (f == -1)
+ {
+ my_error(EE_FILENOTFOUND,ME_ERROR_LOG, filekey, errno);
+ return 1;
+ }
+
+ int len= read(f, secret, MAX_SECRET_SIZE);
+ if (len <= 0)
+ {
+ my_error(EE_READ,ME_ERROR_LOG, filekey, errno);
+ close(f);
+ return 1;
+ }
+ close(f);
+ while (secret[len - 1] == '\r' || secret[len - 1] == '\n') len--;
+ secret[len]= '\0';
+ return 0;
+}
+
+
+/**
+ Get the keys from the key file <filename> and decrypt it with the
+ key <secret>. Store the keys with id smaller then <maxKeyId> in an
+ array of structs keyentry.
+
+ @return 0 when ok, 1 for an error
+ */
+
+bool Parser::parse_file(std::map<uint,keyentry> *keys, const char *secret)
+{
+ char *buffer= read_and_decrypt_file(secret);
+
+ if (!buffer)
+ return 1;
+
+ keyentry key;
+ char *line=buffer;
+
+ while (*line)
+ {
+ line_number++;
+ switch (parse_line(&line, &key)) {
+ case 1: // comment
+ break;
+ case -1: // error
+ free(buffer);
+ return 1;
+ case 0:
+ (*keys)[key.id] = key;
+ break;
+ }
+ }
+
+ free(buffer);
+ if (keys->size() == 0 || (*keys)[1].id == 0)
+ {
+ report_error("System key id 1 is missing", 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+void Parser::report_error(const char *reason, uint position)
+{
+ my_printf_error(EE_READ, "%s at %s line %u, column %u",
+ ME_ERROR_LOG, reason, filename, line_number, position + 1);
+}
+
+/*
+ return 0 - new key
+ 1 - comment
+ -1 - error
+*/
+int Parser::parse_line(char **line_ptr, keyentry *key)
+{
+ int res= 1;
+ char *p= *line_ptr;
+ while (isspace(*p) && *p != '\n') p++;
+ if (*p != '#' && *p != '\n')
+ {
+ if (!isdigit(*p))
+ {
+ report_error("Syntax error", p - *line_ptr);
+ return -1;
+ }
+
+ longlong id = 0;
+ while (isdigit(*p))
+ {
+ id = id * 10 + *p - '0';
+ if (id > UINT_MAX32)
+ {
+ report_error("Invalid key id", p - *line_ptr);
+ return -1;
+ }
+ p++;
+ }
+
+ if (id < 1)
+ {
+ report_error("Invalid key id", p - *line_ptr);
+ return -1;
+ }
+
+ if (*p != ';')
+ {
+ report_error("Syntax error", p - *line_ptr);
+ return -1;
+ }
+
+ p++;
+ key->id= (unsigned int)id;
+ key->length=0;
+ while (isxdigit(p[0]) && isxdigit(p[1]) && key->length < sizeof(key->key))
+ {
+ key->key[key->length++] = from_hex(p[0]) * 16 + from_hex(p[1]);
+ p+=2;
+ }
+ if (isxdigit(*p) ||
+ (key->length != 16 && key->length != 24 && key->length != 32))
+ {
+ report_error("Invalid key", p - *line_ptr);
+ return -1;
+ }
+
+ res= 0;
+ }
+ while (*p && *p != '\n') p++;
+ *line_ptr= *p == '\n' ? p + 1 : p;
+ return res;
+}
+
+/**
+ Decrypt the key file 'filename' if it is encrypted with the key
+ 'secret'. Store the content of the decrypted file in 'buffer'. The
+ buffer has to be freed in the calling function.
+ */
+#ifdef _WIN32
+#define lseek _lseeki64
+#endif
+
+char* Parser::read_and_decrypt_file(const char *secret)
+{
+ int f;
+ if (!filename || !filename[0])
+ {
+ my_printf_error(EE_CANT_OPEN_STREAM, "file-key-management-filename is not set",
+ ME_ERROR_LOG);
+ goto err0;
+ }
+
+ f= open(filename, O_RDONLY|O_BINARY, 0);
+ if (f < 0)
+ {
+ my_error(EE_FILENOTFOUND, ME_ERROR_LOG, filename, errno);
+ goto err0;
+ }
+
+ my_off_t file_size;
+ file_size= lseek(f, 0, SEEK_END);
+
+ if (file_size == MY_FILEPOS_ERROR || (my_off_t)lseek(f, 0, SEEK_SET) == MY_FILEPOS_ERROR)
+ {
+ my_error(EE_CANT_SEEK, MYF(0), filename, errno);
+ goto err1;
+ }
+
+ if (file_size > MAX_KEY_FILE_SIZE)
+ {
+ my_error(EE_READ, MYF(0), filename, EFBIG);
+ goto err1;
+ }
+
+ //Read file into buffer
+ uchar *buffer;
+ buffer= (uchar*)malloc((size_t)file_size + 1);
+ if (!buffer)
+ {
+ my_error(EE_OUTOFMEMORY, ME_ERROR_LOG| ME_FATAL, file_size);
+ goto err1;
+ }
+
+ if (read(f, buffer, (int)file_size) != (int)file_size)
+ {
+ my_printf_error(EE_READ,
+ "read from %s failed, errno %d",
+ MYF(ME_ERROR_LOG|ME_FATAL), filename, errno);
+ goto err2;
+ }
+
+// Check for file encryption
+ uchar *decrypted;
+ if (file_size > OpenSSL_prefix_len && strncmp((char*)buffer, OpenSSL_prefix, OpenSSL_prefix_len) == 0)
+ {
+ uchar key[OpenSSL_key_len];
+ uchar iv[OpenSSL_iv_len];
+
+ decrypted= (uchar*)malloc((size_t)file_size);
+ if (!decrypted)
+ {
+ my_error(EE_OUTOFMEMORY, ME_ERROR_LOG | ME_FATAL, file_size);
+ goto err2;
+ }
+ bytes_to_key(buffer + OpenSSL_prefix_len, secret, key, iv);
+ uint32 d_size;
+ if (my_aes_crypt(MY_AES_CBC, ENCRYPTION_FLAG_DECRYPT,
+ buffer + OpenSSL_prefix_len + OpenSSL_salt_len,
+ (unsigned int)file_size - OpenSSL_prefix_len - OpenSSL_salt_len,
+ decrypted, &d_size, key, OpenSSL_key_len,
+ iv, OpenSSL_iv_len))
+
+ {
+ my_printf_error(EE_READ, "Cannot decrypt %s. Wrong key?", ME_ERROR_LOG, filename);
+ goto err3;
+ }
+
+ free(buffer);
+ buffer= decrypted;
+ file_size= d_size;
+ }
+ else if (*secret)
+ {
+ my_printf_error(EE_READ, "Cannot decrypt %s. Not encrypted", ME_ERROR_LOG, filename);
+ goto err2;
+ }
+
+ buffer[file_size]= '\0';
+ close(f);
+ return (char*) buffer;
+
+err3:
+ free(decrypted);
+err2:
+ free(buffer);
+err1:
+ close(f);
+err0:
+ return NULL;
+}
diff --git a/plugin/file_key_management/parser.h b/plugin/file_key_management/parser.h
new file mode 100644
index 00000000000..ca9dedd8acc
--- /dev/null
+++ b/plugin/file_key_management/parser.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2014 eperi GmbH.
+
+ 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/******************************************************************//**
+@file Parser.h
+A structure and class to keep keys for encryption/decryption.
+
+Created 09/15/2014
+***********************************************************************/
+
+#include <my_crypt.h>
+#include <ctype.h>
+#include <map>
+
+struct keyentry {
+ unsigned int id;
+ unsigned char key[MY_AES_MAX_KEY_LENGTH];
+ unsigned int length;
+};
+
+class Parser
+{
+ const char *filename;
+ const char *filekey;
+ unsigned int line_number;
+
+ unsigned int from_hex(char c)
+ { return c <= '9' ? c - '0' : tolower(c) - 'a' + 10; }
+
+ void bytes_to_key(const unsigned char *salt, const char *secret,
+ unsigned char *key, unsigned char *iv);
+ bool read_filekey(const char *filekey, char *secret);
+ bool parse_file(std::map<unsigned int ,keyentry> *keys, const char *secret);
+ void report_error(const char *reason, unsigned int position);
+ int parse_line(char **line_ptr, keyentry *key);
+ char* read_and_decrypt_file(const char *secret);
+
+public:
+ Parser(const char* fn, const char *fk) :
+ filename(fn), filekey(fk), line_number(0) { }
+ bool parse(std::map<unsigned int ,keyentry> *keys);
+};
diff --git a/plugin/fulltext/plugin_example.c b/plugin/fulltext/plugin_example.c
index 8d347f5642f..f175179e8bb 100644
--- a/plugin/fulltext/plugin_example.c
+++ b/plugin/fulltext/plugin_example.c
@@ -254,24 +254,6 @@ static struct st_mysql_sys_var* simple_system_variables[]= {
Plugin library descriptor
*/
-mysql_declare_plugin(ftexample)
-{
- MYSQL_FTPARSER_PLUGIN, /* type */
- &simple_parser_descriptor, /* descriptor */
- "simple_parser", /* name */
- "Sergei Golubchik", /* author */
- "Simple Full-Text Parser", /* description */
- PLUGIN_LICENSE_GPL,
- simple_parser_plugin_init, /* init function (when loaded) */
- simple_parser_plugin_deinit,/* deinit function (when unloaded) */
- 0x0001, /* version */
- simple_status, /* status variables */
- simple_system_variables, /* system variables */
- NULL,
- 0,
-}
-mysql_declare_plugin_end;
-
maria_declare_plugin(ftexample)
{
MYSQL_FTPARSER_PLUGIN, /* type */
diff --git a/plugin/handler_socket/CMakeLists.txt b/plugin/handler_socket/CMakeLists.txt
index a0cac0015d0..bd656ebc5b7 100644
--- a/plugin/handler_socket/CMakeLists.txt
+++ b/plugin/handler_socket/CMakeLists.txt
@@ -6,9 +6,7 @@ IF(WIN32)
ENDIF()
#Remove -fno-implicit-templates from compiler flags(handlersocket would not work with it)
-IF(CMAKE_COMPILER_IS_GNUCXX)
- STRING(REPLACE "-fno-implicit-templates" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
-ENDIF()
+STRING(REPLACE "-fno-implicit-templates" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(" -Wdeprecated-declarations" HAVE_CXX_WDEPRECATED_DECLARATIONS)
@@ -42,6 +40,6 @@ SET(HANDLERSOCKET_SOURCES
MYSQL_ADD_PLUGIN(handlersocket
${HANDLERSOCKET_SOURCES}
MODULE_ONLY COMPONENT Server
- LINK_LIBRARIES hsclient
+ LINK_LIBRARIES hsclient RECOMPILE_FOR_EMBEDDED
)
diff --git a/plugin/handler_socket/client/hslongrun.cpp b/plugin/handler_socket/client/hslongrun.cpp
index e82c12b166b..b7c02951340 100644
--- a/plugin/handler_socket/client/hslongrun.cpp
+++ b/plugin/handler_socket/client/hslongrun.cpp
@@ -39,7 +39,7 @@ struct auto_mysql : private noncopyable {
mysql_close(db);
}
if ((db = mysql_init(0)) == 0) {
- fatal_exit("failed to initialize mysql client");
+ fatal_abort("failed to initialize mysql client");
}
}
operator MYSQL *() const { return db; }
@@ -870,7 +870,7 @@ mysql_do(MYSQL *db, const char *query)
{
if (mysql_real_query(db, query, strlen(query)) != 0) {
fprintf(stderr, "mysql: e=[%s] q=[%s]\n", mysql_error(db), query);
- fatal_exit("mysql_do");
+ fatal_abort("mysql_do");
}
}
@@ -886,7 +886,7 @@ hs_longrun_init_table(const config& conf, int num_prepare,
if (!mysql_real_connect(db, mysql_host.c_str(), mysql_user.c_str(),
mysql_passwd.c_str(), mysql_dbname.c_str(), mysql_port, 0, 0)) {
fprintf(stderr, "mysql: error=[%s]\n", mysql_error(db));
- fatal_exit("hs_longrun_init_table");
+ fatal_abort("hs_longrun_init_table");
}
mysql_do(db, "drop database if exists hstestdb");
mysql_do(db, "create database hstestdb");
diff --git a/plugin/handler_socket/docs-en/about-handlersocket.en.txt b/plugin/handler_socket/docs-en/about-handlersocket.en.txt
index 0a13a2713d6..73b9cab556b 100644
--- a/plugin/handler_socket/docs-en/about-handlersocket.en.txt
+++ b/plugin/handler_socket/docs-en/about-handlersocket.en.txt
@@ -66,7 +66,7 @@ Here is a list of other language bindings:
https://github.com/koichik/node-handlersocket
The home of HandlerSocket is here:
- https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
+ https://github.com/DeNADev/HandlerSocket-Plugin-for-MySQL
More documents are available in docs-en/ and docs-ja/ directories.
diff --git a/plugin/handler_socket/docs-en/installation.en.txt b/plugin/handler_socket/docs-en/installation.en.txt
index 8e680ed35f1..0a0616fa5c8 100644
--- a/plugin/handler_socket/docs-en/installation.en.txt
+++ b/plugin/handler_socket/docs-en/installation.en.txt
@@ -17,10 +17,11 @@ crash, etc).
$ ./autogen.sh
$ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin
- --with-mysql-source refers to the top of MySQL source directory,
---with-mysql-bindir refers to where MySQL binary executables (i.e.
-mysql_config) are located, and --with-mysql-plugindir refers to a plugin
-directory where plugin libraries (*.so) are installed.
+ --with-mysql-source refers to the top of MySQL source directory (which
+contains the VERSION file or the configure.in file), --with-mysql-bindir
+refers to where MySQL binary executables (i.e. mysql_config) are located,
+and --with-mysql-plugindir refers to a plugin directory where plugin
+libraries (*.so) are installed.
$ make
$ sudo make install
diff --git a/plugin/handler_socket/docs-en/perl-client.en.txt b/plugin/handler_socket/docs-en/perl-client.en.txt
index 2b863c638f0..cc9138518ee 100644
--- a/plugin/handler_socket/docs-en/perl-client.en.txt
+++ b/plugin/handler_socket/docs-en/perl-client.en.txt
@@ -42,7 +42,7 @@ to be retrieved are specified by the 5th argument for the
corresponding open_index call.
The execute_single method always returns an arrayref. The first
-element is the error code, which is 0 when no error is occured.
+element is the error code, which is 0 when no error is occurred.
The remaining are the field values. If more than one record is
returned, it is flatten to an 1-dimensional array. For example,
when 5 records that have 3 columns are returned, you can retrieve
@@ -93,7 +93,6 @@ The execute_single method can be used for inserting records also.
my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]);
die $hs->get_error() if $res->[0] != 0;
- my $num_inserted_rows = $res->[1];
The 3rd argument must be an arrayref whose elements correspond to
the 5th argument for the corresponding open_index call. If there
@@ -117,9 +116,18 @@ executing them separatedly.
}
-----------------------------------------------------------------
-When an error is occured, the first element of the returned
+If handlersocket is configured to authenticate client connections
+(ie., handlersocket_plain_secret or handlersocket_plain_secret_wr
+is set), a client must call 'auth' method before any other
+methods.
+
+ my $res = $hs->auth('password');
+ die $hs->get_error() if $res->[0] != 0;
+
+-----------------------------------------------------------------
+When an error is occurred, the first element of the returned
arrayref becomes a non-zero value. A negative value indicates
-that an I/O error is occured and the Net::HandlerSocket object
+that an I/O error is occurred and the Net::HandlerSocket object
should be disposed. A positive value means that the connection is
still active and the Net::HandlerSocket object can be reused
later.
diff --git a/plugin/handler_socket/docs-en/protocol.en.txt b/plugin/handler_socket/docs-en/protocol.en.txt
index afde231df7d..e36f17444ae 100644
--- a/plugin/handler_socket/docs-en/protocol.en.txt
+++ b/plugin/handler_socket/docs-en/protocol.en.txt
@@ -29,7 +29,7 @@ Request and Response
lines) at one time, and receive responses for them at one time.
----------------------------------------------------------------------------
-'open_index' request
+Opening index
The 'open_index' request has the following syntax.
@@ -74,23 +74,21 @@ FILETER is a sequence of the following parameters.
HandlerSocket supports '=', '>', '>=', '<', and '<='.
- <vlen> indicates the length of the trailing parameters <v1> ... <vn>. This
must be smaller than or equal to the number of index columns specified by
- the <columns> parameter of the corresponding 'open_index' request.
+ the <indexname> parameter of the corresponding 'open_index' request.
- <v1> ... <vn> specify the index column values to fetch.
- LIM is optional. <limit> and <offset> are numbers. When omitted, it works
as if 1 and 0 are specified. These parameter works like LIMIT of SQL.
These values don't include the number of records skipped by a filter.
- IN is optional. It works like WHERE ... IN syntax of SQL. <icol> must be
- smaller than or equal to the number of index columns specified by the
- <columns> parameter of the corresponding 'open_index' request. If IN is
- specified in a find request, the <icol>-th parameter value of <v1> ...
- <vn> is ignored.
- smaller than or equal to the number of index columns specified by the
+ smaller than the number of index columns specified by the <indexname>
+ parameter of the corresponding 'open_index' request. If IN is specified in
+ a find request, the <icol>-th parameter value of <v1> ... <vn> is ignored.
- FILTERs are optional. A FILTER specifies a filter. <ftyp> is either 'F'
(filter) or 'W' (while). <fop> specifies the comparison operation to use.
- <fcol> must be smaller than or equal to the number of columns specified by
- the <fcolumns> parameter of the corresponding 'open_index' request.
- Multiple filters can be specified, and work as the logical AND of them.
- The difference of 'F' and 'W' is that, when a record does not meet the
+ <fcol> must be smaller than the number of columns specified by the
+ <fcolumns> parameter of the corresponding 'open_index' request. Multiple
+ filters can be specified, and work as the logical AND of them. The
+ difference of 'F' and 'W' is that, when a record does not meet the
specified condition, 'F' simply skips the record, and 'W' stops the loop.
----------------------------------------------------------------------------
@@ -112,8 +110,8 @@ MOD is a sequence of the following parameters.
<mk> must be smaller than or equal to the length of <columns> specified by
the corresponding 'open_index' request. If <mop> is 'D', these parameters
are ignored. If <mop> is '+' or '-', values must be numeric. If <mop> is
- '-' and it attempts to change column values from negative to positive or
- positive to negative, it is not modified.
+ '-' and it attempts to change a column value from negative to positive or
+ positive to negative, the column value is not modified.
----------------------------------------------------------------------------
Inserting data
@@ -187,6 +185,8 @@ syntax.
0 1 <nummod>
- <nummod> is the number of modified rows.
+- As an exception, if the '?' suffix is specified in <mop>, a response has
+ the syntax of a response for 'find' instead.
----------------------------------------------------------------------------
Response for 'insert'
@@ -196,3 +196,10 @@ syntax.
0 1
+----------------------------------------------------------------------------
+Response for 'auth'
+
+If 'auth' is succeeded, HanderSocket returns a line of the following syntax.
+
+ 0 1
+
diff --git a/plugin/handler_socket/docs-ja/installation.ja.txt b/plugin/handler_socket/docs-ja/installation.ja.txt
index c14f47f6c02..0e8f3513712 100644
--- a/plugin/handler_socket/docs-ja/installation.ja.txt
+++ b/plugin/handler_socket/docs-ja/installation.ja.txt
@@ -8,7 +8,8 @@ HandlerSocketプラグインã®ãƒ“ルド方法(RPMを使ã‚ãªã„方法)
$ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin
ã“ã“ã§--with-mysql-sourceã«ã¯MySQLã®ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã®ãƒˆãƒƒãƒ—ディレク
-トリを指定ã—ã¾ã™ã€‚--with-mysql-bindirã«ã¯ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«æ¸ˆã¿ã®MySQL
+トリを指定ã—ã¾ã™(ãã“ã«VERSIONファイルã‹configure.inファイルãŒãªã
+ã¦ã¯ãªã‚Šã¾ã›ã‚“)。--with-mysql-bindirã«ã¯ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«æ¸ˆã¿ã®MySQL
ã®mysql_configコマンドãŒæœ‰ã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’指定ã—ã¾ã™ã€‚
ãã®å¾Œä»¥ä¸‹ã®ã‚ˆã†ã«ãƒ“ルド・インストールã—ã¾ã™ã€‚
diff --git a/plugin/handler_socket/docs-ja/perl-client.ja.txt b/plugin/handler_socket/docs-ja/perl-client.ja.txt
index 5d3adfa3301..90b7e4d6fd8 100644
--- a/plugin/handler_socket/docs-ja/perl-client.ja.txt
+++ b/plugin/handler_socket/docs-ja/perl-client.ja.txt
@@ -86,7 +86,6 @@ execute_singleメソッドã¯åˆ—ã®æŒ¿å…¥ã«ã‚‚使用ã§ãã¾ã™ã€‚
my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]);
die $hs->get_error() if $res->[0] != 0;
- my $num_inserted_rows = $res->[1];
第3引数ã¯ã€å¯¾å¿œã™ã‚‹open_index呼ã³å‡ºã—ã®ç¬¬5引数ã®åˆ—リストã¨åŒã˜ã 
ã‘ã®é•·ã•ã®é…列ã¸ã®å‚ç…§ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。open_index呼ã³å‡ºã—ã®
@@ -110,6 +109,15 @@ execute_multiメソッドを使ãˆã°ã€è¤‡æ•°ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’一ã¤ã®å‘¼ã
}
-----------------------------------------------------------------
+ã‚‚ã—handlersocketãŒæŽ¥ç¶šã‚’èªè¨¼ã™ã‚‹ã‚ˆã†ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹
+(handlersocket_plain_secretåˆã¯handlersocket_plain_secret_wrãŒã‚»ãƒƒ
+トã•ã‚Œã¦ã„ã‚‹)ãªã‚‰ã°ã€ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã¯ä»–ã®ãƒ¡ã‚½ãƒƒãƒ‰å‘¼ã³å‡ºã—ã®å‰ã«auth
+メソッドを呼ã³å‡ºã™å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚
+
+ my $res = $hs->auth('password');
+ die $hs->get_error() if $res->[0] != 0;
+
+-----------------------------------------------------------------
エラーãŒèµ·ã“ã‚‹ã¨è¿”値ã®é…列å‚ç…§ã®æœ€åˆã®è¦ç´ ãŒ0以外ã«ãªã‚Šã¾ã™ã€‚è² ã®
æ•°ã®å ´åˆã¯I/OエラーãŒèµ·ã“ã£ãŸã“ã¨ã‚’示ã—ã€ãã®å ´åˆã¯ãã®
Net::HandlerSocketオブジェクトã¯ç ´æ£„ã™ã‚‹ã¹ãã§ã™ã€‚æ­£ã®å€¤ã®å ´åˆã¯
diff --git a/plugin/handler_socket/docs-ja/protocol.ja.txt b/plugin/handler_socket/docs-ja/protocol.ja.txt
index 01c9d39f71f..46cc9932e60 100644
--- a/plugin/handler_socket/docs-ja/protocol.ja.txt
+++ b/plugin/handler_socket/docs-ja/protocol.ja.txt
@@ -1,94 +1,180 @@
------------------------------------------------------------------
+----------------------------------------------------------------------------
handlersocketã®é€šä¿¡ãƒ—ロトコル
------------------------------------------------------------------
-構文
+----------------------------------------------------------------------------
+基本的ãªæ§‹æ–‡
-・コマンド行ã¯æ”¹è¡Œ(LF)ã§çµ‚ã‚る。
-・コマンド行ã¯è¤‡æ•°ã®ãƒˆãƒ¼ã‚¯ãƒ³ã‹ã‚‰ãªã‚Šã€ãƒˆãƒ¼ã‚¯ãƒ³é–“ã¯TABã§åŒºåˆ‡ã‚‰ã‚Œã‚‹ã€‚
+・HandlerSocketã®ãƒ—ロトコルã¯è¡Œãƒ™ãƒ¼ã‚¹ã€‚å„è¡Œã¯æ”¹è¡Œæ–‡å­—(0x0a)ã§çµ‚ã‚る。
+・å„è¡Œã¯è¤‡æ•°ã®ãƒˆãƒ¼ã‚¯ãƒ³ã‹ã‚‰ãªã‚Šã€ãƒˆãƒ¼ã‚¯ãƒ³é–“ã¯TAB文字(0x09)ã§åŒºåˆ‡ã‚‰ã‚Œã‚‹ã€‚
・トークンã¯NULLトークンã‹ã€æ–‡å­—列トークンã®ã„ãšã‚Œã‹ã€‚
-・NULLトークンã¯å˜ä¸€ã®NUL文字ã§ã‚らã‚ã•ã‚Œã‚‹ã€‚
-・文字列トークンã¯ã€0ãƒã‚¤ãƒˆä»¥ä¸Šã®æ–‡å­—列ã§ã‚らã‚ã•ã‚Œã‚‹ã€‚ãŸã ã—0x10
- 未満ã®æ–‡å­—ã«ã¤ã„ã¦ã¯0x01ã‚’å‰ç½®ã—ã€0x40を加ãˆãŸã‚³ãƒ¼ãƒ‰ã§ã‚らã‚ã•
- れる。ãれ以外ã®æ–‡å­—ã¯ãã®æ–‡å­—自身ã®ã‚³ãƒ¼ãƒ‰ã§ã‚らã‚ã•ã‚Œã‚‹ã€‚
+・NULLトークンã¯å˜ä¸€ã®NUL文字(0x00)ã§ã‚らã‚ã•ã‚Œã‚‹ã€‚
+・文字列トークンã¯ã€0ãƒã‚¤ãƒˆä»¥ä¸Šã®æ–‡å­—列ã§ã‚らã‚ã•ã‚Œã‚‹ã€‚ãŸã ã—0x10未満ã®æ–‡å­—
+ ã«ã¤ã„ã¦ã¯0x01ã‚’å‰ç½®ã—ã€0x40を加ãˆãŸã‚³ãƒ¼ãƒ‰ã§ã‚らã‚ã•ã‚Œã‚‹ã€‚ãれ以外ã®æ–‡å­—ã¯
+ ãã®æ–‡å­—自身ã®ã‚³ãƒ¼ãƒ‰ã§ã‚らã‚ã•ã‚Œã‚‹ã€‚
------------------------------------------------------------------
+----------------------------------------------------------------------------
リクエストã¨ãƒ¬ã‚¹ãƒãƒ³ã‚¹
-・接続ãŒç¢ºç«‹ã—ãŸç›´å¾Œã®çŠ¶æ…‹ã§ã¯ã€ã¾ãšã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãŒã‚³ãƒžãƒ³ãƒ‰è¡Œã‚’é€
- る。(リクエスト)
-・サーãƒã¯ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãŒé€ã£ãŸãƒªã‚¯ã‚¨ã‚¹ãƒˆã¨ä¸åº¦åŒã˜æ•°ã®ã‚³ãƒžãƒ³ãƒ‰è¡Œ
- ã‚’è¿”ã™ã€‚(レスãƒãƒ³ã‚¹)
-・リクエストã¯ãƒ‘イプライン化ã—ã¦ã‚ˆã„。ã¤ã¾ã‚Šã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã¯å‰ã«
- é€ã£ãŸãƒªã‚¯ã‚¨ã‚¹ãƒˆã«å¯¾ã™ã‚‹è¿”事を待ãŸãšã«æ¬¡ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’é€ã£ã¦ã‚‚
- よã„。
-
------------------------------------------------------------------
-リクエスト
-
-・open_index命令ã¯æ¬¡ã®ã‚ˆã†ãªæ§‹æ–‡ã‚’æŒã¤ã€‚
- 'P' indexid dbname tablename indexname fieldlist
- indexidã¯é–‹ã„ã¦ã„る索引ã«ä»˜ã‘られる番å·ã§ã€åŒä¸€æŽ¥ç¶šä¸Šã§å¾Œã«å®Ÿè¡Œ
- ã™ã‚‹å‘½ä»¤ã®ã€å¯¾è±¡ç´¢å¼•ã‚’指定ã™ã‚‹ãŸã‚ã«ä½¿ã‚れる。dbnameã€tablenameã€
- indexnameã¯ãã‚Œãžã‚Œé–‹ããŸã„DBã€ãƒ†ãƒ¼ãƒ–ルã€ç´¢å¼•ã®åå‰ã€‚索引ã®åå‰
- ã¨ã—ã¦"PRIMARY"を指定ã™ã‚‹ã¨ãƒ—ライマリキーãŒé–‹ã‹ã‚Œã‚‹ã€‚fieldlist
- ã¯ã‚«ãƒ³ãƒžåŒºåˆ‡ã‚Šã®åˆ—åã®ãƒªã‚¹ãƒˆã€‚
-・find命令ã¯æ¬¡ã®ã‚ˆã†ãªæ§‹æ–‡ã‚’æŒã¤ã€‚
- indexid op nflds v1 ... vn limit offset
- indexidã¯å®Ÿè¡Œå¯¾è±¡ã®ç´¢å¼•ã‚’指定ã™ã‚‹ã€‚opã¯ç´¢å¼•æ¤œç´¢ã®æ¼”ç®—å­(後述)。
- v1ã‹ã‚‰vnã¯å¯å¤‰é•·ã§ã€ãã®å€‹æ•°ã¯nflds。nfldsã¯indexidã§æŒ‡å®šã•ã‚ŒãŸ
- open_index命令ã®indexnameã®ç´¢å¼•ã®fieldlistã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰æ•°ã«ç­‰ã—
- ã„ã‹å°ã•ããªãã¦ã¯ãªã‚‰ãªã„。m2ã‹ã‚‰mkã¯å¯å¤‰é•·ã§ã€ãã®å€‹æ•°ã¯
- indexidã§æŒ‡å®šã•ã‚ŒãŸopen_index命令ãŒç™ºè¡Œã•ã‚ŒãŸéš›ã®fieldlistã«ä¸€
- 致ã—ãªã‘ã‚Œã°ãªã‚‰ãªã„。コマンド行ã®limit以é™ã¯çœç•¥ã§ãる。limit
- ã¨offsetã¯ã€æ¤œç´¢æ¡ä»¶ã«åˆè‡´ã™ã‚‹åˆ—ã®ã†ã¡ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã«è¿”ã™åˆ—æ•°ã®ä¸Š
- é™ã¨ã€ã‚¹ã‚­ãƒƒãƒ—ã™ã‚‹åˆ—数。limitã¨offsetã‚’çœç•¥ã—ãŸå ´åˆã¯ãã‚Œãžã‚Œ1
- ã¨0ãŒæŒ‡å®šã•ã‚ŒãŸã¨ãã¨åŒã˜å‹•ä½œã‚’ã™ã‚‹ã€‚find命令ã¯ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¨ã—ã¦ã€
- æ¡ä»¶ã«åˆè‡´ã—ãŸåˆ—ã®ãƒªã‚¹ãƒˆã‚’è¿”ã™ã€‚opã¨ã—ã¦æŒ‡å®šã§ãる演算å­ã¯æ¬¡ã®
- ã¨ãŠã‚Šã€‚
- '=' - v1 ... vnã¨ä¸€è‡´ã™ã‚‹ã‚‚ã®ã‚’å–å¾—
- '>' - v1 ... vnより大ãã„ã‚‚ã®ã‚’昇順ã«å–å¾—
- '>=' - v1 ... vnã«ä¸€è‡´ã™ã‚‹ã‹å¤§ãã„ã‚‚ã®ã‚’昇順ã«å–å¾—
- '<' - v1 ... vnよりå°ã•ã„ã‚‚ã®ã‚’é™é †ã«å–å¾—
- '<=' - v1 ... vnã«ä¸€è‡´ã™ã‚‹ã‹ç­‰ã—ã„ã‚‚ã®ã‚’é™é †ã«å–å¾—
- nfldsãŒ1より大ãã„(v1 ... vnãŒ2個以上)ã¨ãã¯è¾žæ›¸å¼é †åºã§æ¯”較ã•
- れる。
-・find_modify命令ã¯æ¬¡ã®ã‚ˆã†ãªæ§‹æ–‡ã‚’æŒã¤ã€‚
- indexid op nflds v1 ... vn limit offset modop m1 ... mk
- modopよりå‰ã®éƒ¨åˆ†ã¯find命令ã¨åŒç­‰ã§ã€ã“ã‚Œã«ã‚ˆã£ã¦æ“作対象ã®è¡Œã‚’
- 指定ã™ã‚‹ã€‚ãã®æ“作対象ã®è¡Œã«å¯¾ã—modopã§æŒ‡å®šã•ã‚ŒãŸå¤‰æ›´å‡¦ç†ã‚’実行
- ã™ã‚‹ã€‚m1 ... mkã¯å¯å¤‰é•·ã§ã€çœç•¥ã§ãる。modopã¯æ¬¡ã„ãšã‚Œã‹ã€‚
- 'U' - indexidã§æŒ‡å®šã•ã‚ŒãŸopen_index命令ã®fieldlist列
- ã®å†…容をã€m1 ... mkã®å€¤ã§æ›´æ–°ã™ã‚‹ã€‚
- 'D' - 対象ã®è¡Œã‚’削除ã™ã‚‹ã€‚m1 ... mkã®å€¤ã¯ç„¡è¦–ã•ã‚Œã‚‹ã€‚
-・insert命令ã¯ã®ã‚ˆã†ãªæ§‹æ–‡ã‚’æŒã¤ã€‚
- indexid '+' nflds v1 ... vn
- indexidã§æŒ‡å®šã•ã‚ŒãŸãƒ†ãƒ¼ãƒ–ルã«ã€åˆ—を挿入ã™ã‚‹ã€‚v1 ... vnã¯å¯å¤‰é•·
- ã§ã€ãã®å€‹æ•°ã¯nflds。nfldsã¯indexidã§æŒ‡å®šã•ã‚ŒãŸopen_index命令ã®
- indexnameã®ç´¢å¼•ã®fieldlistã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰æ•°ã«ç­‰ã—ã„ã‹å°ã•ããªãã¦
- ã¯ãªã‚‰ãªã„。
-
------------------------------------------------------------------
-レスãƒãƒ³ã‚¹
-
-・open_index命令ãŒæˆåŠŸã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯æ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
- '0' '1'
-・find命令ãŒæˆåŠŸã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯æ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
- '0' nflds v1 ... vn
- nfldsã¯çµæžœã‚»ãƒƒãƒˆã®åˆ—ã®æ•°ã‚’ã‚らã‚ã™ã€‚v1 ... vnã¯å¯å¤‰é•·ã§ã€ãã®
- é•·ã•ã¯nfldsã®æ•´æ•°å€ã€‚v1 ... vnã¯ç©ºã®ã“ã¨ã‚‚ã‚ã‚Šã€ãã‚Œã¯æ¡ä»¶ã«åˆ
- 致ã™ã‚‹ãƒ¬ã‚³ãƒ¼ãƒ‰ãŒå­˜åœ¨ã—ãªã‹ã£ãŸã“ã¨ã‚’ã‚らã‚ã™ã€‚çµæžœã‚»ãƒƒãƒˆãŒè¤‡æ•°
- è¡Œã«ãªã£ãŸã¨ãã¯v1 ... vnã®é•·ã•ãŒnfldsã®2å€ä»¥ä¸Šã¨ãªã‚Šã€æœ€åˆã®
- è¡Œã‹ã‚‰é †ã«v1 ... vnã«ã‚»ãƒƒãƒˆã•ã‚Œã‚‹ã€‚
-・modify命令ãŒæˆåŠŸã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯æ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
- '0' '1' nummod
- nummodã¯å¤‰æ›´ãŒæ–½ã•ã‚ŒãŸè¡Œæ•°ã€‚nummodãŒ0ã®ã¨ãã¯å¤‰æ›´ã•ã‚ŒãŸè¡ŒãŒç„¡
- ã‹ã£ãŸã“ã¨ã‚’ã‚らã‚ã™ã€‚
-・insert命令ãŒæˆåŠŸã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯æ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
- '0' '1'
-・命令ãŒå¤±æ•—ã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯å‘½ä»¤ã«é–¢ã‚らãšæ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
- err '1' message
- errã¯0以外ã®æ•°å€¤ã§ã€ã‚¨ãƒ©ãƒ¼ã‚³ãƒ¼ãƒ‰ã‚’ã‚らã‚ã™ã€‚messageã¯äººé–“å¯èª­ãª
- エラーメッセージ。ãŸã ã—messageãŒç„¡ã„ã“ã¨ã‚‚ã‚る。
+・HandlerSocketã®ãƒ—ロトコルã¯å˜ç´”ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆãƒ»ãƒ¬ã‚¹ãƒãƒ³ã‚¹ãƒ—ロトコルã«ãªã£ã¦
+ ã„る。接続ãŒç¢ºç«‹ã—ãŸå¾Œã¯ã€ã¾ãšã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãŒãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’é€ã‚‹ã€‚
+・サーãƒã¯ã€ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãŒé€ã£ãŸãƒªã‚¯ã‚¨ã‚¹ãƒˆã¨ä¸åº¦åŒã˜æ•°ã®è¡Œ(レスãƒãƒ³ã‚¹)ã‚’è¿”
+ ã™ã€‚
+・リクエストã¯ãƒ‘イプライン化ã—ã¦ã‚ˆã„。ã¤ã¾ã‚Šã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã¯å‰ã«é€ã£ãŸãƒªã‚¯ã‚¨ã‚¹
+ トã«å¯¾ã™ã‚‹è¿”事(レスãƒãƒ³ã‚¹)ã‚’å¾…ãŸãšã«æ¬¡ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’é€ã£ã¦ã‚‚よã„。
+
+----------------------------------------------------------------------------
+インデックスを開ã
+
+open_index命令ã¯æ¬¡ã®ã‚ˆã†ãªæ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ P <indexid> <dbname> <tablename> <indexname> <columns> [<fcolumns>]
+
+- <indexid>ã¯æ•°å­—ã§ã€åŒä¸€æŽ¥ç¶šä¸Šã§å¾Œã«å®Ÿè¡Œã™ã‚‹å‘½ä»¤ã®ã€å¯¾è±¡ç´¢å¼•ã‚’指定ã™ã‚‹ãŸã‚
+ ã«ä½¿ã‚れる。
+- <dbname>, <tablename>, <indexname>ã¯æ–‡å­—列ã§ã€ãã‚Œãžã‚ŒDBåã€ãƒ†ãƒ¼ãƒ–ルåã€
+ 索引ã®åå‰ã‚’指定ã™ã‚‹ã€‚<indexname>ã¨ã—ã¦ã€ŒPRIMARYã€ã‚’指定ã™ã‚‹ã¨ãƒ—ライマリ
+ キーãŒé–‹ã‹ã‚Œã‚‹ã€‚
+- <columns>ã¯ã‚«ãƒ³ãƒžåŒºåˆ‡ã‚Šã®åˆ—åã®ãƒªã‚¹ãƒˆã€‚
+- <fcolumns>ã¯ã‚«ãƒ³ãƒžåŒºåˆ‡ã‚Šã®åˆ—åã®ãƒªã‚¹ãƒˆã€‚ã“ã‚Œã¯çœç•¥ã™ã‚‹ã“ã¨ãŒã§ãる。
+
+ã“ã®open_index命令ãŒå®Ÿè¡Œã•ã‚Œã‚‹ã¨ã€HandlerSocketプラグインã¯æŒ‡å®šã•ã‚ŒãŸDBã€
+テーブルã€ç´¢å¼•ã‚’é–‹ã。開ã‹ã‚ŒãŸç´¢å¼•ã¯æŽ¥ç¶šãŒé–‰ã˜ã‚‰ã‚Œã‚‹ã¾ã§é–‹ã‹ã‚ŒãŸã¾ã¾ã«ãªã‚‹ã€‚
+é–‹ã‹ã‚ŒãŸç´¢å¼•ã¯<indexid>ã®æ•°å­—ã§è­˜åˆ¥ã•ã‚Œã‚‹ã€‚ã‚‚ã—æ—¢ã«<indexid>ã«æŒ‡å®šã•ã‚ŒãŸç•ªå·
+ã®ç´¢å¼•ãŒæ—¢ã«é–‹ã‹ã‚Œã¦ã„ã‚‹å ´åˆã¯å¤ã„ã»ã†ãŒé–‰ã˜ã‚‰ã‚Œã‚‹ã€‚ã“ã®<indexid>ã¯ãªã‚‹ã¹ã
+å°ã•ãªæ•°å­—を使ã£ãŸã»ã†ãŒåŠ¹çŽ‡ãŒè‰¯ã„。
+
+----------------------------------------------------------------------------
+データå–å¾—
+
+find命令ã¯æ¬¡ã®ã‚ˆã†ãªæ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ <indexid> <op> <vlen> <v1> ... <vn> [LIM] [IN] [FILTER ...]
+
+LIMã¯æ¬¡ã®ã‚ˆã†ãªãƒ‘ラメータã®ä¸¦ã³
+
+ <limit> <offset>
+
+INã¯æ¬¡ã®ã‚ˆã†ãªãƒ‘ラメータã®ä¸¦ã³
+
+ @ <icol> <ivlen> <iv1> ... <ivn>
+
+FILTERã¯æ¬¡ã®ã‚ˆã†ãªãƒ‘ラメータã®ä¸¦ã³
+
+ <ftyp> <fop> <fcol> <fval>
+
+- <indexid>ã¯æ•°å­—ã§ã€ã“ã‚Œã¯åŒã˜æŽ¥ç¶šä¸Šã§éŽåŽ»ã«å®Ÿè¡Œã—ãŸopen_index命令ã«æŒ‡å®šã•
+ ã‚ŒãŸæ•°å­—ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„。
+- <op>ã¯æ¯”較演算å­ã§ã€ç¾åœ¨ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯ '=', '>', '>=', '<', '<=' をサ
+ ãƒãƒ¼ãƒˆã—ã¦ã„る。
+- <vlen>ã¯å¾Œã«ç¶šãパラメータ<v1> ... <vn>ã®é•·ã•ã€‚ã“ã®å€¤ã¯å¯¾å¿œã™ã‚‹open_index
+ 命令ã®<indexname>パラメータã§æŒ‡å®šã•ã‚ŒãŸç´¢å¼•ã®ã‚­ãƒ¼åˆ—ã®æ•°ã¨åŒã˜ã‹å°ã•ã„ã‚‚ã®
+ ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„。
+- <v1> ... <vn>ã¯å–å¾—ã™ã‚‹ã¹ãキーã®å€¤ã‚’指定ã™ã‚‹ãƒ‘ラメータ。
+- LIMã¯çœç•¥ã§ãる。<limit>ã¨<offset>ã¯æ•°å­—ã§ã€ã“ã‚Œã¯SQLã®LIMITã¨åŒã˜ã‚ˆã†ã«
+ ã¯ãŸã‚‰ã。çœç•¥ã—ãŸå ´åˆã¯1ã¨0を指定ã—ãŸå ´åˆã¨åŒã˜å‹•ä½œã‚’ã™ã‚‹ã€‚FILTERã«ã‚ˆã£
+ ã¦èª­ã¿é£›ã°ã•ã‚ŒãŸãƒ¬ã‚³ãƒ¼ãƒ‰ã¯<limit>ã¨<offset>ã«ã‚«ã‚¦ãƒ³ãƒˆã•ã‚Œãªã„。
+- INã¯çœç•¥ã§ãる。指定ã•ã‚Œã‚‹ã¨ã€ã“ã‚Œã¯SQLã® WHERE ... IN ã®ã‚ˆã†ã«å‹•ä½œã™ã‚‹ã€‚
+ <icol>ã¯å¯¾å¿œã™ã‚‹open_index命令ã®<indexname>パラメータã§æŒ‡å®šã•ã‚ŒãŸç´¢å¼•ã®
+ キー列ã®æ•°ã‚ˆã‚Šå°ã•ã„ã‚‚ã®ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„。INãŒæŒ‡å®šã•ã‚ŒãŸã¨ãã¯ã€find命
+ 令ã®<v1> ... <vn>ã®ã†ã¡<icol>番目ã®å€¤ã¯ç„¡è¦–ã•ã‚Œã‚‹ã€‚
+- FILTERã¯çœç•¥ã§ãる。ã“ã‚Œã¯è¡Œå–å¾—ã®éš›ã®ãƒ•ã‚£ãƒ«ã‚¿ã‚’指定ã™ã‚‹ã€‚<ftyp>ã¯
+ 'F'(filter)ã‹'W'(while)ã®ã„ãšã‚Œã‹ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„。<fop>ã¯æ¯”較演算å­ã€‚
+ <fcol>ã¯æ•°å­—ã§ã€ã“ã‚Œã¯å¯¾å¿œã™ã‚‹open_index命令ã®<fcolumns>ã§æŒ‡å®šã•ã‚ŒãŸåˆ—ã®
+ 数よりå°ã•ã„ã‚‚ã®ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„。複数ã®ãƒ•ã‚£ãƒ«ã‚¿ã‚’指定ã™ã‚‹ã“ã¨ã‚‚ã§ãã€
+ ãã®å ´åˆã¯å„フィルタã®ANDã¨è§£é‡ˆã•ã‚Œã‚‹ã€‚'F'ã¨'W'ã®é•ã„ã¯ã€æ¡ä»¶ã«ã‚ã¦ã¯ã¾
+ らãªã„è¡ŒãŒã‚ã£ãŸã¨ãã«'F'ã¯å˜ã«ãれをスキップã™ã‚‹ãŒã€'W'ã¯ãã®æ™‚点ã§ãƒ«ãƒ¼
+ プを抜ã‘ã‚‹ã¨ã„ã†ç‚¹ã€‚
+
+----------------------------------------------------------------------------
+æ›´æ–°ã¨å‰Šé™¤
+
+find_modify命令ã¯æ¬¡ã®ã‚ˆã†ãªæ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ <indexid> <op> <vlen> <v1> ... <vn> [LIM] [IN] [FILTER ...] MOD
+
+MODã¯æ¬¡ã®ã‚ˆã†ãªãƒ‘ラメータã®ä¸¦ã³
+
+ <mop> <m1> ... <mk>
+
+- <mop>ã¯'U', '+', '-', 'D', 'U?', '+?', '-?', 'D?'ã®ã„ãšã‚Œã‹ã€‚'?'ãŒä»˜ã„ãŸ
+ ã‚‚ã®ã¯ä»˜ã„ã¦ã„ãªã„ã‚‚ã®ã¨ã»ã¼åŒã˜å‹•ä½œã‚’ã™ã‚‹ãŒã€ä»˜ã„ã¦ã„ãªã„ã‚‚ã®ãŒãƒ¬ã‚¹ãƒãƒ³
+ スã¨ã—ã¦æ›´æ–°ã•ã‚ŒãŸè¡Œã®æ•°ã‚’è¿”ã™ã®ã«å¯¾ã—ã€ä»˜ã„ã¦ã„ã‚‹ã‚‚ã®ã¯æ›´æ–°ã•ã‚Œã‚‹å‰ã®è¡Œ
+ ã®å†…容を返ã™ç‚¹ã®ã¿ãŒç•°ãªã‚‹ã€‚'U'ã¯æ›´æ–°ã€'D'ã¯å‰Šé™¤ã€'+'ã¯ã‚¤ãƒ³ã‚¯ãƒªãƒ¡ãƒ³ãƒˆã€
+ '-'ã¯ãƒ‡ã‚¯ãƒªãƒ¡ãƒ³ãƒˆã‚’実行ã™ã‚‹ã€‚
+- <m1> ... <mk>ã¯ã‚»ãƒƒãƒˆã•ã‚Œã‚‹å„列ã®å€¤ã€‚<m1> ... <mk>ã®é•·ã•ã¯å¯¾å¿œã™ã‚‹
+ open_index命令ã®<columns>ã®é•·ã•ã¨ç­‰ã—ã„ã‹å°ã•ããªã‘ã‚Œã°ãªã‚‰ãªã„。<mop>ãŒ
+ 'D'ã®ã¨ãã¯ã“れらã®ãƒ‘ラメータã¯ç„¡è¦–ã•ã‚Œã‚‹ã€‚<mop>ãŒ'+'ã‹'-'ã®ã¨ãã¯ã€ã“れら
+ ã®å€¤ã¯æ•°å€¤ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„。<mop>ãŒ'-'ã§ã€ãã‚ŒãŒè² æ•°ã‹ã‚‰æ­£æ•°ã€ã¾ãŸã¯æ­£æ•°
+ ã‹ã‚‰è² æ•°ã¸åˆ—ã®å€¤ã‚’変更ã™ã‚‹ã‚ˆã†ãªã‚‚ã®ã§ã‚ã£ãŸå ´åˆã¯ã€å€¤ã¯å¤‰æ›´ã•ã‚Œãªã„。
+
+----------------------------------------------------------------------------
+è¡Œã®æŒ¿å…¥
+
+insert命令ã¯æ¬¡ã®ã‚ˆã†ãªæ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ <indexid> + <vlen> <v1> ... <vn>
+
+- <vlen>ã¯å¾Œã«ç¶šãパラメータ<v1> ... <vn>ã®é•·ã•ã€‚ã“ã‚Œã¯å¯¾å¿œã™ã‚‹open_indexã®
+ <columns>ã®é•·ã•ã«ç­‰ã—ã„ã‹å°ã•ããªã‘ã‚Œã°ãªã‚‰ãªã„。
+- <v1> ... <vn>ã¯ã‚»ãƒƒãƒˆã•ã‚Œã‚‹å„列ã®å€¤ã€‚指定ã•ã‚Œãªã„ã‹ã£ãŸåˆ—ã«ã¤ã„ã¦ã¯ãã®åˆ—
+ ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ãŒã‚»ãƒƒãƒˆã•ã‚Œã‚‹ã€‚
+
+----------------------------------------------------------------------------
+èªè¨¼
+
+auth命令ã¯æ¬¡ã®ã‚ˆã†ãªæ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ A <atyp> <akey>
+
+- <atyp>ã¯ç¾åœ¨ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯'1'ã®ã¿ãŒæœ‰åŠ¹ã€‚
+- 指定ã•ã‚ŒãŸ<akey>ãŒã€ã‚µãƒ¼ãƒã®è¨­å®šã®'handlersocket_plain_secret'ã‚„
+ 'handlersocket_plain_secret_wr'ã«æŒ‡å®šã•ã‚ŒãŸæ–‡å­—列ã¨ä¸€è‡´ã—ãŸå ´åˆã«ã®ã¿èªè¨¼
+ ã¯æˆåŠŸã™ã‚‹ã€‚
+- HandlerSocketã®èªè¨¼ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã‚‹ã¨ãã¯ã€ã“ã®'auth'ãŒæˆåŠŸã—ãªã„é™ã‚Šã
+ れ以外ã®å‘½ä»¤ã¯å…¨ã¦å¤±æ•—ã™ã‚‹ã€‚
+
+----------------------------------------------------------------------------
+open_indexã«å¯¾ã™ã‚‹ãƒ¬ã‚¹ãƒãƒ³ã‚¹
+
+open_index命令ãŒæˆåŠŸã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯æ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ 0 1
+
+----------------------------------------------------------------------------
+findã«å¯¾ã™ã‚‹ãƒ¬ã‚¹ãƒãƒ³ã‚¹
+
+find命令ãŒæˆåŠŸã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯æ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ 0 <numcolumns> <r1> ... <rn>
+
+- <numcolumns>ã¯find命令ã®å¯¾å¿œã™ã‚‹open_index命令ã«æŒ‡å®šã—ãŸ<columns>ã®é•·ã•ã«
+ 一致ã™ã‚‹ã€‚
+- <r1> ... <rn>ã¯çµæžœã‚»ãƒƒãƒˆã€‚ã‚‚ã—Nè¡ŒãŒfind命令ã§è¦‹ã¤ã‹ã£ãŸãªã‚‰ã€<r1> ...
+ <rn>ã®é•·ã•ã¯ ( <numcolumns> * N )ã«ãªã‚‹ã€‚
+
+----------------------------------------------------------------------------
+find_modifyã«å¯¾ã™ã‚‹ãƒ¬ã‚¹ãƒãƒ³ã‚¹
+
+find_modify命令ãŒæˆåŠŸã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯æ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ 0 1 <nummod>
+
+- <nummod>ã¯å¤‰æ›´ã•ã‚ŒãŸè¡Œã®æ•°ã€‚
+- 例外ã¨ã—ã¦ã€<mop>ãŒ'?'ã®ä»˜ã„ãŸã‚‚ã®ã§ã‚ã£ãŸå ´åˆã«ã¯ã€find命令ã«å¯¾ã™ã‚‹ãƒ¬ã‚¹ãƒ
+ ンスã¨åŒã˜æ§‹æ–‡ã®ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã‚’è¿”ã™ã€‚
+
+----------------------------------------------------------------------------
+insertã«å¯¾ã™ã‚‹ãƒ¬ã‚¹ãƒãƒ³ã‚¹
+
+insert命令ãŒæˆåŠŸã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯æ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ 0 1
+
+----------------------------------------------------------------------------
+authã«å¯¾ã™ã‚‹ãƒ¬ã‚¹ãƒãƒ³ã‚¹
+
+auth命令ãŒæˆåŠŸã—ãŸã¨ãã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¯æ¬¡ã®æ§‹æ–‡ã‚’æŒã¤ã€‚
+
+ 0 1
diff --git a/plugin/handler_socket/handlersocket/database.cpp b/plugin/handler_socket/handlersocket/database.cpp
index da55113a179..b05b6384565 100644
--- a/plugin/handler_socket/handlersocket/database.cpp
+++ b/plugin/handler_socket/handlersocket/database.cpp
@@ -106,10 +106,10 @@ struct tablevec_entry {
struct expr_user_lock : private noncopyable {
expr_user_lock(THD *thd, int timeout)
- : lck_key("handlersocket_wr", 16, &my_charset_latin1),
- lck_timeout(timeout),
- lck_func_get_lock(&lck_key, &lck_timeout),
- lck_func_release_lock(&lck_key)
+ : lck_key(thd, "handlersocket_wr", 16, &my_charset_latin1),
+ lck_timeout(thd, timeout),
+ lck_func_get_lock(thd, &lck_key, &lck_timeout),
+ lck_func_release_lock(thd, &lck_key)
{
lck_key.fix_fields(thd, 0);
lck_timeout.fix_fields(thd, 0);
@@ -304,6 +304,7 @@ dbcontext::init_thread(const void *stack_bottom, volatile int& shutdown_flag)
thd->db = 0;
thd->db = my_strdup("handlersocket", MYF(0));
}
+ thd->variables.option_bits |= OPTION_TABLE_LOCK;
my_pthread_setspecific_ptr(THR_THD, thd);
DBG_THR(fprintf(stderr, "HNDSOCK x0 %p\n", thd));
}
@@ -343,7 +344,7 @@ void
dbcontext::term_thread()
{
DBG_THR(fprintf(stderr, "HNDSOCK thread end %p\n", thd));
- unlock_tables_if();
+ close_tables_if();
my_pthread_setspecific_ptr(THR_THD, 0);
{
pthread_mutex_lock(&LOCK_thread_count);
@@ -660,7 +661,7 @@ dbcontext::cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst,
empty_record(table);
memset(buf, 0, table->s->null_bytes); /* clear null flags */
const prep_stmt::fields_type& rf = pst.get_ret_fields();
- const size_t n = rf.size();
+ const size_t n = std::min(rf.size(), fvalslen);
for (size_t i = 0; i < n; ++i) {
uint32_t fn = rf[i];
Field *const fld = table->field[fn];
@@ -764,7 +765,7 @@ dbcontext::cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst,
return cb.dbcb_resp_short(2, "idxnum");
}
KEY& kinfo = table->key_info[pst.get_idxnum()];
- if (args.kvalslen > kinfo.key_parts) {
+ if (args.kvalslen > kinfo.user_defined_key_parts) {
return cb.dbcb_resp_short(2, "kpnum");
}
uchar *const key_buf = DENA_ALLOCA_ALLOCATE(uchar, kinfo.key_length);
@@ -1016,7 +1017,7 @@ dbcontext::cmd_open(dbcallback_i& cb, const cmd_open_args& arg)
tables.mdl_request.init(MDL_key::TABLE, arg.dbn, arg.tbl,
for_write_flag ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION);
Open_table_context ot_act(thd, 0);
- if (!open_table(thd, &tables, thd->mem_root, &ot_act)) {
+ if (!open_table(thd, &tables, &ot_act)) {
table = tables.table;
}
#else
diff --git a/plugin/handler_socket/libhsclient/auto_file.hpp b/plugin/handler_socket/libhsclient/auto_file.hpp
index 841351e54cd..03c357f4d4e 100644
--- a/plugin/handler_socket/libhsclient/auto_file.hpp
+++ b/plugin/handler_socket/libhsclient/auto_file.hpp
@@ -9,6 +9,11 @@
#ifndef DENA_AUTO_FILE_HPP
#define DENA_AUTO_FILE_HPP
+/* Workaround for _LARGE_FILES and _LARGE_FILE_API incompatibility on AIX */
+#if defined(_AIX) && defined(_LARGE_FILE_API)
+#undef _LARGE_FILE_API
+#endif
+
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
diff --git a/plugin/handler_socket/libhsclient/fatal.cpp b/plugin/handler_socket/libhsclient/fatal.cpp
index 5cdd8879ab1..8e109cf13ba 100644
--- a/plugin/handler_socket/libhsclient/fatal.cpp
+++ b/plugin/handler_socket/libhsclient/fatal.cpp
@@ -18,14 +18,6 @@ namespace dena {
const int opt_syslog = LOG_ERR | LOG_PID | LOG_CONS;
void
-fatal_exit(const std::string& message)
-{
- fprintf(stderr, "FATAL_EXIT: %s\n", message.c_str());
- syslog(opt_syslog, "FATAL_EXIT: %s", message.c_str());
- _exit(1);
-}
-
-void
fatal_abort(const std::string& message)
{
fprintf(stderr, "FATAL_COREDUMP: %s\n", message.c_str());
diff --git a/plugin/handler_socket/libhsclient/fatal.hpp b/plugin/handler_socket/libhsclient/fatal.hpp
index 8a630fab1cb..5eaa3db8687 100644
--- a/plugin/handler_socket/libhsclient/fatal.hpp
+++ b/plugin/handler_socket/libhsclient/fatal.hpp
@@ -13,7 +13,6 @@
namespace dena {
-void fatal_exit(const std::string& message);
void fatal_abort(const std::string& message);
};
diff --git a/plugin/handler_socket/libhsclient/socket.cpp b/plugin/handler_socket/libhsclient/socket.cpp
index cf19d4bbe14..2c93a3b4846 100644
--- a/plugin/handler_socket/libhsclient/socket.cpp
+++ b/plugin/handler_socket/libhsclient/socket.cpp
@@ -43,7 +43,7 @@ socket_args::set(const config& conf)
} else {
const char *nd = node.empty() ? 0 : node.c_str();
if (resolve(nd, port.c_str()) != 0) {
- fatal_exit("getaddrinfo failed: " + node + ":" + port);
+ fatal_abort("getaddrinfo failed: " + node + ":" + port);
}
}
}
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.xs b/plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.xs
index 899941df7ff..8169b3e52a9 100644
--- a/plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.xs
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.xs
@@ -148,7 +148,7 @@ sv_get_string_ref(SV *sv)
static IV
sv_get_iv(SV *sv)
{
- if (sv == 0 || !SvIOK(sv)) {
+ if (sv == 0 || ( !SvIOK(sv) && !SvPOK(sv) ) ) {
return 0;
}
return SvIV(sv);
diff --git a/plugin/handler_socket/plug.in b/plugin/handler_socket/plug.in
deleted file mode 100644
index fd351dec98d..00000000000
--- a/plugin/handler_socket/plug.in
+++ /dev/null
@@ -1,20 +0,0 @@
-MYSQL_PLUGIN(handlersocket, [HandlerSocket], [HandlerSocket], [max])
-MYSQL_PLUGIN_DYNAMIC(handlersocket, handlersocket.la)
-MYSQL_PLUGIN_ACTIONS(handlersocket,
-[
- ac_mysql_source_dir='$(top_srcdir)'
- MYSQL_INC="-I$ac_mysql_source_dir/sql"
- MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/include"
- MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/regex"
- MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir"
- MYSQL_LIB='-L$(top_builddir)/libservices -lmysqlservices'
- PLUGIN_DIR='$(pkglibdir)/plugin'
- HANDLERSOCKET_SUBDIRS="libhsclient handlersocket client"
-
- AC_SUBST(MYSQL_INC)
- AC_SUBST(MYSQL_CFLAGS)
- AC_SUBST(MYSQL_LIB)
- AC_SUBST(PLUGIN_DIR)
- AC_SUBST(HANDLERSOCKET_SUBDIRS)
- AC_CONFIG_FILES(plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL)
-])
diff --git a/plugin/handler_socket/regtest/test_01_lib/run.sh b/plugin/handler_socket/regtest/test_01_lib/run.sh
index 8514612832f..84603d65a57 100755
--- a/plugin/handler_socket/regtest/test_01_lib/run.sh
+++ b/plugin/handler_socket/regtest/test_01_lib/run.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-TESTS="01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23";
+TESTS="01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24";
source ../common/compat.sh
diff --git a/plugin/handler_socket/regtest/test_01_lib/test14.pl b/plugin/handler_socket/regtest/test_01_lib/test14.pl
index 68ce87bdd63..ff4e433ae8f 100644
--- a/plugin/handler_socket/regtest/test_01_lib/test14.pl
+++ b/plugin/handler_socket/regtest/test_01_lib/test14.pl
@@ -27,7 +27,7 @@ srand(999);
my %valmap = ();
-my $sth = $dbh->prepare("insert into $table values (?,?,?)");
+my $sth = $dbh->prepare("insert ignore into $table values (?,?,?)");
for (my $i = 0; $i < $tablesize; ++$i) {
my $k = $i;
my ($s1, $s2) = ("", "");
diff --git a/plugin/handler_socket/regtest/test_01_lib/test17.pl b/plugin/handler_socket/regtest/test_01_lib/test17.pl
index b7861b880f5..1ffd7fa1242 100644
--- a/plugin/handler_socket/regtest/test_01_lib/test17.pl
+++ b/plugin/handler_socket/regtest/test_01_lib/test17.pl
@@ -60,7 +60,7 @@ sub test_one {
$dbh->do(
"create table $table (" .
"k $typ, " .
- "v1 varchar(2047), " .
+ "v1 varchar(1000), " .
"v2 $typ, " .
"primary key(k$keylen_str), " .
"index i1(v1), index i2(v2$keylen_str, v1(300))) " .
diff --git a/plugin/handler_socket/regtest/test_01_lib/test19.pl b/plugin/handler_socket/regtest/test_01_lib/test19.pl
index 6c43267c927..9870199c1a7 100644
--- a/plugin/handler_socket/regtest/test_01_lib/test19.pl
+++ b/plugin/handler_socket/regtest/test_01_lib/test19.pl
@@ -113,7 +113,7 @@ sub test_one {
"(k1 int not null, k2 int not null, " .
"v1 int not null, v2 $typ default null, " .
"primary key (k1, k2) ) engine = innodb");
- my $sth = $dbh->prepare("insert into $table values (?,?,?,?)");
+ my $sth = $dbh->prepare("insert ignore into $table values (?,?,?,?)");
for (my $i = 0; $i < $tablesize; ++$i) {
my $j = 0;
for my $v (@$values) {
diff --git a/plugin/handler_socket/regtest/test_01_lib/test24.expected b/plugin/handler_socket/regtest/test_01_lib/test24.expected
new file mode 100644
index 00000000000..5d07e01bb92
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test24.expected
@@ -0,0 +1,2 @@
+HS
+0 0
diff --git a/plugin/handler_socket/regtest/test_01_lib/test24.pl b/plugin/handler_socket/regtest/test_01_lib/test24.pl
new file mode 100644
index 00000000000..6cd95a995e5
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test24.pl
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+
+# vim:sw=2:ai
+
+# test for issue #78
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (" .
+ "id bigint(20) not null auto_increment, " .
+ "t1 timestamp not null default current_timestamp, " .
+ "primary key (id)" .
+ ") engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(0, $dbname, $table, 'PRIMARY', 'id,t1');
+my $res = $hs->execute_single(0, '+', [ 321 ], 0, 0);
+die $hs->get_error() if $res->[0] != 0;
+print "HS\n";
+print join(' ', @$res) . "\n";
+
diff --git a/plugin/locale_info/CMakeLists.txt b/plugin/locale_info/CMakeLists.txt
new file mode 100644
index 00000000000..8f1dfa0d715
--- /dev/null
+++ b/plugin/locale_info/CMakeLists.txt
@@ -0,0 +1,5 @@
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex
+ ${CMAKE_SOURCE_DIR}/extra/yassl/include)
+
+MYSQL_ADD_PLUGIN(LOCALES locale_info.cc RECOMPILE_FOR_EMBEDDED)
+
diff --git a/plugin/locale_info/locale_info.cc b/plugin/locale_info/locale_info.cc
new file mode 100644
index 00000000000..3d775c0be7c
--- /dev/null
+++ b/plugin/locale_info/locale_info.cc
@@ -0,0 +1,122 @@
+/*
+ Copyright (c) 2013, Spaempresarial - Brazil, Roberto Spadim
+ http://www.spadim.com.br/
+ roberto@spadim.com.br
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Roberto Spadim nor the
+ names of the contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL ROBERTO SPADIM BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sql_class.h> // THD
+#include <table.h> // ST_SCHEMA_TABLE
+#include <mysql/plugin.h>
+#include <m_ctype.h>
+#include "sql_locale.h"
+
+bool schema_table_store_record(THD *thd, TABLE *table);
+static MY_LOCALE **locale_list;
+
+/* LOCALES */
+static ST_FIELD_INFO locale_info_locale_fields_info[]=
+{
+ {"ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Id", 0},
+ {"NAME", 255, MYSQL_TYPE_STRING, 0, 0, "Name", 0},
+ {"DESCRIPTION", 255, MYSQL_TYPE_STRING, 0, 0, "Description", 0},
+ {"MAX_MONTH_NAME_LENGTH", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, 0},
+ {"MAX_DAY_NAME_LENGTH", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, 0},
+ {"DECIMAL_POINT", 2, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+ {"THOUSAND_SEP", 2, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+ {"ERROR_MESSAGE_LANGUAGE", 64, MYSQL_TYPE_STRING, 0, 0, "Error_Message_Language", 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+};
+static int locale_info_fill_table_locale(THD* thd, TABLE_LIST* tables, COND* cond)
+{
+ TABLE *table= tables->table;
+ CHARSET_INFO *cs= system_charset_info;
+
+ for (MY_LOCALE **loc= locale_list; *loc; loc++)
+ {
+ /* ID */
+ table->field[0]->store((longlong) (*loc)->number, TRUE);
+ /* NAME */
+ table->field[1]->store((*loc)->name, strlen((*loc)->name), cs);
+ /* DESCRIPTION */
+ table->field[2]->store((*loc)->description, strlen((*loc)->description), cs);
+ /* MAX_MONTH_NAME_LENGTH */
+ table->field[3]->store((longlong) (*loc)->max_month_name_length, TRUE);
+ /* MAX_DAY_NAME_LENGTH */
+ table->field[4]->store((longlong) (*loc)->max_day_name_length, TRUE);
+ /* DECIMAL_POINT */
+ char decimal= (*loc)->decimal_point;
+ table->field[5]->store(&decimal, decimal ? 1 : 0, cs);
+ /* THOUSAND_SEP */
+ char thousand= (*loc)->thousand_sep;
+ table->field[6]->store(&thousand, thousand ? 1 : 0, cs);
+ /* ERROR_MESSAGE_LANGUAGE */
+ table->field[7]->store((*loc)->errmsgs->language,
+ strlen((*loc)->errmsgs->language), cs);
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ return 0;
+}
+
+static int locale_info_plugin_init_locales(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= locale_info_locale_fields_info;
+ schema->fill_table= locale_info_fill_table_locale;
+
+#if defined(_WIN64)
+ locale_list = (MY_LOCALE **)GetProcAddress(GetModuleHandle(NULL), "?my_locales@@3PAPEAVMY_LOCALE@@A");
+#elif defined(_WIN32)
+ locale_list = (MY_LOCALE **)GetProcAddress(GetModuleHandle(NULL), "?my_locales@@3PAPAVMY_LOCALE@@A");
+#else
+ locale_list = my_locales;
+#endif
+
+ return 0;
+}
+static struct st_mysql_information_schema locale_info_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+/*
+ Plugin library descriptor
+*/
+
+maria_declare_plugin(locales)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN, /* the plugin type (see include/mysql/plugin.h) */
+ &locale_info_plugin, /* pointer to type-specific plugin descriptor */
+ "LOCALES", /* plugin name */
+ "Roberto Spadim, Spaempresarial - Brazil", /* plugin author */
+ "Lists all locales from server.", /* the plugin description */
+ PLUGIN_LICENSE_BSD, /* the plugin license (see include/mysql/plugin.h) */
+ locale_info_plugin_init_locales, /* Pointer to plugin initialization function */
+ 0, /* Pointer to plugin deinitialization function */
+ 0x0100, /* Numeric version 0xAABB means AA.BB veriosn */
+ NULL, /* Status variables */
+ NULL, /* System variables */
+ "1.0", /* String version representation */
+ MariaDB_PLUGIN_MATURITY_STABLE /* Maturity (see include/mysql/plugin.h)*/
+}
+maria_declare_plugin_end;
diff --git a/plugin/metadata_lock_info/CMakeLists.txt b/plugin/metadata_lock_info/CMakeLists.txt
new file mode 100644
index 00000000000..6b1f5108bf1
--- /dev/null
+++ b/plugin/metadata_lock_info/CMakeLists.txt
@@ -0,0 +1,3 @@
+SET(METADATA_LOCK_INFO_SOURCES metadata_lock_info.cc)
+MYSQL_ADD_PLUGIN(metadata_lock_info ${METADATA_LOCK_INFO_SOURCES}
+ RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/metadata_lock_info/metadata_lock_info.cc b/plugin/metadata_lock_info/metadata_lock_info.cc
new file mode 100644
index 00000000000..7abae275ff2
--- /dev/null
+++ b/plugin/metadata_lock_info/metadata_lock_info.cc
@@ -0,0 +1,182 @@
+/* Copyright (C) 2013 Kentoku Shiba
+
+ 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 02110-1335 USA */
+
+#define MYSQL_SERVER 1
+#include "my_config.h"
+#include "mysql_version.h"
+#include "mysql/plugin.h"
+#include "sql_class.h"
+#include "sql_show.h"
+
+static const LEX_STRING metadata_lock_info_lock_name[] = {
+ { C_STRING_WITH_LEN("Global read lock") },
+ { C_STRING_WITH_LEN("Schema metadata lock") },
+ { C_STRING_WITH_LEN("Table metadata lock") },
+ { C_STRING_WITH_LEN("Stored function metadata lock") },
+ { C_STRING_WITH_LEN("Stored procedure 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_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,
+ MY_I_S_UNSIGNED, "thread_id", SKIP_OPEN_TABLE},
+ {"LOCK_MODE", 24, MYSQL_TYPE_STRING, 0,
+ MY_I_S_MAYBE_NULL, "lock_mode", SKIP_OPEN_TABLE},
+ {"LOCK_DURATION", 30, MYSQL_TYPE_STRING, 0,
+ MY_I_S_MAYBE_NULL, "lock_duration", SKIP_OPEN_TABLE},
+ {"LOCK_TYPE", 30, MYSQL_TYPE_STRING, 0,
+ MY_I_S_MAYBE_NULL, "lock_type", SKIP_OPEN_TABLE},
+ {"TABLE_SCHEMA", 64, MYSQL_TYPE_STRING, 0,
+ MY_I_S_MAYBE_NULL, "table_schema", SKIP_OPEN_TABLE},
+ {"TABLE_NAME", 64, MYSQL_TYPE_STRING, 0,
+ MY_I_S_MAYBE_NULL, "table_name", SKIP_OPEN_TABLE},
+ {NULL, 0, MYSQL_TYPE_STRING, 0, 0, NULL, 0}
+};
+
+struct st_i_s_metadata_param
+{
+ THD *thd;
+ TABLE *table;
+};
+
+int i_s_metadata_lock_info_fill_row(
+ MDL_ticket *mdl_ticket,
+ void *arg
+) {
+ 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();
+ 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[2]->set_null();
+ table->field[3]->set_notnull();
+ table->field[3]->store(
+ metadata_lock_info_lock_name[(int) mdl_namespace].str,
+ metadata_lock_info_lock_name[(int) mdl_namespace].length,
+ system_charset_info);
+ table->field[4]->set_notnull();
+ table->field[4]->store(mdl_key->db_name(),
+ mdl_key->db_name_length(), system_charset_info);
+ table->field[5]->set_notnull();
+ table->field[5]->store(mdl_key->name(),
+ mdl_key->name_length(), system_charset_info);
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+int i_s_metadata_lock_info_fill_table(
+ THD *thd,
+ TABLE_LIST *tables,
+ COND *cond
+) {
+ st_i_s_metadata_param param;
+ DBUG_ENTER("i_s_metadata_lock_info_fill_table");
+ param.table = tables->table;
+ param.thd = thd;
+ DBUG_RETURN(mdl_iterate(i_s_metadata_lock_info_fill_row, &param));
+}
+
+static int i_s_metadata_lock_info_init(
+ void *p
+) {
+
+ 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");
+ schema->fields_info = i_s_metadata_lock_info_fields_info;
+ schema->fill_table = i_s_metadata_lock_info_fill_table;
+ schema->idx_field1 = 0;
+ DBUG_RETURN(0);
+}
+
+static int i_s_metadata_lock_info_deinit(
+ void *p
+) {
+ DBUG_ENTER("i_s_metadata_lock_info_deinit");
+ DBUG_RETURN(0);
+}
+
+static struct st_mysql_information_schema i_s_metadata_lock_info_plugin =
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+#ifdef MARIADB_BASE_VERSION
+maria_declare_plugin(metadata_lock_info)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &i_s_metadata_lock_info_plugin,
+ "METADATA_LOCK_INFO",
+ "Kentoku Shiba",
+ "Metadata locking viewer",
+ PLUGIN_LICENSE_GPL,
+ i_s_metadata_lock_info_init,
+ i_s_metadata_lock_info_deinit,
+ 0x0001,
+ NULL,
+ NULL,
+ NULL,
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+#else
+mysql_declare_plugin(metadata_lock_info)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &i_s_metadata_lock_info_plugin,
+ "METADATA_LOCK_INFO",
+ "Kentoku Shiba",
+ "Metadata locking viewer",
+ PLUGIN_LICENSE_GPL,
+ i_s_metadata_lock_info_init,
+ i_s_metadata_lock_info_deinit,
+ 0x0001,
+ NULL,
+ NULL,
+ NULL,
+#if MYSQL_VERSION_ID >= 50600
+ 0,
+#endif
+}
+mysql_declare_plugin_end;
+#endif
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
new file mode 100644
index 00000000000..5803d7d1290
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result
@@ -0,0 +1,10 @@
+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
+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
+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/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result
new file mode 100644
index 00000000000..1b76b9e8222
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result
@@ -0,0 +1,13 @@
+CREATE TABLE IF NOT EXISTS t1(a int);
+BEGIN;
+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
+SELECT * FROM t1;
+a
+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_READ NULL Table metadata lock test t1
+ROLLBACK;
+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
+DROP TABLE t1;
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result
new file mode 100644
index 00000000000..34d238cb43b
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result
@@ -0,0 +1,13 @@
+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
+SELECT GET_LOCK('LOCK1',0);
+GET_LOCK('LOCK1',0)
+1
+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_NO_WRITE NULL User lock LOCK1
+SELECT RELEASE_LOCK('LOCK1');
+RELEASE_LOCK('LOCK1')
+1
+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/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt
new file mode 100644
index 00000000000..47a7881bf33
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt
@@ -0,0 +1,2 @@
+--loose-metadata_lock_info
+--plugin-load-add=$METADATA_LOCK_INFO_SO
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm
new file mode 100644
index 00000000000..a1c6d00343c
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm
@@ -0,0 +1,11 @@
+package My::Suite::Metadata_lock_info;
+
+@ISA = qw(My::Suite);
+
+return "No Metadata_lock_info plugin" unless $ENV{METADATA_LOCK_INFO_SO} or
+ $::mysqld_variables{'metadata-lock-info'} eq "ON";;
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test
new file mode 100644
index 00000000000..103050e3fb8
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test
@@ -0,0 +1,6 @@
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+FLUSH TABLES WITH READ LOCK;
+--sorted_result
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+UNLOCK TABLES;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test
new file mode 100644
index 00000000000..3451dff039d
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test
@@ -0,0 +1,8 @@
+CREATE TABLE IF NOT EXISTS t1(a int);
+BEGIN;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+SELECT * FROM t1;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+ROLLBACK;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+DROP TABLE t1;
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test
new file mode 100644
index 00000000000..85dec3dcf75
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test
@@ -0,0 +1,5 @@
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+SELECT GET_LOCK('LOCK1',0);
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+SELECT RELEASE_LOCK('LOCK1');
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
diff --git a/plugin/qc_info/CMakeLists.txt b/plugin/qc_info/CMakeLists.txt
index f9c58f77466..821ffb79225 100644
--- a/plugin/qc_info/CMakeLists.txt
+++ b/plugin/qc_info/CMakeLists.txt
@@ -1,4 +1,5 @@
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql
+ ${PCRE_INCLUDES}
${CMAKE_SOURCE_DIR}/extra/yassl/include)
-MYSQL_ADD_PLUGIN(QUERY_CACHE_INFO qc_info.cc)
+MYSQL_ADD_PLUGIN(QUERY_CACHE_INFO qc_info.cc RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/qc_info/qc_info.cc b/plugin/qc_info/qc_info.cc
index 8489b14c5db..1dcef004447 100644
--- a/plugin/qc_info/qc_info.cc
+++ b/plugin/qc_info/qc_info.cc
@@ -28,9 +28,6 @@
*/
-/*
- * TODO: report query cache flags
- */
#ifndef MYSQL_SERVER
#define MYSQL_SERVER
#endif
@@ -40,6 +37,8 @@
#include <sql_acl.h> // PROCESS_ACL
#include <sql_class.h> // THD
#include <table.h> // ST_SCHEMA_TABLE
+#include <set_var.h> // sql_mode_string_representation
+#include <tztime.h>
#include <mysql/plugin.h>
class Accessible_Query_Cache : public Query_cache {
@@ -58,6 +57,25 @@ bool schema_table_store_record(THD *thd, TABLE *table);
#define COLUMN_RESULT_BLOCKS_COUNT 2
#define COLUMN_RESULT_BLOCKS_SIZE 3
#define COLUMN_RESULT_BLOCKS_SIZE_USED 4
+#define COLUMN_LIMIT 5
+#define COLUMN_MAX_SORT_LENGTH 6
+#define COLUMN_GROUP_CONCAT_MAX_LENGTH 7
+#define COLUMN_CHARACTER_SET_CLIENT 8
+#define COLUMN_CHARACTER_SET_RESULT 9
+#define COLUMN_COLLATION 10
+#define COLUMN_TIMEZONE 11
+#define COLUMN_DEFAULT_WEEK_FORMAT 12
+#define COLUMN_DIV_PRECISION_INCREMENT 13
+#define COLUMN_SQL_MODE 14
+#define COLUMN_LC_TIME_NAMES 15
+
+#define COLUMN_CLIENT_LONG_FLAG 16
+#define COLUMN_CLIENT_PROTOCOL_41 17
+#define COLUMN_PROTOCOL_TYPE 18
+#define COLUMN_MORE_RESULTS_EXISTS 19
+#define COLUMN_IN_TRANS 20
+#define COLUMN_AUTOCOMMIT 21
+#define COLUMN_PKT_NR 22
/* ST_FIELD_INFO is defined in table.h */
static ST_FIELD_INFO qc_info_fields[]=
@@ -67,9 +85,30 @@ static ST_FIELD_INFO qc_info_fields[]=
{"RESULT_BLOCKS_COUNT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, 0, 0},
{"RESULT_BLOCKS_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0, 0},
{"RESULT_BLOCKS_SIZE_USED", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0, 0},
+ {"LIMIT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0, 0},
+ {"MAX_SORT_LENGTH", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0, 0},
+ {"GROUP_CONCAT_MAX_LENGTH", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0, 0},
+ {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+ {"CHARACTER_SET_RESULT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+ {"COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+ {"TIMEZONE", 50, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+ {"DEFAULT_WEEK_FORMAT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, 0, 0},
+ {"DIV_PRECISION_INCREMENT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, 0, 0},
+ {"SQL_MODE", 250, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+ {"LC_TIME_NAMES", 100, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+ {"CLIENT_LONG_FLAG", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_TINY, 0, 0, 0, 0},
+ {"CLIENT_PROTOCOL_41", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_TINY, 0, 0, 0, 0},
+ {"PROTOCOL_TYPE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_TINY, 0, 0, 0, 0},
+ {"MORE_RESULTS_EXISTS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_TINY, 0, 0, 0, 0},
+ {"IN_TRANS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_TINY, 0, 0, 0, 0},
+ {"AUTOCOMMIT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_TINY, 0, 0, 0, 0},
+ {"PACKET_NUMBER", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_TINY, 0, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
};
+
+static const char unknown[]= "#UNKNOWN#";
+
static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
COND *cond)
{
@@ -91,6 +130,7 @@ static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
const uchar *query_cache_block_raw;
Query_cache_block* query_cache_block;
Query_cache_query* query_cache_query;
+ Query_cache_query_flags flags;
uint result_blocks_count;
ulonglong result_blocks_size;
ulonglong result_blocks_size_used;
@@ -98,12 +138,19 @@ static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
Query_cache_block *result_block;
const char *statement_text;
size_t statement_text_length;
+ size_t flags_length;
const char *key, *db;
size_t key_length, db_length;
+ LEX_STRING sql_mode_str;
+ const String *tz;
+ CHARSET_INFO *cs_client;
+ CHARSET_INFO *cs_result;
+ CHARSET_INFO *collation;
query_cache_block_raw = my_hash_element(queries, i);
query_cache_block = (Query_cache_block*)query_cache_block_raw;
- if (query_cache_block->type != Query_cache_block::QUERY)
+ if (unlikely(!query_cache_block ||
+ query_cache_block->type != Query_cache_block::QUERY))
continue;
query_cache_query = query_cache_block->query();
@@ -113,11 +160,62 @@ static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
statement_text_length = strlen(statement_text);
/* We truncate SQL statements up to MAX_STATEMENT_TEXT_LENGTH in our I_S table */
table->field[COLUMN_STATEMENT_TEXT]->store((char*)statement_text,
- min(statement_text_length, MAX_STATEMENT_TEXT_LENGTH), scs);
+ MY_MIN(statement_text_length, MAX_STATEMENT_TEXT_LENGTH), scs);
/* get the entire key that identifies this query cache query */
key = (const char*)query_cache_query_get_key(query_cache_block_raw,
&key_length, 0);
+ /* get and store the flags */
+ flags_length= key_length - QUERY_CACHE_FLAGS_SIZE;
+ memcpy(&flags, key+flags_length, QUERY_CACHE_FLAGS_SIZE);
+ table->field[COLUMN_LIMIT]->store(flags.limit, 0);
+ table->field[COLUMN_MAX_SORT_LENGTH]->store(flags.max_sort_length, 0);
+ table->field[COLUMN_GROUP_CONCAT_MAX_LENGTH]->store(flags.group_concat_max_len, 0);
+
+ cs_client= get_charset(flags.character_set_client_num, MYF(MY_WME));
+ if (likely(cs_client))
+ table->field[COLUMN_CHARACTER_SET_CLIENT]->
+ store(cs_client->csname, strlen(cs_client->csname), scs);
+ else
+ table->field[COLUMN_CHARACTER_SET_CLIENT]->
+ store(STRING_WITH_LEN(unknown), scs);
+
+ cs_result= get_charset(flags.character_set_results_num, MYF(MY_WME));
+ if (likely(cs_result))
+ table->field[COLUMN_CHARACTER_SET_RESULT]->
+ store(cs_result->csname, strlen(cs_result->csname), scs);
+ else
+ table->field[COLUMN_CHARACTER_SET_RESULT]->
+ store(STRING_WITH_LEN(unknown), scs);
+
+ collation= get_charset(flags.collation_connection_num, MYF(MY_WME));
+ if (likely(collation))
+ table->field[COLUMN_COLLATION]->
+ store(collation->name, strlen(collation->name), scs);
+ else
+ table->field[COLUMN_COLLATION]-> store(STRING_WITH_LEN(unknown), scs);
+
+ tz= flags.time_zone->get_name();
+ if (likely(tz))
+ table->field[COLUMN_TIMEZONE]->store(tz->ptr(), tz->length(), scs);
+ else
+ table->field[COLUMN_TIMEZONE]-> store(STRING_WITH_LEN(unknown), scs);
+ table->field[COLUMN_DEFAULT_WEEK_FORMAT]->store(flags.default_week_format, 0);
+ table->field[COLUMN_DIV_PRECISION_INCREMENT]->store(flags.div_precision_increment, 0);
+
+ sql_mode_string_representation(thd, flags.sql_mode, &sql_mode_str);
+ table->field[COLUMN_SQL_MODE]->store(sql_mode_str.str, sql_mode_str.length, scs);
+
+ table->field[COLUMN_LC_TIME_NAMES]->store(flags.lc_time_names->name,strlen(flags.lc_time_names->name), scs);
+
+ table->field[COLUMN_CLIENT_LONG_FLAG]->store(flags.client_long_flag, 0);
+ table->field[COLUMN_CLIENT_PROTOCOL_41]->store(flags.client_protocol_41, 0);
+ table->field[COLUMN_PROTOCOL_TYPE]->store(flags.protocol_type, 0);
+ table->field[COLUMN_MORE_RESULTS_EXISTS]->store(flags.more_results_exists, 0);
+ table->field[COLUMN_IN_TRANS]->store(flags.in_trans, 0);
+ table->field[COLUMN_AUTOCOMMIT]->store(flags.autocommit, 0);
+ table->field[COLUMN_PKT_NR]->store(flags.pkt_nr, 0);
+
/* The database against which the statement is executed is part of the
query cache query key
*/
@@ -129,7 +227,8 @@ static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
/* If we have result blocks, process them */
first_result_block= query_cache_query->result();
- if(first_result_block)
+ if(query_cache_query->is_results_ready() &&
+ first_result_block)
{
/* initialize so we can loop over the result blocks*/
result_block= first_result_block;
@@ -156,7 +255,8 @@ static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
}
table->field[COLUMN_RESULT_BLOCKS_COUNT]->store(result_blocks_count, 0);
table->field[COLUMN_RESULT_BLOCKS_SIZE]->store(result_blocks_size, 0);
- table->field[COLUMN_RESULT_BLOCKS_SIZE_USED]->store(result_blocks_size_used, 0);
+ table->field[COLUMN_RESULT_BLOCKS_SIZE_USED]->
+ store(result_blocks_size_used, 0);
if (schema_table_store_record(thd, table))
goto cleanup;
@@ -198,16 +298,16 @@ maria_declare_plugin(query_cache_info)
MYSQL_INFORMATION_SCHEMA_PLUGIN,
&qc_info_plugin,
"QUERY_CACHE_INFO",
- "Roland Bouman",
+ "Roland Bouman, Daniel Black",
"Lists all queries in the query cache.",
PLUGIN_LICENSE_BSD,
qc_info_plugin_init, /* Plugin Init */
0, /* Plugin Deinit */
- 0x0100, /* version, hex */
+ 0x0101, /* version, hex */
NULL, /* status variables */
NULL, /* system variables */
- "1.0", /* version as a string */
- MariaDB_PLUGIN_MATURITY_ALPHA
+ "1.1", /* version as a string */
+ MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;
diff --git a/plugin/query_response_time/CMakeLists.txt b/plugin/query_response_time/CMakeLists.txt
new file mode 100644
index 00000000000..112d72e429a
--- /dev/null
+++ b/plugin/query_response_time/CMakeLists.txt
@@ -0,0 +1,3 @@
+ADD_DEFINITIONS(-DHAVE_RESPONSE_TIME_DISTRIBUTION)
+MYSQL_ADD_PLUGIN(QUERY_RESPONSE_TIME query_response_time.cc plugin.cc
+ RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/query_response_time/mysql-test/query_response_time/basic.result b/plugin/query_response_time/mysql-test/query_response_time/basic.result
new file mode 100644
index 00000000000..11cc607df39
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/basic.result
@@ -0,0 +1,27 @@
+SHOW VARIABLES WHERE VARIABLE_NAME LIKE 'query_response_time%' AND VARIABLE_NAME!='query_response_time_exec_time_debug';
+Variable_name Value
+query_response_time_flush OFF
+query_response_time_range_base 10
+query_response_time_stats OFF
+SHOW CREATE TABLE INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+Table Create Table
+QUERY_RESPONSE_TIME CREATE TEMPORARY TABLE `QUERY_RESPONSE_TIME` (
+ `TIME` varchar(14) NOT NULL DEFAULT '',
+ `COUNT` int(11) unsigned NOT NULL DEFAULT '0',
+ `TOTAL` varchar(14) NOT NULL DEFAULT ''
+) ENGINE=MEMORY DEFAULT CHARSET=utf8
+SELECT PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_TYPE, PLUGIN_AUTHOR, PLUGIN_DESCRIPTION, PLUGIN_LICENSE, PLUGIN_MATURITY FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'query_response_time%';;
+PLUGIN_NAME QUERY_RESPONSE_TIME
+PLUGIN_VERSION 1.0
+PLUGIN_TYPE INFORMATION SCHEMA
+PLUGIN_AUTHOR Percona and Sergey Vojtovich
+PLUGIN_DESCRIPTION Query Response Time Distribution INFORMATION_SCHEMA Plugin
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_NAME QUERY_RESPONSE_TIME_AUDIT
+PLUGIN_VERSION 1.0
+PLUGIN_TYPE AUDIT
+PLUGIN_AUTHOR Percona and Sergey Vojtovich
+PLUGIN_DESCRIPTION Query Response Time Distribution Audit Plugin
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
diff --git a/plugin/query_response_time/mysql-test/query_response_time/basic.test b/plugin/query_response_time/mysql-test/query_response_time/basic.test
new file mode 100644
index 00000000000..e46c8035d24
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/basic.test
@@ -0,0 +1,3 @@
+SHOW VARIABLES WHERE VARIABLE_NAME LIKE 'query_response_time%' AND VARIABLE_NAME!='query_response_time_exec_time_debug';
+SHOW CREATE TABLE INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+--query_vertical SELECT PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_TYPE, PLUGIN_AUTHOR, PLUGIN_DESCRIPTION, PLUGIN_LICENSE, PLUGIN_MATURITY FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'query_response_time%';
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.inc b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.inc
new file mode 100644
index 00000000000..e86594d6fac
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.inc
@@ -0,0 +1,36 @@
+SET SESSION query_response_time_exec_time_debug=100000;
+
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+EVAL SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=$base;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+
+SET SESSION query_response_time_exec_time_debug=default;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.result b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.result
new file mode 100644
index 00000000000..bec7007d2d0
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.result
@@ -0,0 +1,392 @@
+CREATE TABLE t(a INT);
+CREATE PROCEDURE test_f(t INT)
+BEGIN
+SET SESSION query_response_time_exec_time_debug=t;
+INSERT INTO t VALUES(1);
+SET SESSION query_response_time_exec_time_debug=100000;
+DELETE FROM t;
+END^
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1;
+Warnings:
+Warning 1292 Truncated incorrect query_response_time_range_base value: '1'
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 2
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 44 4.400000
+ 0.250000 0 0.000000
+ 0.500000 10 3.550000
+ 1.000000 1 0.500000
+ 2.000000 5 6.500000
+ 4.000000 4 10.000000
+ 8.000000 2 9.200000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=2;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 2
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 44 4.400000
+ 0.250000 0 0.000000
+ 0.500000 10 3.550000
+ 1.000000 1 0.500000
+ 2.000000 5 6.500000
+ 4.000000 4 10.000000
+ 8.000000 2 9.200000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=10;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 10
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.000010 0 0.000000
+ 0.000100 0 0.000000
+ 0.001000 0 0.000000
+ 0.010000 0 0.000000
+ 0.100000 0 0.000000
+ 1.000000 55 8.450000
+ 10.000000 11 25.700000
+ 100.000000 0 0.000000
+ 1000.000000 0 0.000000
+ 10000.000000 0 0.000000
+ 100000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=7;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 7
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.000008 0 0.000000
+ 0.000059 0 0.000000
+ 0.000416 0 0.000000
+ 0.002915 0 0.000000
+ 0.020408 0 0.000000
+ 0.142857 44 4.400000
+ 1.000000 11 4.050000
+ 7.000000 11 25.700000
+ 49.000000 0 0.000000
+ 343.000000 0 0.000000
+ 2401.000000 0 0.000000
+ 16807.000000 0 0.000000
+ 117649.000000 0 0.000000
+ 823543.000000 0 0.000000
+5764801.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=156;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 156
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000041 45 0.000000
+ 0.006410 0 0.000000
+ 1.000000 55 8.450000
+ 156.000000 11 25.700000
+ 24336.000000 0 0.000000
+3796416.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1000;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 1000
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.001000 0 0.000000
+ 1.000000 55 8.450000
+ 1000.000000 11 25.700000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1001;
+Warnings:
+Warning 1292 Truncated incorrect query_response_time_range_base value: '1001'
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 1000
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.001000 0 0.000000
+ 1.000000 55 8.450000
+ 1000.000000 11 25.700000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=default;
+DROP PROCEDURE test_f;
+DROP TABLE t;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.test b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.test
new file mode 100644
index 00000000000..e281bd352f1
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.test
@@ -0,0 +1,44 @@
+--source include/have_debug.inc
+
+# The file with expected results fits only to a run without
+# ps-protocol/sp-protocol/cursor-protocol/view-protocol.
+if (`SELECT $PS_PROTOCOL + $SP_PROTOCOL + $CURSOR_PROTOCOL
+ + $VIEW_PROTOCOL > 0`)
+{
+ --skip Test requires: ps-protocol/sp-protocol/cursor-protocol/view-protocol disabled
+}
+
+
+CREATE TABLE t(a INT);
+
+delimiter ^;
+CREATE PROCEDURE test_f(t INT)
+BEGIN
+ SET SESSION query_response_time_exec_time_debug=t;
+ INSERT INTO t VALUES(1);
+ SET SESSION query_response_time_exec_time_debug=100000;
+ DELETE FROM t;
+END^
+delimiter ;^
+
+--let base=1
+--source query_response_time-stored.inc
+--let base=2
+--source query_response_time-stored.inc
+--let base=10
+--source query_response_time-stored.inc
+--let base=7
+--source query_response_time-stored.inc
+--let base=156
+--source query_response_time-stored.inc
+--let base=1000
+--source query_response_time-stored.inc
+--let base=1001
+--source query_response_time-stored.inc
+
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=default;
+
+DROP PROCEDURE test_f;
+
+DROP TABLE t;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time.inc b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.inc
new file mode 100644
index 00000000000..d13215aa5d4
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.inc
@@ -0,0 +1,41 @@
+SET SESSION query_response_time_exec_time_debug=100000;
+
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+EVAL SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=$base;
+FLUSH QUERY_RESPONSE_TIME;
+# Following two queries check works of FLUSH and
+# respecting of "QUERY_RESPONSE_TIME_STATS" variable (see launchpad bug #855312)
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+
+SET SESSION query_response_time_exec_time_debug=310000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=320000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=330000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=340000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=350000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=360000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=370000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=380000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=390000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=400000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1100000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1200000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1300000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1500000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1400000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=500000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=2100000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=2300000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=2500000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=3100000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=4100000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=5100000; SELECT 1;
+
+SET SESSION query_response_time_exec_time_debug=100000;
+
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+SHOW QUERY_RESPONSE_TIME;
+
+SET SESSION query_response_time_exec_time_debug=default;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time.result b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.result
new file mode 100644
index 00000000000..14822c35915
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.result
@@ -0,0 +1,1003 @@
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1;
+Warnings:
+Warning 1292 Truncated incorrect query_response_time_range_base value: '1'
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 0 0.000000
+ 0.250000 0 0.000000
+ 0.500000 0 0.000000
+ 1.000000 0 0.000000
+ 2.000000 0 0.000000
+ 4.000000 0 0.000000
+ 8.000000 0 0.000000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 2
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 0 0.000000
+ 0.250000 0 0.000000
+ 0.500000 10 3.550000
+ 1.000000 1 0.500000
+ 2.000000 5 6.500000
+ 4.000000 4 10.000000
+ 8.000000 2 9.200000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=2;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 0 0.000000
+ 0.250000 0 0.000000
+ 0.500000 0 0.000000
+ 1.000000 0 0.000000
+ 2.000000 0 0.000000
+ 4.000000 0 0.000000
+ 8.000000 0 0.000000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 2
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 0 0.000000
+ 0.250000 0 0.000000
+ 0.500000 10 3.550000
+ 1.000000 1 0.500000
+ 2.000000 5 6.500000
+ 4.000000 4 10.000000
+ 8.000000 2 9.200000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=10;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.000010 0 0.000000
+ 0.000100 0 0.000000
+ 0.001000 0 0.000000
+ 0.010000 0 0.000000
+ 0.100000 0 0.000000
+ 1.000000 0 0.000000
+ 10.000000 0 0.000000
+ 100.000000 0 0.000000
+ 1000.000000 0 0.000000
+ 10000.000000 0 0.000000
+ 100000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 10
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.000010 0 0.000000
+ 0.000100 0 0.000000
+ 0.001000 0 0.000000
+ 0.010000 0 0.000000
+ 0.100000 0 0.000000
+ 1.000000 11 4.050000
+ 10.000000 11 25.700000
+ 100.000000 0 0.000000
+ 1000.000000 0 0.000000
+ 10000.000000 0 0.000000
+ 100000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=7;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.000008 0 0.000000
+ 0.000059 0 0.000000
+ 0.000416 0 0.000000
+ 0.002915 0 0.000000
+ 0.020408 0 0.000000
+ 0.142857 0 0.000000
+ 1.000000 0 0.000000
+ 7.000000 0 0.000000
+ 49.000000 0 0.000000
+ 343.000000 0 0.000000
+ 2401.000000 0 0.000000
+ 16807.000000 0 0.000000
+ 117649.000000 0 0.000000
+ 823543.000000 0 0.000000
+5764801.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 7
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.000008 0 0.000000
+ 0.000059 0 0.000000
+ 0.000416 0 0.000000
+ 0.002915 0 0.000000
+ 0.020408 0 0.000000
+ 0.142857 0 0.000000
+ 1.000000 11 4.050000
+ 7.000000 11 25.700000
+ 49.000000 0 0.000000
+ 343.000000 0 0.000000
+ 2401.000000 0 0.000000
+ 16807.000000 0 0.000000
+ 117649.000000 0 0.000000
+ 823543.000000 0 0.000000
+5764801.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=156;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000041 0 0.000000
+ 0.006410 0 0.000000
+ 1.000000 0 0.000000
+ 156.000000 0 0.000000
+ 24336.000000 0 0.000000
+3796416.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 156
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000041 24 0.000000
+ 0.006410 0 0.000000
+ 1.000000 11 4.050000
+ 156.000000 11 25.700000
+ 24336.000000 0 0.000000
+3796416.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1000;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.001000 0 0.000000
+ 1.000000 0 0.000000
+ 1000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 1000
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.001000 0 0.000000
+ 1.000000 11 4.050000
+ 1000.000000 11 25.700000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1001;
+Warnings:
+Warning 1292 Truncated incorrect query_response_time_range_base value: '1001'
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.001000 0 0.000000
+ 1.000000 0 0.000000
+ 1000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 1000
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.001000 0 0.000000
+ 1.000000 11 4.050000
+ 1000.000000 11 25.700000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=default;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time.test b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.test
new file mode 100644
index 00000000000..5caec36fa96
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.test
@@ -0,0 +1,28 @@
+--source include/have_debug.inc
+
+# The file with expected results fits only to a run without
+# ps-protocol/sp-protocol/cursor-protocol/view-protocol.
+if (`SELECT $PS_PROTOCOL + $SP_PROTOCOL + $CURSOR_PROTOCOL
+ + $VIEW_PROTOCOL > 0`)
+{
+ --skip Test requires: ps-protocol/sp-protocol/cursor-protocol/view-protocol disabled
+}
+
+
+--let base=1
+--source query_response_time.inc
+--let base=2
+--source query_response_time.inc
+--let base=10
+--source query_response_time.inc
+--let base=7
+--source query_response_time.inc
+--let base=156
+--source query_response_time.inc
+--let base=1000
+--source query_response_time.inc
+--let base=1001
+--source query_response_time.inc
+
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=default;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/suite.opt b/plugin/query_response_time/mysql-test/query_response_time/suite.opt
new file mode 100644
index 00000000000..7283ce84e33
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$QUERY_RESPONSE_TIME_SO --plugin-query-response-time=ON --plugin-query-response-time-audit=ON
diff --git a/plugin/query_response_time/mysql-test/query_response_time/suite.pm b/plugin/query_response_time/mysql-test/query_response_time/suite.pm
new file mode 100644
index 00000000000..5b4983bc1f6
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/suite.pm
@@ -0,0 +1,14 @@
+package My::Suite::Query_response_time;
+
+@ISA = qw(My::Suite);
+
+return "No QUERY_RESPONSE_TIME plugin" unless
+ $ENV{QUERY_RESPONSE_TIME_SO} or
+ $::mysqld_variables{'query-response-time'} eq "ON";
+
+return "Not run for embedded server" if $::opt_embedded_server;
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/query_response_time/plugin.cc b/plugin/query_response_time/plugin.cc
new file mode 100644
index 00000000000..eddf65c491b
--- /dev/null
+++ b/plugin/query_response_time/plugin.cc
@@ -0,0 +1,164 @@
+/* Copyright (C) 2013 Percona and Sergey Vojtovich
+
+ 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 02110-1335 USA */
+
+#define MYSQL_SERVER
+#include <sql_class.h>
+#include <table.h>
+#include <sql_show.h>
+#include <mysql/plugin_audit.h>
+#include "query_response_time.h"
+
+
+ulong opt_query_response_time_range_base= QRT_DEFAULT_BASE;
+my_bool opt_query_response_time_stats= 0;
+static my_bool opt_query_response_time_flush= 0;
+
+
+static void query_response_time_flush_update(
+ MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *tgt __attribute__((unused)),
+ const void *save __attribute__((unused)))
+{
+ query_response_time_flush();
+}
+
+
+static MYSQL_SYSVAR_ULONG(range_base, opt_query_response_time_range_base,
+ PLUGIN_VAR_RQCMDARG,
+ "Select base of log for query_response_time ranges. WARNING: variable "
+ "change affect only after flush",
+ NULL, NULL, QRT_DEFAULT_BASE, 2, QRT_MAXIMUM_BASE, 1);
+static MYSQL_SYSVAR_BOOL(stats, opt_query_response_time_stats,
+ PLUGIN_VAR_OPCMDARG,
+ "Enable or disable query response time statisics collecting",
+ NULL, NULL, FALSE);
+static MYSQL_SYSVAR_BOOL(flush, opt_query_response_time_flush,
+ PLUGIN_VAR_NOCMDOPT,
+ "Update of this variable flushes statistics and re-reads "
+ "query_response_time_range_base",
+ NULL, query_response_time_flush_update, FALSE);
+#ifndef DBUG_OFF
+static MYSQL_THDVAR_ULONGLONG(exec_time_debug, PLUGIN_VAR_NOCMDOPT,
+ "Pretend queries take this many microseconds. When 0 (the default) use "
+ "the actual execution time. Used only for debugging.",
+ NULL, NULL, 0, 0, LONG_TIMEOUT, 1);
+#endif
+
+
+static struct st_mysql_sys_var *query_response_time_info_vars[]=
+{
+ MYSQL_SYSVAR(range_base),
+ MYSQL_SYSVAR(stats),
+ MYSQL_SYSVAR(flush),
+#ifndef DBUG_OFF
+ MYSQL_SYSVAR(exec_time_debug),
+#endif
+ NULL
+};
+
+
+ST_FIELD_INFO query_response_time_fields_info[] =
+{
+ { "TIME", QRT_TIME_STRING_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Time", 0 },
+ { "COUNT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, MY_I_S_UNSIGNED, "Count", 0 },
+ { "TOTAL", QRT_TIME_STRING_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Total", 0 },
+ { 0, 0, MYSQL_TYPE_NULL, 0, 0, 0, 0 }
+};
+
+
+static int query_response_time_info_init(void *p)
+{
+ ST_SCHEMA_TABLE *i_s_query_response_time= (ST_SCHEMA_TABLE *) p;
+ i_s_query_response_time->fields_info= query_response_time_fields_info;
+ i_s_query_response_time->fill_table= query_response_time_fill;
+ i_s_query_response_time->reset_table= query_response_time_flush;
+ query_response_time_init();
+ return 0;
+}
+
+
+static int query_response_time_info_deinit(void *arg __attribute__((unused)))
+{
+ opt_query_response_time_stats= 0;
+ query_response_time_free();
+ return 0;
+}
+
+
+static struct st_mysql_information_schema query_response_time_info_descriptor=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+
+static void query_response_time_audit_notify(MYSQL_THD thd,
+ unsigned int event_class,
+ const void *event)
+{
+ const struct mysql_event_general *event_general=
+ (const struct mysql_event_general *) event;
+ DBUG_ASSERT(event_class == MYSQL_AUDIT_GENERAL_CLASS);
+ if (event_general->event_subclass == MYSQL_AUDIT_GENERAL_STATUS &&
+ opt_query_response_time_stats)
+ {
+#ifndef DBUG_OFF
+ if (THDVAR(thd, exec_time_debug))
+ query_response_time_collect(thd->lex->sql_command != SQLCOM_SET_OPTION ?
+ THDVAR(thd, exec_time_debug) : 0);
+ else
+#endif
+ query_response_time_collect(thd->utime_after_query - thd->utime_after_lock);
+ }
+}
+
+
+static struct st_mysql_audit query_response_time_audit_descriptor=
+{
+ MYSQL_AUDIT_INTERFACE_VERSION, NULL, query_response_time_audit_notify,
+ { (unsigned long) MYSQL_AUDIT_GENERAL_CLASSMASK }
+};
+
+
+maria_declare_plugin(query_response_time)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &query_response_time_info_descriptor,
+ "QUERY_RESPONSE_TIME",
+ "Percona and Sergey Vojtovich",
+ "Query Response Time Distribution INFORMATION_SCHEMA Plugin",
+ PLUGIN_LICENSE_GPL,
+ query_response_time_info_init,
+ query_response_time_info_deinit,
+ 0x0100,
+ NULL,
+ query_response_time_info_vars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_AUDIT_PLUGIN,
+ &query_response_time_audit_descriptor,
+ "QUERY_RESPONSE_TIME_AUDIT",
+ "Percona and Sergey Vojtovich",
+ "Query Response Time Distribution Audit Plugin",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/query_response_time/query_response_time.cc b/plugin/query_response_time/query_response_time.cc
new file mode 100644
index 00000000000..10b9391d9da
--- /dev/null
+++ b/plugin/query_response_time/query_response_time.cc
@@ -0,0 +1,285 @@
+#include "mysql_version.h"
+#include "my_global.h"
+#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
+#include "mysql_com.h"
+#include "rpl_tblmap.h"
+#include "table.h"
+#include "field.h"
+#include "sql_show.h"
+#include "query_response_time.h"
+
+#define TIME_STRING_POSITIVE_POWER_LENGTH QRT_TIME_STRING_POSITIVE_POWER_LENGTH
+#define TIME_STRING_NEGATIVE_POWER_LENGTH 6
+#define TOTAL_STRING_POSITIVE_POWER_LENGTH QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH
+#define TOTAL_STRING_NEGATIVE_POWER_LENGTH 6
+#define MINIMUM_BASE 2
+#define MAXIMUM_BASE QRT_MAXIMUM_BASE
+#define POSITIVE_POWER_FILLER QRT_POSITIVE_POWER_FILLER
+#define NEGATIVE_POWER_FILLER QRT_NEGATIVE_POWER_FILLER
+#define TIME_OVERFLOW QRT_TIME_OVERFLOW
+#define DEFAULT_BASE QRT_DEFAULT_BASE
+
+#define do_xstr(s) do_str(s)
+#define do_str(s) #s
+#define do_format(filler,width) "%" filler width "lld"
+/*
+ Format strings for snprintf. Generate from:
+ POSITIVE_POWER_FILLER and TIME_STRING_POSITIVE_POWER_LENGTH
+ NEFATIVE_POWER_FILLER and TIME_STRING_NEGATIVE_POWER_LENGTH
+*/
+#define TIME_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TIME_STRING_POSITIVE_POWER_LENGTH))
+#define TIME_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TIME_STRING_NEGATIVE_POWER_LENGTH))
+#define TIME_STRING_FORMAT TIME_STRING_POSITIVE_POWER_FORMAT "." TIME_STRING_NEGATIVE_POWER_FORMAT
+
+#define TOTAL_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TOTAL_STRING_POSITIVE_POWER_LENGTH))
+#define TOTAL_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TOTAL_STRING_NEGATIVE_POWER_LENGTH))
+#define TOTAL_STRING_FORMAT TOTAL_STRING_POSITIVE_POWER_FORMAT "." TOTAL_STRING_NEGATIVE_POWER_FORMAT
+
+#define TIME_STRING_LENGTH QRT_TIME_STRING_LENGTH
+#define TIME_STRING_BUFFER_LENGTH (TIME_STRING_LENGTH + 1 /* '\0' */)
+
+#define TOTAL_STRING_LENGTH QRT_TOTAL_STRING_LENGTH
+#define TOTAL_STRING_BUFFER_LENGTH (TOTAL_STRING_LENGTH + 1 /* '\0' */)
+
+/*
+ Calculate length of "log linear"
+ 1)
+ (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH) < (MINIMUM_BASE ^ (result + 1))
+
+ 2)
+ (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH)
+ and
+ (MINIMUM_BASE ^ (result + 1)) > (10 ^ STRING_POWER_LENGTH)
+
+ 3)
+ result <= LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
+ result + 1 > LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
+
+ 4) STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10) - 1 < result <= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
+
+ MINIMUM_BASE= 2 always, LOG(MINIMUM_BASE,10)= 3.3219280948873626, result= (int)3.3219280948873626 * STRING_POWER_LENGTH
+
+ Last counter always use for time overflow
+*/
+#define POSITIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_POSITIVE_POWER_LENGTH))
+#define NEGATIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_NEGATIVE_POWER_LENGTH))
+#define OVERALL_POWER_COUNT (NEGATIVE_POWER_COUNT + 1 + POSITIVE_POWER_COUNT)
+
+#define MILLION ((unsigned long)1000 * 1000)
+
+namespace query_response_time
+{
+
+class utility
+{
+public:
+ utility() : m_base(0)
+ {
+ m_max_dec_value= MILLION;
+ for(int i= 0; TIME_STRING_POSITIVE_POWER_LENGTH > i; ++i)
+ m_max_dec_value *= 10;
+ setup(DEFAULT_BASE);
+ }
+public:
+ uint base() const { return m_base; }
+ uint negative_count() const { return m_negative_count; }
+ uint positive_count() const { return m_positive_count; }
+ uint bound_count() const { return m_bound_count; }
+ ulonglong max_dec_value() const { return m_max_dec_value; }
+ ulonglong bound(uint index) const { return m_bound[ index ]; }
+public:
+ void setup(uint base)
+ {
+ if(base != m_base)
+ {
+ m_base= base;
+
+ const ulonglong million= 1000 * 1000;
+ ulonglong value= million;
+ m_negative_count= 0;
+ while(value > 0)
+ {
+ m_negative_count += 1;
+ value /= m_base;
+ }
+ m_negative_count -= 1;
+
+ value= million;
+ m_positive_count= 0;
+ while(value < m_max_dec_value)
+ {
+ m_positive_count += 1;
+ value *= m_base;
+ }
+ m_bound_count= m_negative_count + m_positive_count;
+
+ value= million;
+ for(uint i= 0; i < m_negative_count; ++i)
+ {
+ value /= m_base;
+ m_bound[m_negative_count - i - 1]= value;
+ }
+ value= million;
+ for(uint i= 0; i < m_positive_count; ++i)
+ {
+ m_bound[m_negative_count + i]= value;
+ value *= m_base;
+ }
+ }
+ }
+private:
+ uint m_base;
+ uint m_negative_count;
+ uint m_positive_count;
+ uint m_bound_count;
+ ulonglong m_max_dec_value; /* for TIME_STRING_POSITIVE_POWER_LENGTH=7 is 10000000 */
+ ulonglong m_bound[OVERALL_POWER_COUNT];
+};
+
+static
+void print_time(char* buffer, std::size_t buffer_size, const char* format,
+ uint64 value)
+{
+ ulonglong second= (value / MILLION);
+ ulonglong microsecond= (value % MILLION);
+ my_snprintf(buffer, buffer_size, format, second, microsecond);
+}
+
+class time_collector
+{
+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:
+ void flush()
+ {
+ memset((void*)&m_count,0,sizeof(m_count));
+ memset((void*)&m_total,0,sizeof(m_total));
+ }
+ void collect(uint64 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);
+ break;
+ }
+ }
+ }
+private:
+ utility* m_utility;
+ uint32 m_count[OVERALL_POWER_COUNT + 1];
+ uint64 m_total[OVERALL_POWER_COUNT + 1];
+};
+
+class collector
+{
+public:
+ collector() : m_time(m_utility)
+ {
+ m_utility.setup(DEFAULT_BASE);
+ m_time.flush();
+ }
+public:
+ void flush()
+ {
+ m_utility.setup(opt_query_response_time_range_base);
+ m_time.flush();
+ }
+ int fill(THD* thd, TABLE_LIST *tables, COND *cond)
+ {
+ DBUG_ENTER("fill_schema_query_response_time");
+ TABLE *table= static_cast<TABLE*>(tables->table);
+ Field **fields= table->field;
+ for(uint i= 0, count= bound_count() + 1 /* with overflow */; count > i; ++i)
+ {
+ char time[TIME_STRING_BUFFER_LENGTH];
+ char total[TOTAL_STRING_BUFFER_LENGTH];
+ if(i == bound_count())
+ {
+ assert(sizeof(TIME_OVERFLOW) <= TIME_STRING_BUFFER_LENGTH);
+ assert(sizeof(TIME_OVERFLOW) <= TOTAL_STRING_BUFFER_LENGTH);
+ memcpy(time,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
+ memcpy(total,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
+ }
+ else
+ {
+ print_time(time, sizeof(time), TIME_STRING_FORMAT, this->bound(i));
+ print_time(total, sizeof(total), TOTAL_STRING_FORMAT, this->total(i));
+ }
+ fields[0]->store(time,strlen(time),system_charset_info);
+ fields[1]->store(this->count(i));
+ fields[2]->store(total,strlen(total),system_charset_info);
+ if (schema_table_store_record(thd, table))
+ {
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+ }
+ void collect(ulonglong time)
+ {
+ m_time.collect(time);
+ }
+ uint bound_count() const
+ {
+ return m_utility.bound_count();
+ }
+ ulonglong bound(uint index)
+ {
+ return m_utility.bound(index);
+ }
+ ulonglong count(uint index)
+ {
+ return m_time.count(index);
+ }
+ ulonglong total(uint index)
+ {
+ return m_time.total(index);
+ }
+private:
+ utility m_utility;
+ time_collector m_time;
+};
+
+static collector g_collector;
+
+} // namespace query_response_time
+
+void query_response_time_init()
+{
+}
+
+void query_response_time_free()
+{
+ query_response_time::g_collector.flush();
+}
+
+int query_response_time_flush()
+{
+ query_response_time::g_collector.flush();
+ return 0;
+}
+void query_response_time_collect(ulonglong query_time)
+{
+ query_response_time::g_collector.collect(query_time);
+}
+
+int query_response_time_fill(THD* thd, TABLE_LIST *tables, COND *cond)
+{
+ return query_response_time::g_collector.fill(thd,tables,cond);
+}
+#endif // HAVE_RESPONSE_TIME_DISTRIBUTION
diff --git a/plugin/query_response_time/query_response_time.h b/plugin/query_response_time/query_response_time.h
new file mode 100644
index 00000000000..f59639f00a7
--- /dev/null
+++ b/plugin/query_response_time/query_response_time.h
@@ -0,0 +1,67 @@
+#ifndef QUERY_RESPONSE_TIME_H
+#define QUERY_RESPONSE_TIME_H
+
+/*
+ Settings for query response time
+*/
+
+/*
+ Maximum string length for (10 ^ (-1 * QRT_STRING_NEGATIVE_POWER_LENGTH)) in text representation.
+ Example: for 6 is 0.000001
+ Always 2
+
+ Maximum string length for (10 ^ (QRT_STRING_POSITIVE_POWER_LENGTH + 1) - 1) in text representation.
+ Example: for 7 is 9999999.0
+*/
+#define QRT_TIME_STRING_POSITIVE_POWER_LENGTH 7
+#define QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH 7
+
+/*
+ Minimum base for log - ALWAYS 2
+ Maximum base for log:
+*/
+#define QRT_MAXIMUM_BASE 1000
+
+/*
+ Filler for whole number (positive power)
+ Example: for
+ QRT_POSITIVE_POWER_FILLER ' '
+ QRT_POSITIVE_POWER_LENGTH 7
+ and number 7234 result is:
+ ' 7234'
+*/
+#define QRT_POSITIVE_POWER_FILLER ""
+/*
+ Filler for fractional number. Similiary to whole number
+*/
+#define QRT_NEGATIVE_POWER_FILLER "0"
+
+/*
+ Message if time too big for statistic collecting (very long query)
+*/
+#define QRT_TIME_OVERFLOW "TOO LONG"
+
+#define QRT_DEFAULT_BASE 10
+
+#define QRT_TIME_STRING_LENGTH \
+ MY_MAX( (QRT_TIME_STRING_POSITIVE_POWER_LENGTH + 1 /* '.' */ + 6 /*QRT_TIME_STRING_NEGATIVE_POWER_LENGTH*/), \
+ (sizeof(QRT_TIME_OVERFLOW) - 1) )
+
+#define QRT_TOTAL_STRING_LENGTH \
+ MY_MAX( (QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH + 1 /* '.' */ + 6 /*QRT_TOTAL_STRING_NEGATIVE_POWER_LENGTH*/), \
+ (sizeof(QRT_TIME_OVERFLOW) - 1) )
+
+extern ST_SCHEMA_TABLE query_response_time_table;
+
+#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
+extern void query_response_time_init ();
+extern void query_response_time_free ();
+extern int query_response_time_flush ();
+extern void query_response_time_collect(ulonglong query_time);
+extern int query_response_time_fill (THD* thd, TABLE_LIST *tables, COND *cond);
+
+extern ulong opt_query_response_time_range_base;
+extern my_bool opt_query_response_time_stats;
+#endif // HAVE_RESPONSE_TIME_DISTRIBUTION
+
+#endif // QUERY_RESPONSE_TIME_H
diff --git a/plugin/semisync/CMakeLists.txt b/plugin/semisync/CMakeLists.txt
index d2d3327fb2e..1def8fdc682 100644
--- a/plugin/semisync/CMakeLists.txt
+++ b/plugin/semisync/CMakeLists.txt
@@ -17,11 +17,12 @@ SET(SEMISYNC_MASTER_SOURCES
semisync.cc semisync_master.cc semisync_master_plugin.cc
semisync.h semisync_master.h)
-MYSQL_ADD_PLUGIN(semisync_master ${SEMISYNC_MASTER_SOURCES}
- MODULE_ONLY MODULE_OUTPUT_NAME "semisync_master")
+MYSQL_ADD_PLUGIN(semisync_master ${SEMISYNC_MASTER_SOURCES}
+ RECOMPILE_FOR_EMBEDDED)
SET(SEMISYNC_SLAVE_SOURCES semisync.cc semisync_slave.cc
semisync_slave_plugin.cc semisync.h semisync_slave.h )
-MYSQL_ADD_PLUGIN(semisync_slave ${SEMISYNC_SLAVE_SOURCES}
- MODULE_ONLY MODULE_OUTPUT_NAME "semisync_slave")
+
+MYSQL_ADD_PLUGIN(semisync_slave ${SEMISYNC_SLAVE_SOURCES}
+ RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/semisync/semisync.h b/plugin/semisync/semisync.h
index 70ab8ce9cc3..abd0bb0787c 100644
--- a/plugin/semisync/semisync.h
+++ b/plugin/semisync/semisync.h
@@ -21,11 +21,10 @@
#define MYSQL_SERVER
#define HAVE_REPLICATION
+#include <my_pthread.h>
#include <sql_priv.h>
+#include <sql_class.h>
#include "unireg.h"
-#include <my_global.h>
-#include <my_pthread.h>
-#include <mysql/plugin.h>
#include <replication.h>
#include "log.h" /* sql_print_information */
diff --git a/plugin/semisync/semisync_master.cc b/plugin/semisync/semisync_master.cc
index 5175385b884..cd80e86140d 100644
--- a/plugin/semisync/semisync_master.cc
+++ b/plugin/semisync/semisync_master.cc
@@ -24,6 +24,8 @@
/* This indicates whether semi-synchronous replication is enabled. */
char rpl_semi_sync_master_enabled;
+unsigned long rpl_semi_sync_master_wait_point =
+ SEMI_SYNC_MASTER_WAIT_POINT_AFTER_STORAGE_COMMIT;
unsigned long rpl_semi_sync_master_timeout;
unsigned long rpl_semi_sync_master_trace_level;
char rpl_semi_sync_master_status = 0;
@@ -429,12 +431,13 @@ int ReplSemiSyncMaster::disableMaster()
return 0;
}
-ReplSemiSyncMaster::~ReplSemiSyncMaster()
+void ReplSemiSyncMaster::cleanup()
{
if (init_done_)
{
mysql_mutex_destroy(&LOCK_binlog_);
mysql_cond_destroy(&COND_binlog_send_);
+ init_done_= 0;
}
delete active_tranxs_;
@@ -608,7 +611,7 @@ int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name,
struct timespec start_ts;
struct timespec abstime;
int wait_result;
- const char *old_msg= 0;
+ PSI_stage_info old_stage;
set_timespec(start_ts, 0);
@@ -617,8 +620,9 @@ int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name,
lock();
/* This must be called after acquired the lock */
- old_msg= thd_enter_cond(NULL, &COND_binlog_send_, &LOCK_binlog_,
- "Waiting for semi-sync ACK from slave");
+ THD_ENTER_COND(NULL, &COND_binlog_send_, &LOCK_binlog_,
+ & stage_waiting_for_semi_sync_ack_from_slave,
+ & old_stage);
/* This is the real check inside the mutex. */
if (!getMasterEnabled() || !is_on())
@@ -631,7 +635,7 @@ int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name,
(int)is_on());
}
- while (is_on() && !thd_killed(NULL))
+ while (is_on() && !thd_killed(current_thd))
{
if (reply_file_name_inited_)
{
@@ -742,9 +746,10 @@ int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name,
/*
At this point, the binlog file and position of this transaction
must have been removed from ActiveTranx.
+ active_tranxs_ may be NULL if someone disabled semi sync during
+ cond_timewait()
*/
- assert(thd_killed(NULL) ||
- !getMasterEnabled() ||
+ assert(thd_killed(current_thd) || !active_tranxs_ ||
!active_tranxs_->is_tranx_end_pos(trx_wait_binlog_name,
trx_wait_binlog_pos));
@@ -757,7 +762,7 @@ int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name,
/* The lock held will be released by thd_exit_cond, so no need to
call unlock() here */
- thd_exit_cond(NULL, old_msg);
+ THD_EXIT_COND(NULL, & old_stage);
}
return function_exit(kWho, 0);
@@ -1045,7 +1050,6 @@ int ReplSemiSyncMaster::readSlaveReply(NET *net, uint32 server_id,
int result = -1;
struct timespec start_ts;
ulong trc_level = trace_level_;
-
LINT_INIT_STRUCT(start_ts);
function_enter(kWho);
diff --git a/plugin/semisync/semisync_master.h b/plugin/semisync/semisync_master.h
index cd1c0507039..23d3140bf2f 100644
--- a/plugin/semisync/semisync_master.h
+++ b/plugin/semisync/semisync_master.h
@@ -26,6 +26,8 @@ extern PSI_mutex_key key_ss_mutex_LOCK_binlog_;
extern PSI_cond_key key_ss_cond_COND_binlog_send_;
#endif
+extern PSI_stage_info stage_waiting_for_semi_sync_ack_from_slave;
+
struct TranxNode {
char log_name_[FN_REFLEN];
my_off_t log_pos_;
@@ -100,7 +102,7 @@ public:
it are in use. A new Block is allocated and is put into the rear of the
Block link table if no Block is free.
- @return Return a TranxNode *, or NULL if an error occured.
+ @return Return a TranxNode *, or NULL if an error occurred.
*/
TranxNode *allocate_node()
{
@@ -132,7 +134,7 @@ public:
/**
All nodes are freed.
- @return Return 0, or 1 if an error occured.
+ @return Return 0, or 1 if an error occurred.
*/
int free_all_nodes()
{
@@ -148,7 +150,7 @@ public:
@param node All nodes before 'node' will be freed
- @return Return 0, or 1 if an error occured.
+ @return Return 0, or 1 if an error occurred.
*/
int free_nodes_before(TranxNode* node)
{
@@ -453,7 +455,9 @@ class ReplSemiSyncMaster
public:
ReplSemiSyncMaster();
- ~ReplSemiSyncMaster();
+ ~ReplSemiSyncMaster() {}
+
+ void cleanup();
bool getMasterEnabled() {
return master_enabled_;
@@ -590,9 +594,15 @@ class ReplSemiSyncMaster
int resetMaster();
};
+enum rpl_semi_sync_master_wait_point_t {
+ SEMI_SYNC_MASTER_WAIT_POINT_AFTER_BINLOG_SYNC,
+ SEMI_SYNC_MASTER_WAIT_POINT_AFTER_STORAGE_COMMIT,
+};
+
/* System and status variables for the master component */
extern char rpl_semi_sync_master_enabled;
extern char rpl_semi_sync_master_status;
+extern unsigned long rpl_semi_sync_master_wait_point;
extern unsigned long rpl_semi_sync_master_clients;
extern unsigned long rpl_semi_sync_master_timeout;
extern unsigned long rpl_semi_sync_master_trace_level;
diff --git a/plugin/semisync/semisync_master_plugin.cc b/plugin/semisync/semisync_master_plugin.cc
index 4a085233939..4432b829c87 100644
--- a/plugin/semisync/semisync_master_plugin.cc
+++ b/plugin/semisync/semisync_master_plugin.cc
@@ -19,7 +19,7 @@
#include "semisync_master.h"
#include "sql_class.h" // THD
-ReplSemiSyncMaster repl_semisync;
+static ReplSemiSyncMaster repl_semisync;
C_MODE_START
@@ -48,8 +48,27 @@ int repl_semi_request_commit(Trans_param *param)
return 0;
}
+int repl_semi_report_binlog_sync(Binlog_storage_param *param,
+ const char *log_file,
+ my_off_t log_pos, uint32 flags)
+{
+ int error= 0;
+ if (rpl_semi_sync_master_wait_point ==
+ SEMI_SYNC_MASTER_WAIT_POINT_AFTER_BINLOG_SYNC)
+ {
+ error = repl_semisync.commitTrx(log_file, log_pos);
+ }
+
+ return error;
+}
+
int repl_semi_report_commit(Trans_param *param)
{
+ if (rpl_semi_sync_master_wait_point !=
+ SEMI_SYNC_MASTER_WAIT_POINT_AFTER_STORAGE_COMMIT)
+ {
+ return 0;
+ }
bool is_real_trans= param->flags & TRANS_IS_REAL_TRANS;
@@ -175,6 +194,33 @@ static MYSQL_SYSVAR_BOOL(enabled, rpl_semi_sync_master_enabled,
&fix_rpl_semi_sync_master_enabled, // update
0);
+/* NOTE: must match order of rpl_semi_sync_master_wait_point_t */
+static const char *rpl_semi_sync_master_wait_point_names[] =
+{
+ "AFTER_SYNC",
+ "AFTER_COMMIT",
+ NullS
+};
+
+static TYPELIB rpl_semi_sync_master_wait_point_typelib =
+{
+ array_elements(rpl_semi_sync_master_wait_point_names) - 1,
+ "",
+ rpl_semi_sync_master_wait_point_names,
+ NULL
+};
+
+static MYSQL_SYSVAR_ENUM(
+ wait_point,
+ rpl_semi_sync_master_wait_point,
+ PLUGIN_VAR_RQCMDARG,
+ "Should transaction wait for semi-sync ack after having synced binlog, "
+ "or after having committed in storeage engine.",
+ NULL, // check
+ NULL, // update
+ SEMI_SYNC_MASTER_WAIT_POINT_AFTER_STORAGE_COMMIT,
+ &rpl_semi_sync_master_wait_point_typelib);
+
static MYSQL_SYSVAR_ULONG(timeout, rpl_semi_sync_master_timeout,
PLUGIN_VAR_OPCMDARG,
"The timeout value (in ms) for semi-synchronous replication in the master",
@@ -198,6 +244,7 @@ static MYSQL_SYSVAR_ULONG(trace_level, rpl_semi_sync_master_trace_level,
static SYS_VAR* semi_sync_master_system_vars[]= {
MYSQL_SYSVAR(enabled),
+ MYSQL_SYSVAR(wait_point),
MYSQL_SYSVAR(timeout),
MYSQL_SYSVAR(wait_no_slave),
MYSQL_SYSVAR(trace_level),
@@ -256,6 +303,7 @@ Binlog_storage_observer storage_observer = {
sizeof(Binlog_storage_observer), // len
repl_semi_report_binlog_update, // report_update
+ repl_semi_report_binlog_sync, // after_sync
};
Binlog_transmit_observer transmit_observer = {
@@ -297,10 +345,10 @@ DEF_SHOW_FUNC(avg_trx_wait_time, SHOW_LONG)
static SHOW_VAR semi_sync_master_status_vars[]= {
{"Rpl_semi_sync_master_status",
(char*) &SHOW_FNAME(status),
- SHOW_FUNC},
+ SHOW_SIMPLE_FUNC},
{"Rpl_semi_sync_master_clients",
(char*) &SHOW_FNAME(clients),
- SHOW_FUNC},
+ SHOW_SIMPLE_FUNC},
{"Rpl_semi_sync_master_yes_tx",
(char*) &rpl_semi_sync_master_yes_transactions,
SHOW_LONG},
@@ -309,7 +357,7 @@ static SHOW_VAR semi_sync_master_status_vars[]= {
SHOW_LONG},
{"Rpl_semi_sync_master_wait_sessions",
(char*) &SHOW_FNAME(wait_sessions),
- SHOW_FUNC},
+ SHOW_SIMPLE_FUNC},
{"Rpl_semi_sync_master_no_times",
(char*) &rpl_semi_sync_master_off_times,
SHOW_LONG},
@@ -321,22 +369,22 @@ static SHOW_VAR semi_sync_master_status_vars[]= {
SHOW_LONG},
{"Rpl_semi_sync_master_tx_wait_time",
(char*) &SHOW_FNAME(trx_wait_time),
- SHOW_FUNC},
+ SHOW_SIMPLE_FUNC},
{"Rpl_semi_sync_master_tx_waits",
(char*) &SHOW_FNAME(trx_wait_num),
- SHOW_FUNC},
+ SHOW_SIMPLE_FUNC},
{"Rpl_semi_sync_master_tx_avg_wait_time",
(char*) &SHOW_FNAME(avg_trx_wait_time),
- SHOW_FUNC},
+ SHOW_SIMPLE_FUNC},
{"Rpl_semi_sync_master_net_wait_time",
(char*) &SHOW_FNAME(net_wait_time),
- SHOW_FUNC},
+ SHOW_SIMPLE_FUNC},
{"Rpl_semi_sync_master_net_waits",
(char*) &SHOW_FNAME(net_wait_num),
- SHOW_FUNC},
+ SHOW_SIMPLE_FUNC},
{"Rpl_semi_sync_master_net_avg_wait_time",
(char*) &SHOW_FNAME(avg_net_wait_time),
- SHOW_FUNC},
+ SHOW_SIMPLE_FUNC},
{NULL, NULL, SHOW_LONG},
};
@@ -354,20 +402,30 @@ static PSI_cond_info all_semisync_conds[]=
{
{ &key_ss_cond_COND_binlog_send_, "COND_binlog_send_", 0}
};
+#endif /* HAVE_PSI_INTERFACE */
+
+PSI_stage_info stage_waiting_for_semi_sync_ack_from_slave=
+{ 0, "Waiting for semi-sync ACK from slave", 0};
+
+#ifdef HAVE_PSI_INTERFACE
+PSI_stage_info *all_semisync_stages[]=
+{
+ & stage_waiting_for_semi_sync_ack_from_slave
+};
static void init_semisync_psi_keys(void)
{
const char* category= "semisync";
int count;
- if (PSI_server == NULL)
- return;
-
count= array_elements(all_semisync_mutexes);
- PSI_server->register_mutex(category, all_semisync_mutexes, count);
+ mysql_mutex_register(category, all_semisync_mutexes, count);
count= array_elements(all_semisync_conds);
- PSI_server->register_cond(category, all_semisync_conds, count);
+ mysql_cond_register(category, all_semisync_conds, count);
+
+ count= array_elements(all_semisync_stages);
+ mysql_stage_register(category, all_semisync_stages, count);
}
#endif /* HAVE_PSI_INTERFACE */
@@ -405,6 +463,7 @@ static int semi_sync_master_plugin_deinit(void *p)
sql_print_error("unregister_binlog_transmit_observer failed");
return 1;
}
+ repl_semisync.cleanup();
sql_print_information("unregister_replicator OK");
return 0;
}
@@ -416,7 +475,7 @@ struct Mysql_replication semi_sync_master_plugin= {
/*
Plugin library descriptor
*/
-mysql_declare_plugin(semi_sync_master)
+maria_declare_plugin(semisync_master)
{
MYSQL_REPLICATION_PLUGIN,
&semi_sync_master_plugin,
@@ -429,7 +488,8 @@ mysql_declare_plugin(semi_sync_master)
0x0100 /* 1.0 */,
semi_sync_master_status_vars, /* status variables */
semi_sync_master_system_vars, /* system variables */
- NULL, /* config options */
- 0, /* flags */
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
}
-mysql_declare_plugin_end;
+maria_declare_plugin_end;
+
diff --git a/plugin/semisync/semisync_slave_plugin.cc b/plugin/semisync/semisync_slave_plugin.cc
index 1d62bbdf7fc..b7a4c964c80 100644
--- a/plugin/semisync/semisync_slave_plugin.cc
+++ b/plugin/semisync/semisync_slave_plugin.cc
@@ -19,7 +19,7 @@
#include "semisync_slave.h"
#include <mysql.h>
-ReplSemiSyncSlave repl_semisync;
+static ReplSemiSyncSlave repl_semisync;
/*
indicate whether or not the slave should send a reply to the master.
@@ -213,7 +213,7 @@ struct Mysql_replication semi_sync_slave_plugin= {
/*
Plugin library descriptor
*/
-mysql_declare_plugin(semi_sync_slave)
+maria_declare_plugin(semisync_slave)
{
MYSQL_REPLICATION_PLUGIN,
&semi_sync_slave_plugin,
@@ -226,7 +226,8 @@ mysql_declare_plugin(semi_sync_slave)
0x0100 /* 1.0 */,
semi_sync_slave_status_vars, /* status variables */
semi_sync_slave_system_vars, /* system variables */
- NULL, /* config options */
- 0, /* flags */
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
}
-mysql_declare_plugin_end;
+maria_declare_plugin_end;
+
diff --git a/plugin/server_audit/CMakeLists.txt b/plugin/server_audit/CMakeLists.txt
index 21b1df57acf..8a5333cfb9f 100644
--- a/plugin/server_audit/CMakeLists.txt
+++ b/plugin/server_audit/CMakeLists.txt
@@ -13,7 +13,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
-SET(SERVER_AUDIT_SOURCES
- server_audit.c test_audit_v4.c plugin_audit_v4.h)
+SET(SOURCES server_audit.c test_audit_v4.c plugin_audit_v4.h)
- MYSQL_ADD_PLUGIN(server_audit ${SERVER_AUDIT_SOURCES} MODULE_ONLY)
+MYSQL_ADD_PLUGIN(server_audit ${SOURCES} MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/server_audit/plugin_audit_v4.h b/plugin/server_audit/plugin_audit_v4.h
index e9f00d66ee4..a2a38806f4f 100644
--- a/plugin/server_audit/plugin_audit_v4.h
+++ b/plugin/server_audit/plugin_audit_v4.h
@@ -232,7 +232,7 @@ struct mysql_event_parse
/** input: the original query text */
MYSQL_LEX_CSTRING query;
- /** output: returns the null-terminated rewriten query allocated by my_malloc() */
+ /** output: returns the null-terminated rewritten query allocated by my_malloc() */
MYSQL_LEX_CSTRING *rewritten_query;
};
diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c
index 634a804d24c..c9e7e3a532a 100644
--- a/plugin/server_audit/server_audit.c
+++ b/plugin/server_audit/server_audit.c
@@ -97,13 +97,11 @@ static void closelog() {}
#define FLOGGER_NO_PSI
/* How to access the pthread_mutex in mysql_mutex_t */
-//#ifdef SAFE_MUTEX
-//#define mysql_mutex_real_mutex(A) &(A)->m_mutex.mutex
-//#elif defined(MY_PTHREAD_FASTMUTEX)
-//#define mysql_mutex_real_mutex(A) &(A)->m_mutex.mutex
-//#else
+#if defined(SAFE_MUTEX) || defined(MY_PTHREAD_FASTMUTEX)
+#define mysql_mutex_real_mutex(A) &(A)->m_mutex.mutex
+#else
#define mysql_mutex_real_mutex(A) &(A)->m_mutex
-//#endif
+#endif
#define flogger_mutex_init(A,B,C) do{}while(0)
#define flogger_mutex_destroy(A) do{}while(0)
@@ -1058,14 +1056,16 @@ static int start_logging()
}
error_header();
fprintf(stderr, "logging started to the file %s.\n", alt_fname);
- strncpy(current_log_buf, alt_fname, sizeof(current_log_buf));
+ strncpy(current_log_buf, alt_fname, sizeof(current_log_buf)-1);
+ current_log_buf[sizeof(current_log_buf)-1]= 0;
}
else if (output_type == OUTPUT_SYSLOG)
{
openlog(syslog_ident, LOG_NOWAIT, syslog_facility_codes[syslog_facility]);
error_header();
fprintf(stderr, "logging started to the syslog.\n");
- strncpy(current_log_buf, "[SYSLOG]", sizeof(current_log_buf));
+ strncpy(current_log_buf, "[SYSLOG]", sizeof(current_log_buf)-1);
+ compile_time_assert(sizeof current_log_buf > sizeof "[SYSLOG]");
}
is_active= 1;
return 0;
@@ -1179,7 +1179,7 @@ static void setup_connection_initdb(struct connection_info *cn,
}
else
{
- get_str_n(cn->user, &cn->user_length, sizeof(cn->db),
+ get_str_n(cn->user, &cn->user_length, sizeof(cn->user),
uh_buffer, user_len);
get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
uh_buffer+user_len+1, host_len);
@@ -1232,7 +1232,7 @@ static void setup_connection_query(struct connection_info *cn,
}
else
{
- get_str_n(cn->user, &cn->user_length, sizeof(cn->db),
+ get_str_n(cn->user, &cn->user_length, sizeof(cn->user),
uh_buffer, user_len);
get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
uh_buffer+user_len+1, host_len);
@@ -1985,7 +1985,7 @@ void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev)
/* That one is important as this function can be called with */
/* &lock_operations locked when the server logs an error reported */
/* by this plugin. */
- if (internal_stop_logging)
+ if (!thd || internal_stop_logging)
return;
flogger_mutex_lock(&lock_operations);
@@ -2601,7 +2601,8 @@ static void update_file_path(MYSQL_THD thd,
internal_stop_logging= 0;
}
- strncpy(path_buffer, new_name, sizeof(path_buffer));
+ strncpy(path_buffer, new_name, sizeof(path_buffer)-1);
+ path_buffer[sizeof(path_buffer)-1]= 0;
file_path= path_buffer;
exit_func:
internal_stop_logging= 0;
@@ -2653,7 +2654,8 @@ static void update_incl_users(MYSQL_THD thd,
if (!maria_55_started || !debug_server_started)
flogger_mutex_lock(&lock_operations);
mark_always_logged(thd);
- strncpy(incl_user_buffer, new_users, sizeof(incl_user_buffer));
+ strncpy(incl_user_buffer, new_users, sizeof(incl_user_buffer)-1);
+ incl_user_buffer[sizeof(incl_user_buffer)-1]= 0;
incl_users= incl_user_buffer;
user_coll_fill(&incl_user_coll, incl_users, &excl_user_coll, 1);
error_header();
@@ -2671,7 +2673,8 @@ static void update_excl_users(MYSQL_THD thd __attribute__((unused)),
if (!maria_55_started || !debug_server_started)
flogger_mutex_lock(&lock_operations);
mark_always_logged(thd);
- strncpy(excl_user_buffer, new_users, sizeof(excl_user_buffer));
+ strncpy(excl_user_buffer, new_users, sizeof(excl_user_buffer)-1);
+ excl_user_buffer[sizeof(excl_user_buffer)-1]= 0;
excl_users= excl_user_buffer;
user_coll_fill(&excl_user_coll, excl_users, &incl_user_coll, 0);
error_header();
@@ -2802,7 +2805,8 @@ static void update_syslog_ident(MYSQL_THD thd __attribute__((unused)),
void *var_ptr __attribute__((unused)), const void *save)
{
char *new_ident= (*(char **) save) ? *(char **) save : empty_str;
- strncpy(syslog_ident_buffer, new_ident, sizeof(syslog_ident_buffer));
+ strncpy(syslog_ident_buffer, new_ident, sizeof(syslog_ident_buffer)-1);
+ syslog_ident_buffer[sizeof(syslog_ident_buffer)-1]= 0;
syslog_ident= syslog_ident_buffer;
error_header();
fprintf(stderr, "SYSYLOG ident was changed to '%s'\n", syslog_ident);
diff --git a/plugin/simple_password_check/CMakeLists.txt b/plugin/simple_password_check/CMakeLists.txt
new file mode 100644
index 00000000000..f41024d2c8e
--- /dev/null
+++ b/plugin/simple_password_check/CMakeLists.txt
@@ -0,0 +1 @@
+MYSQL_ADD_PLUGIN(simple_password_check simple_password_check.c MODULE_ONLY)
diff --git a/plugin/simple_password_check/simple_password_check.c b/plugin/simple_password_check/simple_password_check.c
new file mode 100644
index 00000000000..32f3ba6c703
--- /dev/null
+++ b/plugin/simple_password_check/simple_password_check.c
@@ -0,0 +1,116 @@
+/* Copyright (c) 2014, Sergei Golubchik and MariaDB
+ Copyright (c) 2012, 2013, Oracle and/or its affiliates.
+
+ 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_sys.h>
+#include <mysqld_error.h>
+#include <mysql/plugin_password_validation.h>
+#include <ctype.h>
+#include <string.h>
+#include <my_attribute.h>
+
+static unsigned min_length, min_digits, min_letters, min_others;
+
+static int validate(MYSQL_LEX_STRING *username, MYSQL_LEX_STRING *password)
+{
+ unsigned digits=0 , uppers=0 , lowers=0, others=0, length= password->length;
+ const char *ptr= password->str, *end= ptr + length;
+
+ if (strncmp(password->str, username->str, length) == 0)
+ return 1;
+
+ /* everything non-ascii is the "other" character and is good for the password */
+ for(; ptr < end; ptr++)
+ {
+ if (isdigit(*ptr))
+ digits++;
+ else if (isupper(*ptr))
+ uppers++;
+ else if (islower(*ptr))
+ lowers++;
+ else
+ others++;
+ }
+ /* remember TRUE means the password failed the validation */
+ return length < min_length ||
+ uppers < min_letters ||
+ lowers < min_letters ||
+ digits < min_digits ||
+ others < min_others;
+}
+
+static void fix_min_length(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr, const void *save)
+{
+ uint new_min_length;
+ *((unsigned int *)var_ptr)= *((unsigned int *)save);
+ new_min_length= min_digits + 2 * min_letters + min_others;
+ if (min_length < new_min_length)
+ {
+ my_printf_error(ER_TRUNCATED_WRONG_VALUE,
+ "Adjusted the value of simple_password_check_minimal_length "
+ "from %u to %u", ME_JUST_WARNING,
+ min_length, new_min_length);
+ min_length= new_min_length;
+ }
+}
+
+static MYSQL_SYSVAR_UINT(minimal_length, min_length, PLUGIN_VAR_RQCMDARG,
+ "Minimal required password length", NULL, fix_min_length, 8, 0, 1000, 1);
+
+static MYSQL_SYSVAR_UINT(digits, min_digits, PLUGIN_VAR_RQCMDARG,
+ "Minimal required number of digits", NULL, fix_min_length, 1, 0, 1000, 1);
+
+static MYSQL_SYSVAR_UINT(letters_same_case, min_letters, PLUGIN_VAR_RQCMDARG,
+ "Minimal required number of letters of the same letter case."
+ "This limit is applied separately to upper-case and lower-case letters",
+ NULL, fix_min_length, 1, 0, 1000, 1);
+
+static MYSQL_SYSVAR_UINT(other_characters, min_others, PLUGIN_VAR_RQCMDARG,
+ "Minimal required number of other (not letters or digits) characters",
+ NULL, fix_min_length, 1, 0, 1000, 1);
+
+static struct st_mysql_sys_var* sysvars[]= {
+ MYSQL_SYSVAR(minimal_length),
+ MYSQL_SYSVAR(digits),
+ MYSQL_SYSVAR(letters_same_case),
+ MYSQL_SYSVAR(other_characters),
+ NULL
+};
+
+static struct st_mariadb_password_validation info=
+{
+ MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION,
+ validate
+};
+
+maria_declare_plugin(simple_password_check)
+{
+ MariaDB_PASSWORD_VALIDATION_PLUGIN,
+ &info,
+ "simple_password_check",
+ "Sergei Golubchik",
+ "Simple password strength checks",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ sysvars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/sql_errlog/sql_errlog.c b/plugin/sql_errlog/sql_errlog.c
index c2dc0b3af98..e0ebd6b7737 100644
--- a/plugin/sql_errlog/sql_errlog.c
+++ b/plugin/sql_errlog/sql_errlog.c
@@ -144,24 +144,6 @@ static struct st_mysql_audit descriptor =
{ MYSQL_AUDIT_GENERAL_CLASSMASK }
};
-mysql_declare_plugin(sql_errlog)
-{
- MYSQL_AUDIT_PLUGIN,
- &descriptor,
- "SQL_ERROR_LOG",
- "Alexey Botchkov",
- "Log SQL level errors to a file with rotation",
- PLUGIN_LICENSE_GPL,
- sql_error_log_init,
- sql_error_log_deinit,
- 0x0100,
- NULL,
- vars,
- NULL,
- 0
-}
-mysql_declare_plugin_end;
-
maria_declare_plugin(sql_errlog)
{
MYSQL_AUDIT_PLUGIN,
@@ -176,6 +158,6 @@ maria_declare_plugin(sql_errlog)
NULL,
vars,
"1.0",
- MariaDB_PLUGIN_MATURITY_ALPHA
+ MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;
diff --git a/plugin/userstat/CMakeLists.txt b/plugin/userstat/CMakeLists.txt
new file mode 100644
index 00000000000..5daa4f59577
--- /dev/null
+++ b/plugin/userstat/CMakeLists.txt
@@ -0,0 +1,4 @@
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql)
+
+MYSQL_ADD_PLUGIN(USERSTAT userstat.cc MANDATORY)
+
diff --git a/plugin/userstat/client_stats.cc b/plugin/userstat/client_stats.cc
new file mode 100644
index 00000000000..a1835384ad1
--- /dev/null
+++ b/plugin/userstat/client_stats.cc
@@ -0,0 +1,99 @@
+static ST_FIELD_INFO client_stats_fields[]=
+{
+ {"CLIENT", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Client", 0},
+ {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Total_connections", 0},
+ {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Concurrent_connections", 0},
+ {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Connected_time", 0},
+ {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Busy_time", 0},
+ {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Cpu_time", 0},
+ {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_received", 0},
+ {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_sent", 0},
+ {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Binlog_bytes_written", 0},
+ {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read", 0},
+ {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_sent", 0},
+ {"ROWS_DELETED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_deleted", 0},
+ {"ROWS_INSERTED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_inserted", 0},
+ {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_updated", 0},
+ {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Select_commands", 0},
+ {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Update_commands", 0},
+ {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Other_commands", 0},
+ {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Commit_transactions", 0},
+ {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rollback_transactions", 0},
+ {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Denied_connections", 0},
+ {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Lost_connections", 0},
+ {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Access_denied", 0},
+ {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Empty_queries", 0},
+ {"TOTAL_SSL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, "Total_ssl_connections", 0},
+ {"MAX_STATEMENT_TIME_EXCEEDED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Max_statement_time_exceeded",SKIP_OPEN_TABLE},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+};
+
+static int send_user_stats(THD* thd, HASH *all_user_stats, TABLE *table)
+{
+ mysql_mutex_lock(&LOCK_global_user_client_stats);
+ for (uint i= 0; i < all_user_stats->records; i++)
+ {
+ uint j= 0;
+ USER_STATS *user_stats= (USER_STATS*) my_hash_element(all_user_stats, i);
+
+ table->field[j++]->store(user_stats->user, user_stats->user_name_length,
+ system_charset_info);
+ table->field[j++]->store((longlong)user_stats->total_connections,TRUE);
+ table->field[j++]->store((longlong)user_stats->concurrent_connections, TRUE);
+ table->field[j++]->store((longlong)user_stats->connected_time, TRUE);
+ table->field[j++]->store((double)user_stats->busy_time);
+ table->field[j++]->store((double)user_stats->cpu_time);
+ table->field[j++]->store((longlong)user_stats->bytes_received, TRUE);
+ table->field[j++]->store((longlong)user_stats->bytes_sent, TRUE);
+ table->field[j++]->store((longlong)user_stats->binlog_bytes_written, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_read, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_sent, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_deleted, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_inserted, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_updated, TRUE);
+ table->field[j++]->store((longlong)user_stats->select_commands, TRUE);
+ table->field[j++]->store((longlong)user_stats->update_commands, TRUE);
+ table->field[j++]->store((longlong)user_stats->other_commands, TRUE);
+ table->field[j++]->store((longlong)user_stats->commit_trans, TRUE);
+ table->field[j++]->store((longlong)user_stats->rollback_trans, TRUE);
+ table->field[j++]->store((longlong)user_stats->denied_connections, TRUE);
+ table->field[j++]->store((longlong)user_stats->lost_connections, TRUE);
+ table->field[j++]->store((longlong)user_stats->access_denied_errors, TRUE);
+ table->field[j++]->store((longlong)user_stats->empty_queries, TRUE);
+ table->field[j++]->store((longlong)user_stats->total_ssl_connections, TRUE);
+ table->field[j++]->store((longlong)user_stats->max_statement_time_exceeded, TRUE);
+ if (schema_table_store_record(thd, table))
+ {
+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
+ return 1;
+ }
+ }
+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
+ return 0;
+}
+
+static int client_stats_fill(THD* thd, TABLE_LIST* tables, COND* cond)
+{
+ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL, true))
+ return 0;
+
+ return send_user_stats(thd, &global_client_stats, tables->table);
+}
+
+static int client_stats_reset()
+{
+ mysql_mutex_lock(&LOCK_global_user_client_stats);
+ free_global_client_stats();
+ init_global_client_stats();
+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
+ return 0;
+}
+
+static int client_stats_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= client_stats_fields;
+ schema->fill_table= client_stats_fill;
+ schema->reset_table= client_stats_reset;
+ return 0;
+}
diff --git a/plugin/userstat/index_stats.cc b/plugin/userstat/index_stats.cc
new file mode 100644
index 00000000000..236130d327f
--- /dev/null
+++ b/plugin/userstat/index_stats.cc
@@ -0,0 +1,72 @@
+static ST_FIELD_INFO index_stats_fields[]=
+{
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema",SKIP_OPEN_TABLE},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name",SKIP_OPEN_TABLE},
+ {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Index_name",SKIP_OPEN_TABLE},
+ {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0,0}
+};
+
+static int index_stats_fill(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ TABLE *table= tables->table;
+
+ mysql_mutex_lock(&LOCK_global_index_stats);
+ for (uint i= 0; i < global_index_stats.records; i++)
+ {
+ INDEX_STATS *index_stats =
+ (INDEX_STATS*) my_hash_element(&global_index_stats, i);
+ TABLE_LIST tmp_table;
+ char *index_name;
+ size_t schema_name_length, table_name_length, index_name_length;
+
+ bzero((char*) &tmp_table,sizeof(tmp_table));
+ tmp_table.db= index_stats->index;
+ tmp_table.table_name= strend(index_stats->index)+1;
+ tmp_table.grant.privilege= 0;
+ if (check_access(thd, SELECT_ACL, tmp_table.db,
+ &tmp_table.grant.privilege, NULL, 0, 1) ||
+ check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX, 1))
+ continue;
+
+ index_name= strend(tmp_table.table_name)+1;
+ schema_name_length= (tmp_table.table_name - index_stats->index) -1;
+ table_name_length= (index_name - tmp_table.table_name)-1;
+ index_name_length= (index_stats->index_name_length - schema_name_length -
+ table_name_length - 3);
+
+ table->field[0]->store(tmp_table.db, schema_name_length,
+ system_charset_info);
+ table->field[1]->store(tmp_table.table_name, table_name_length,
+ system_charset_info);
+ table->field[2]->store(index_name, index_name_length, system_charset_info);
+ table->field[3]->store((longlong)index_stats->rows_read, TRUE);
+
+ if (schema_table_store_record(thd, table))
+ {
+ mysql_mutex_unlock(&LOCK_global_index_stats);
+ return 1;
+ }
+ }
+ mysql_mutex_unlock(&LOCK_global_index_stats);
+ return 0;
+}
+
+static int index_stats_reset()
+{
+ mysql_mutex_lock(&LOCK_global_index_stats);
+ free_global_index_stats();
+ init_global_index_stats();
+ mysql_mutex_unlock(&LOCK_global_index_stats);
+ return 0;
+}
+
+static int index_stats_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= index_stats_fields;
+ schema->fill_table= index_stats_fill;
+ schema->reset_table= index_stats_reset;
+ return 0;
+}
+
diff --git a/plugin/userstat/table_stats.cc b/plugin/userstat/table_stats.cc
new file mode 100644
index 00000000000..7b522a388d7
--- /dev/null
+++ b/plugin/userstat/table_stats.cc
@@ -0,0 +1,73 @@
+static ST_FIELD_INFO table_stats_fields[]=
+{
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema",SKIP_OPEN_TABLE},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name",SKIP_OPEN_TABLE},
+ {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE},
+ {"ROWS_CHANGED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_changed",SKIP_OPEN_TABLE},
+ {"ROWS_CHANGED_X_INDEXES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_changed_x_#indexes",SKIP_OPEN_TABLE},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+};
+
+static int table_stats_fill(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ TABLE *table= tables->table;
+
+ mysql_mutex_lock(&LOCK_global_table_stats);
+ for (uint i= 0; i < global_table_stats.records; i++)
+ {
+ char *end_of_schema;
+ TABLE_STATS *table_stats=
+ (TABLE_STATS*)my_hash_element(&global_table_stats, i);
+ TABLE_LIST tmp_table;
+ size_t schema_length, table_name_length;
+
+ end_of_schema= strend(table_stats->table);
+ schema_length= (size_t) (end_of_schema - table_stats->table);
+ table_name_length= strlen(table_stats->table + schema_length + 1);
+
+ bzero((char*) &tmp_table,sizeof(tmp_table));
+ tmp_table.db= table_stats->table;
+ tmp_table.table_name= end_of_schema+1;
+ tmp_table.grant.privilege= 0;
+ if (check_access(thd, SELECT_ACL, tmp_table.db,
+ &tmp_table.grant.privilege, NULL, 0, 1) ||
+ check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX,
+ 1))
+ continue;
+
+ table->field[0]->store(table_stats->table, schema_length,
+ system_charset_info);
+ table->field[1]->store(table_stats->table + schema_length+1,
+ table_name_length, system_charset_info);
+ table->field[2]->store((longlong)table_stats->rows_read, TRUE);
+ table->field[3]->store((longlong)table_stats->rows_changed, TRUE);
+ table->field[4]->store((longlong)table_stats->rows_changed_x_indexes,
+ TRUE);
+ if (schema_table_store_record(thd, table))
+ {
+ mysql_mutex_unlock(&LOCK_global_table_stats);
+ return 1;
+ }
+ }
+ mysql_mutex_unlock(&LOCK_global_table_stats);
+ return 0;
+}
+
+static int table_stats_reset()
+{
+ mysql_mutex_lock(&LOCK_global_table_stats);
+ free_global_table_stats();
+ init_global_table_stats();
+ mysql_mutex_unlock(&LOCK_global_table_stats);
+ return 0;
+}
+
+static int table_stats_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= table_stats_fields;
+ schema->fill_table= table_stats_fill;
+ schema->reset_table= table_stats_reset;
+ return 0;
+}
+
diff --git a/plugin/userstat/user_stats.cc b/plugin/userstat/user_stats.cc
new file mode 100644
index 00000000000..12e2372e5cf
--- /dev/null
+++ b/plugin/userstat/user_stats.cc
@@ -0,0 +1,56 @@
+static ST_FIELD_INFO user_stats_fields[]=
+{
+ {"USER", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User", 0},
+ {"TOTAL_CONNECTIONS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections", 0},
+ {"CONCURRENT_CONNECTIONS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections", 0},
+ {"CONNECTED_TIME", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time", 0},
+ {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Busy_time", 0},
+ {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Cpu_time", 0},
+ {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_received", 0},
+ {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_sent", 0},
+ {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Binlog_bytes_written", 0},
+ {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read", 0},
+ {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_sent", 0},
+ {"ROWS_DELETED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_deleted", 0},
+ {"ROWS_INSERTED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_inserted", 0},
+ {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_updated", 0},
+ {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Select_commands", 0},
+ {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Update_commands", 0},
+ {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Other_commands", 0},
+ {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Commit_transactions", 0},
+ {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rollback_transactions", 0},
+ {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Denied_connections", 0},
+ {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Lost_connections", 0},
+ {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Access_denied", 0},
+ {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Empty_queries", 0},
+ {"TOTAL_SSL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, "Total_ssl_connections", 0},
+ {"MAX_STATEMENT_TIME_EXCEEDED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Max_statement_time_exceeded",SKIP_OPEN_TABLE},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+};
+
+static int user_stats_fill(THD* thd, TABLE_LIST* tables, COND* cond)
+{
+ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL, true))
+ return 0;
+
+ return send_user_stats(thd, &global_user_stats, tables->table);
+}
+
+static int user_stats_reset()
+{
+ mysql_mutex_lock(&LOCK_global_user_client_stats);
+ free_global_user_stats();
+ init_global_user_stats();
+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
+ return 0;
+}
+
+static int user_stats_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= user_stats_fields;
+ schema->fill_table= user_stats_fill;
+ schema->reset_table= user_stats_reset;
+ return 0;
+}
+
diff --git a/plugin/userstat/userstat.cc b/plugin/userstat/userstat.cc
new file mode 100644
index 00000000000..96d926ac908
--- /dev/null
+++ b/plugin/userstat/userstat.cc
@@ -0,0 +1,82 @@
+#include <my_config.h>
+#include <mysql/plugin.h>
+#include <mysql_version.h>
+#include "table.h"
+#include "sql_connect.h"
+#include "field.h"
+#include "sql_const.h"
+#include "sql_acl.h"
+
+bool schema_table_store_record(THD *thd, TABLE *table);
+
+#include "client_stats.cc"
+#include "index_stats.cc"
+#include "table_stats.cc"
+#include "user_stats.cc"
+
+static struct st_mysql_information_schema userstat_info=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+maria_declare_plugin(userstat)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &userstat_info,
+ "CLIENT_STATISTICS",
+ "Percona and Sergei Golubchik",
+ "Client Statistics",
+ PLUGIN_LICENSE_GPL,
+ client_stats_init,
+ 0,
+ 0x0200,
+ NULL,
+ NULL,
+ "2.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &userstat_info,
+ "INDEX_STATISTICS",
+ "Percona and Sergei Golubchik",
+ "Index Statistics",
+ PLUGIN_LICENSE_GPL,
+ index_stats_init,
+ 0,
+ 0x0200,
+ NULL,
+ NULL,
+ "2.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &userstat_info,
+ "TABLE_STATISTICS",
+ "Percona and Sergei Golubchik",
+ "Table Statistics",
+ PLUGIN_LICENSE_GPL,
+ table_stats_init,
+ 0,
+ 0x0200,
+ NULL,
+ NULL,
+ "2.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &userstat_info,
+ "USER_STATISTICS",
+ "Percona and Sergei Golubchik",
+ "User Statistics",
+ PLUGIN_LICENSE_GPL,
+ user_stats_init,
+ 0,
+ 0x0200,
+ NULL,
+ NULL,
+ "2.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/win_auth_client/CMakeLists.txt b/plugin/win_auth_client/CMakeLists.txt
index d54a740357e..435c5b8966a 100644
--- a/plugin/win_auth_client/CMakeLists.txt
+++ b/plugin/win_auth_client/CMakeLists.txt
@@ -29,7 +29,7 @@ IF(WIN32)
MYSQL_ADD_PLUGIN(authentication_windows_client ${PLUGIN_SOURCES} ${HEADERS}
LINK_LIBRARIES Secur32
- MODULE_ONLY COMPONENT SharedLibraries)
+ MODULE_ONLY COMPONENT ClientPlugins)
#IF(MSVC)
# INSTALL_DEBUG_TARGET(auth_win_client DESTINATION ${INSTALL_LIBDIR}/debug)
diff --git a/plugin/win_auth_client/handshake_client.cc b/plugin/win_auth_client/handshake_client.cc
index a02ba4b4688..4a3208af28f 100644
--- a/plugin/win_auth_client/handshake_client.cc
+++ b/plugin/win_auth_client/handshake_client.cc
@@ -216,7 +216,7 @@ int Handshake_client::write_packet(Blob &data)
an empty blob is returned and @c error() gives non-zero error code.
When invoked for the first time (in the first round of the handshake)
- there is no data from the server (data blob is null) and the intial
+ there is no data from the server (data blob is null) and the initial
packet is generated without an input.
@return Data to be sent to the server next or null blob if no more data
diff --git a/plugin/wsrep_info/CMakeLists.txt b/plugin/wsrep_info/CMakeLists.txt
new file mode 100644
index 00000000000..34aee9fba2c
--- /dev/null
+++ b/plugin/wsrep_info/CMakeLists.txt
@@ -0,0 +1,5 @@
+IF (WITH_WSREP)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql
+ ${CMAKE_SOURCE_DIR}/wsrep)
+ MYSQL_ADD_PLUGIN(WSREP_INFO plugin.cc MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
+ENDIF()
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf
new file mode 100644
index 00000000000..70682178ca1
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf
@@ -0,0 +1,33 @@
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld]
+wsrep-on=1
+binlog-format=row
+innodb-autoinc-lock-mode=2
+innodb-locks-unsafe-for-binlog=1
+wsrep-cluster-address=gcomm://
+wsrep_provider=@ENV.WSREP_PROVIDER
+
+[mysqld.1]
+#galera_port=@OPT.port
+#sst_port=@OPT.port
+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
+#sst_port=@OPT.port
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port'
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+wsrep_node_name=test-node-2
+
+[ENV]
+NODE_MYPORT_1= @mysqld.1.port
+NODE_MYSOCK_1= @mysqld.1.socket
+
+NODE_MYPORT_2= @mysqld.2.port
+NODE_MYSOCK_2= @mysqld.2.socket
+
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result
new file mode 100644
index 00000000000..31d66ab8b34
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result
@@ -0,0 +1,17 @@
+# On 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
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+INDEX UUID NAME ADDRESS
+<IDX> <MEMBER_ID> test-node-1 <ADDRESS>
+<IDX> <MEMBER_ID> test-node-2 <ADDRESS>
+# On 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
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+INDEX UUID NAME ADDRESS
+<IDX> <MEMBER_ID> test-node-1 <ADDRESS>
+<IDX> <MEMBER_ID> test-node-2 <ADDRESS>
+# End of test
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/suite.opt b/plugin/wsrep_info/mysql-test/wsrep_info/suite.opt
new file mode 100644
index 00000000000..b17344f88d0
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$WSREP_INFO_SO
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm
new file mode 100644
index 00000000000..cf4d124cb53
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm
@@ -0,0 +1,48 @@
+package My::Suite::WSREP_INFO;
+use File::Basename;
+use My::Find;
+
+@ISA = qw(My::Suite);
+
+return "Not run for embedded server" if $::opt_embedded_server;
+
+return "WSREP is not compiled in" unless defined $::mysqld_variables{'wsrep-on'};
+
+my ($provider) = grep { -f $_ } $ENV{WSREP_PROVIDER},
+ "/usr/lib/galera/libgalera_smm.so",
+ "/usr/lib64/galera/libgalera_smm.so";
+
+return "No wsrep provider library" unless -f $provider;
+
+return "No WSREP_INFO plugin" unless $ENV{WSREP_INFO_SO};
+
+$ENV{WSREP_PROVIDER} = $provider;
+
+my ($spath) = grep { -f "$_/wsrep_sst_rsync"; } "$::bindir/scripts", $::path_client_bindir;
+return "No SST scripts" unless $spath;
+
+my ($epath) = grep { -f "$_/my_print_defaults"; } "$::bindir/extra", $::path_client_bindir;
+return "No my_print_defaults" unless $epath;
+
+push @::global_suppressions,
+ (
+ qr(WSREP:.*down context.*),
+ qr(WSREP: Failed to send state UUID:.*),
+ qr(WSREP: wsrep_sst_receive_address.*),
+ qr(WSREP: Could not open saved state file for reading: .*),
+ qr(WSREP: Could not open state file for reading: .*),
+ qr(WSREP: last inactive check more than .* skipping check),
+ qr(WSREP: Gap in state sequence. Need state transfer.),
+ qr(WSREP: Failed to prepare for incremental state transfer: .*),
+ qr(WSREP: SYNC message from member .* in non-primary configuration. Ignored.),
+ qr|WSREP: access file\(.*gvwstate.dat\) failed\(No such file or directory\)|,
+ );
+
+
+$ENV{PATH}="$epath:$ENV{PATH}";
+$ENV{PATH}="$spath:$ENV{PATH}" unless $epath eq $spath;
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test b/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test
new file mode 100644
index 00000000000..9ae783a957e
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test
@@ -0,0 +1,23 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo # On node 1
+--connection node_1
+
+--replace_column 1 <IDX> 5 <CLUSTER_STATE_UUID> 7 <CLUSTER_CONF_ID>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+
+--replace_column 1 <IDX> 2 <MEMBER_ID> 4 <ADDRESS>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+
+--echo # On node 2
+--connection node_2
+
+--replace_column 1 <IDX> 5 <CLUSTER_STATE_UUID> 7 <CLUSTER_CONF_ID>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+
+--replace_column 1 <IDX> 2 <MEMBER_ID> 4 <ADDRESS>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+
+--source include/galera_end.inc
+--echo # End of test
diff --git a/plugin/wsrep_info/plugin.cc b/plugin/wsrep_info/plugin.cc
new file mode 100644
index 00000000000..6e95438c3b6
--- /dev/null
+++ b/plugin/wsrep_info/plugin.cc
@@ -0,0 +1,266 @@
+/* Copyright (C) 2014 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 02110-1335 USA */
+
+#ifndef MYSQL_SERVER
+#define MYSQL_SERVER
+#endif
+
+#include <my_config.h>
+#include <mysql/plugin.h>
+#include <table.h> /* ST_SCHEMA_TABLE */
+#include <sql_show.h>
+#include <sql_acl.h> /* check_global_access() */
+#include <wsrep_mysqld.h>
+#include <wsrep_utils.h>
+
+/* WSREP_MEMBERSHIP table fields */
+
+/* Node index */
+#define COLUMN_WSREP_MEMB_INDEX 0
+/* Unique member ID */
+#define COLUMN_WSREP_MEMB_UUID 1
+/* Human-readable name */
+#define COLUMN_WSREP_MEMB_NAME 2
+/* Incoming address */
+#define COLUMN_WSREP_MEMB_ADDRESS 3
+
+/* WSREP_STATUS table fields */
+
+/* Node index */
+#define COLUMN_WSREP_STATUS_NODE_INDEX 0
+/* Node status */
+#define COLUMN_WSREP_STATUS_NODE_STATUS 1
+/* Cluster status */
+#define COLUMN_WSREP_STATUS_CLUSTER_STATUS 2
+/* Cluster size */
+#define COLUMN_WSREP_STATUS_CLUSTER_SIZE 3
+/* Global cluster state UUID */
+#define COLUMN_WSREP_STATUS_CLUSTER_STATE_UUID 4
+/* Global cluster state Sequence number */
+#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
+
+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[]=
+{
+ {"INDEX", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Index", 0},
+ {"UUID", WSREP_UUID_STR_LEN, MYSQL_TYPE_STRING, 0, 0, "Uuid", 0},
+ {"NAME", WSREP_MEMBER_NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name", 0},
+ {"ADDRESS", WSREP_INCOMING_LEN, MYSQL_TYPE_STRING, 0, 0, "Address", 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+};
+
+static ST_FIELD_INFO wsrep_status_fields[]=
+{
+ {"NODE_INDEX", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
+ 0, 0, "Node_Index", 0},
+ {"NODE_STATUS", 16, MYSQL_TYPE_STRING, 0, 0, "Node_Status", 0},
+ {"CLUSTER_STATUS", 16, MYSQL_TYPE_STRING, 0, 0, "Cluster_Status", 0},
+ {"CLUSTER_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
+ 0, 0, "Cluster_Size", 0},
+ {"CLUSTER_STATE_UUID", WSREP_UUID_STR_LEN, MYSQL_TYPE_STRING,
+ 0, 0, 0, 0},
+ {"CLUSTER_STATE_SEQNO", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
+ 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}
+};
+
+static int wsrep_memb_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ int rc= 0;
+
+ if (check_global_access(thd, SUPER_ACL, true))
+ return rc;
+
+ wsrep_config_state.lock();
+
+ Dynamic_array<wsrep_member_info_t> *memb_arr=
+ wsrep_config_state.get_member_info();
+
+ TABLE *table= tables->table;
+
+ for (unsigned int i= 0; i < memb_arr->elements(); 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),
+ system_charset_info);
+ table->field[COLUMN_WSREP_MEMB_NAME]->store(memb.name, strlen(memb.name),
+ system_charset_info);
+ table->field[COLUMN_WSREP_MEMB_ADDRESS]->store(memb.incoming,
+ strlen(memb.incoming),
+ system_charset_info);
+
+ if (schema_table_store_record(thd, table))
+ {
+ rc= 1;
+ goto end;
+ }
+ }
+
+end:
+ wsrep_config_state.unlock();
+ return rc;
+}
+
+static int wsrep_memb_plugin_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+
+ schema->fields_info= wsrep_memb_fields;
+ schema->fill_table= wsrep_memb_fill_table;
+
+ return 0;
+}
+
+static struct st_mysql_information_schema wsrep_memb_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+static int wsrep_status_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ int rc= 0;
+
+ if (check_global_access(thd, SUPER_ACL, true))
+ return rc;
+
+ 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();
+
+ TABLE *table= tables->table;
+
+ table->field[COLUMN_WSREP_STATUS_NODE_INDEX]
+ ->store(view.my_idx, 0);
+ table->field[COLUMN_WSREP_STATUS_NODE_STATUS]
+ ->store(get_member_status(status), strlen(get_member_status(status)),
+ system_charset_info);
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_STATUS]
+ ->store(get_cluster_status(view.status),
+ strlen(get_cluster_status(view.status)),
+ system_charset_info);
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_SIZE]->store(view.memb_num, 0);
+
+ char uuid[40];
+ wsrep_uuid_print(&view.state_id.uuid, uuid, sizeof(uuid));
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_STATE_UUID]
+ ->store(uuid, sizeof(uuid), 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);
+
+ if (schema_table_store_record(thd, table))
+ rc= 1;
+
+ wsrep_config_state.unlock();
+ return rc;
+}
+
+static int wsrep_status_plugin_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+
+ schema->fields_info= wsrep_status_fields;
+ schema->fill_table= wsrep_status_fill_table;
+
+ return 0;
+}
+
+static struct st_mysql_information_schema wsrep_status_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+/*
+ Plugin library descriptor
+*/
+
+maria_declare_plugin(wsrep_info)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &wsrep_memb_plugin,
+ "WSREP_MEMBERSHIP", /* Plugin name */
+ "Nirbhay Choubey", /* Plugin author */
+ "Information about group members", /* Plugin description */
+ PLUGIN_LICENSE_GPL, /* License */
+ wsrep_memb_plugin_init, /* Plugin Init */
+ 0, /* Plugin Deinit */
+ 0x0100, /* Version (hex) */
+ NULL, /* Status variables */
+ NULL, /* System variables */
+ "1.0", /* Version (string) */
+ MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &wsrep_status_plugin,
+ "WSREP_STATUS", /* Plugin name */
+ "Nirbhay Choubey", /* Plugin author */
+ "Group view information", /* Plugin description */
+ PLUGIN_LICENSE_GPL, /* License */
+ wsrep_status_plugin_init, /* Plugin Init */
+ 0, /* Plugin Deinit */
+ 0x0100, /* Version (hex) */
+ NULL, /* Status variables */
+ NULL, /* System variables */
+ "1.0", /* Version (string) */
+ MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */
+}
+maria_declare_plugin_end;
+