Merge branch '10.1' into 10.2

Conflicts:
	VERSION
	cmake/plugin.cmake
	config.h.cmake
	configure.cmake
	plugin/server_audit/server_audit.c
	sql/sql_yacc.yy
This commit is contained in:
Monty 2016-02-06 18:14:54 +02:00
commit b2f8d7b410
166 changed files with 5717 additions and 1142 deletions

2
.gitignore vendored
View File

@ -112,6 +112,8 @@ scripts/wsrep_sst_mysqldump
scripts/wsrep_sst_rsync
scripts/wsrep_sst_xtrabackup
scripts/wsrep_sst_xtrabackup-v2
scripts/maria_add_gis_sp.sql
scripts/maria_add_gis_sp_bootstrap.sql
sql-bench/bench-count-distinct
sql-bench/bench-init.pl
sql-bench/compare-results

View File

@ -31,6 +31,7 @@ Usage: $0 [-h|-n] [configure-options]
-h, --help Show this help message.
-n, --just-print Don't actually run any commands; just print them.
-c, --just-configure Stop after running configure.
Combined with --just-print shows configure options.
--extra-configs=xxx Add this to configure options
--extra-flags=xxx Add this C and CXX flags
--extra-cflags=xxx Add this to C flags

View File

@ -4977,12 +4977,13 @@ static int my_kill(int pid, int sig)
{
#ifdef __WIN__
HANDLE proc;
if ((proc= OpenProcess(PROCESS_TERMINATE, FALSE, pid)) == NULL)
if ((proc= OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, pid)) == NULL)
return -1;
if (sig == 0)
{
DWORD wait_result= WaitForSingleObject(proc, 0);
CloseHandle(proc);
return 0;
return wait_result == WAIT_OBJECT_0?-1:0;
}
(void)TerminateProcess(proc, 201);
CloseHandle(proc);

View File

@ -86,6 +86,7 @@ SET(ignored
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man"
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man1*"
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man8*"
"%ignore ${CMAKE_INSTALL_PREFIX}/share/pkgconfig"
)
SET(CPACK_RPM_server_USER_FILELIST ${ignored} "%config(noreplace) ${INSTALL_SYSCONF2DIR}/*")

View File

@ -44,11 +44,10 @@ FUNCTION (INSTALL_DEBUG_SYMBOLS)
ENDIF()
set(comp "")
IF(ARG_COMPONENT STREQUAL "Server")
IF(target MATCHES "mysqld" OR type MATCHES "MODULE")
#MESSAGE("PDB: ${targets}")
SET(comp Server)
ENDIF()
IF(target MATCHES "mysqld" OR type MATCHES "MODULE")
#MESSAGE("PDB: ${targets}")
SET(comp Server)
ENDIF()
IF(NOT comp MATCHES Server)

View File

@ -87,6 +87,11 @@ MACRO(CREATE_EXPORT_FILE VAR TARGET API_FUNCTIONS)
ENDFOREACH()
SET(CONTENT "${CONTENT} (void *)0\n}\;")
CONFIGURE_FILE_CONTENT(${CONTENT} ${EXPORTS})
# Avoid "function redeclared as variable" error
# when using gcc/clang option -flto(link time optimization)
IF(" ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS} " MATCHES " -flto")
SET_SOURCE_FILES_PROPERTIES(${EXPORTS} PROPERTIES COMPILE_FLAGS "-fno-lto")
ENDIF()
SET(${VAR} ${EXPORTS})
ENDIF()
ENDMACRO()

View File

@ -56,3 +56,10 @@ ELSEIF(MYSQL_MAINTAINER_MODE MATCHES "AUTO")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${MY_MAINTAINER_C_WARNINGS}")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MY_MAINTAINER_CXX_WARNINGS}")
ENDIF()
IF(CMAKE_C_COMPILER_ID MATCHES "GNU")
STRING(REPLACE " -E " " -E -dDI " CMAKE_C_CREATE_PREPROCESSED_SOURCE ${CMAKE_C_CREATE_PREPROCESSED_SOURCE})
ENDIF()
IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
STRING(REPLACE " -E " " -E -dDI " CMAKE_CXX_CREATE_PREPROCESSED_SOURCE ${CMAKE_CXX_CREATE_PREPROCESSED_SOURCE})
ENDIF()

View File

@ -18,6 +18,7 @@ INCLUDE(CMakeParseArguments)
# MYSQL_ADD_PLUGIN(plugin_name source1...sourceN
# [STORAGE_ENGINE]
# [CLIENT]
# [MANDATORY|DEFAULT]
# [STATIC_ONLY|DYNAMIC_ONLY]
# [MODULE_OUTPUT_NAME module_name]
@ -28,7 +29,7 @@ INCLUDE(CMakeParseArguments)
MACRO(MYSQL_ADD_PLUGIN)
CMAKE_PARSE_ARGUMENTS(ARG
"STORAGE_ENGINE;STATIC_ONLY;MODULE_ONLY;MANDATORY;DEFAULT;DISABLED;RECOMPILE_FOR_EMBEDDED"
"STORAGE_ENGINE;STATIC_ONLY;MODULE_ONLY;MANDATORY;DEFAULT;DISABLED;RECOMPILE_FOR_EMBEDDED;CLIENT"
"MODULE_OUTPUT_NAME;STATIC_OUTPUT_NAME;COMPONENT;CONFIG"
"LINK_LIBRARIES;DEPENDENCIES"
${ARGN}
@ -120,7 +121,7 @@ MACRO(MYSQL_ADD_PLUGIN)
# Build either static library or module
IF (PLUGIN_${plugin} MATCHES "(STATIC|AUTO|YES)" AND NOT ARG_MODULE_ONLY
AND NOT ARG_DISABLED)
AND NOT ARG_DISABLED AND NOT ARG_CLIENT)
IF(CMAKE_GENERATOR MATCHES "Makefiles|Ninja")
# If there is a shared library from previous shared build,
@ -188,14 +189,14 @@ MACRO(MYSQL_ADD_PLUGIN)
TARGET_LINK_LIBRARIES (${target} mysqlservices ${ARG_LINK_LIBRARIES})
# Plugin uses symbols defined in mysqld executable.
# Server plugins use symbols defined in mysqld executable.
# Some operating systems like Windows and OSX and are pretty strict about
# unresolved symbols. Others are less strict and allow unresolved symbols
# in shared libraries. On Linux for example, CMake does not even add
# executable to the linker command line (it would result into link error).
# Thus we skip TARGET_LINK_LIBRARIES on Linux, as it would only generate
# an additional dependency.
IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT ARG_CLIENT)
TARGET_LINK_LIBRARIES (${target} mysqld)
ENDIF()
ADD_DEPENDENCIES(${target} GenError ${ARG_DEPENDENCIES})
@ -206,19 +207,22 @@ MACRO(MYSQL_ADD_PLUGIN)
IF(ARG_COMPONENT)
IF(CPACK_COMPONENTS_ALL AND
NOT CPACK_COMPONENTS_ALL MATCHES ${ARG_COMPONENT})
SET(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} ${ARG_COMPONENT} PARENT_SCOPE)
SET(CPACK_RPM_${ARG_COMPONENT}_PACKAGE_REQUIRES "MariaDB" PARENT_SCOPE)
IF (NOT ARG_CONFIG)
SET(ARG_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/${target}.cnf")
FILE(WRITE ${ARG_CONFIG} "[mariadb]\nplugin-load-add=${ARG_MODULE_OUTPUT_NAME}.so\n")
SET(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} ${ARG_COMPONENT})
SET(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} PARENT_SCOPE)
IF (NOT ARG_CLIENT)
SET(CPACK_RPM_${ARG_COMPONENT}_PACKAGE_REQUIRES "MariaDB" PARENT_SCOPE)
ENDIF()
INSTALL(FILES ${ARG_CONFIG} COMPONENT ${ARG_COMPONENT} DESTINATION ${INSTALL_SYSCONF2DIR})
# workarounds for cmake issues #13248 and #12864:
SET(CPACK_RPM_${ARG_COMPONENT}_PACKAGE_PROVIDES "cmake_bug_13248" PARENT_SCOPE)
SET(CPACK_RPM_${ARG_COMPONENT}_PACKAGE_OBSOLETES "cmake_bug_13248" PARENT_SCOPE)
SET(CPACK_RPM_${ARG_COMPONENT}_USER_FILELIST ${ignored} "%config(noreplace) ${INSTALL_SYSCONF2DIR}/*" PARENT_SCOPE)
SET(CPACK_RPM_${ARG_COMPONENT}_USER_FILELIST ${ignored} PARENT_SCOPE)
IF(NOT ARG_CLIENT AND NOT ARG_CONFIG AND UNIX)
SET(ARG_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/${target}.cnf")
FILE(WRITE ${ARG_CONFIG} "[mariadb]\nplugin-load-add=${ARG_MODULE_OUTPUT_NAME}.so\n")
INSTALL(FILES ${ARG_CONFIG} COMPONENT ${ARG_COMPONENT} DESTINATION ${INSTALL_SYSCONF2DIR})
SET(CPACK_RPM_${ARG_COMPONENT}_USER_FILELIST ${ignored} "%config(noreplace) ${INSTALL_SYSCONF2DIR}/*" PARENT_SCOPE)
ENDIF()
ENDIF()
ELSE()
SET(ARG_COMPONENT Server)

View File

@ -88,6 +88,7 @@
#cmakedefine HAVE_SYS_UN_H 1
#cmakedefine HAVE_SYS_VADVISE_H 1
#cmakedefine HAVE_SYS_STATVFS_H 1
#cmakedefine HAVE_UCONTEXT_H 1
#cmakedefine HAVE_TERM_H 1
#cmakedefine HAVE_TERMBITS_H 1
#cmakedefine HAVE_TERMIOS_H 1
@ -237,6 +238,7 @@
#cmakedefine HAVE_TIME 1
#cmakedefine HAVE_TIMES 1
#cmakedefine HAVE_UCONTEXT 1
#cmakedefine HAVE_VALLOC 1
#cmakedefine HAVE_VIDATTR 1
#define HAVE_VIO_READ_BUFF 1
#cmakedefine HAVE_VASPRINTF 1

View File

@ -977,6 +977,14 @@ CHECK_STRUCT_HAS_MEMBER("struct sockaddr_in6" sin6_len
SET(CMAKE_EXTRA_INCLUDE_FILES)
CHECK_STRUCT_HAS_MEMBER("struct dirent" d_ino "dirent.h" STRUCT_DIRENT_HAS_D_INO)
CHECK_STRUCT_HAS_MEMBER("struct dirent" d_namlen "dirent.h" STRUCT_DIRENT_HAS_D_NAMLEN)
SET(SPRINTF_RETURNS_INT 1)
CHECK_INCLUDE_FILE(ucontext.h HAVE_UCONTEXT_H)
IF(NOT HAVE_UCONTEXT_H)
CHECK_INCLUDE_FILE(sys/ucontext.h HAVE_UCONTEXT_H)
ENDIF()
CHECK_STRUCT_HAS_MEMBER("struct timespec" tv_sec "time.h" STRUCT_TIMESPEC_HAS_TV_SEC)
CHECK_STRUCT_HAS_MEMBER("struct timespec" tv_nsec "time.h" STRUCT_TIMESPEC_HAS_TV_NSEC)
@ -997,4 +1005,3 @@ IF(NOT MSVC)
HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE
)
ENDIF()

View File

@ -6,6 +6,7 @@ usr/lib/mysql/plugin/ha_blackhole.so
usr/lib/mysql/plugin/ha_federated.so
usr/lib/mysql/plugin/ha_federatedx.so
usr/lib/mysql/plugin/ha_innodb.so
usr/lib/mysql/plugin/ha_mroonga.so
usr/lib/mysql/plugin/ha_sphinx.so
usr/lib/mysql/plugin/handlersocket.so
usr/lib/mysql/plugin/locales.so
@ -83,6 +84,8 @@ usr/share/mysql/echo_stderr
usr/share/mysql/errmsg-utf8.txt
usr/share/mysql/fill_help_tables.sql
usr/share/mysql/maria_add_gis_sp_bootstrap.sql
usr/share/mysql/mroonga/install.sql
usr/share/mysql/mroonga/uninstall.sql
usr/share/mysql/mysql_system_tables_data.sql
usr/share/mysql/mysql_system_tables.sql
usr/share/mysql/mysql_performance_tables.sql

View File

@ -694,14 +694,14 @@ int main(int argc, char **argv)
if (*filename == '\0')
{
fprintf(stderr, "Error; File name missing\n");
goto error;
goto error_out;
}
/* stat the file to get size and page count */
if (stat(filename, &st))
{
fprintf(stderr, "Error; %s cannot be found\n", filename);
goto error;
goto error_out;
}
size= st.st_size;
@ -711,7 +711,7 @@ int main(int argc, char **argv)
{
fprintf(stderr, "Error; %s cannot be opened", filename);
perror(" ");
goto error;
goto error_out;
}
big_buf = (unsigned char *)malloc(2 * UNIV_PAGE_SIZE_MAX);
@ -719,7 +719,7 @@ int main(int argc, char **argv)
{
fprintf(stderr, "Error; failed to allocate memory\n");
perror("");
goto error;
goto error_f;
}
/* Make sure the page is aligned */
@ -731,7 +731,7 @@ int main(int argc, char **argv)
{
fprintf(stderr, "Error; failed to allocate memory\n");
perror("");
return 1;
goto error_big_buf;
}
/* Make sure the page is aligned */
@ -983,12 +983,17 @@ ok:
print_stats();
free(big_xdes);
free(big_buf);
fclose(f);
my_end(0);
exit(0);
error:
free(big_xdes);
error_big_buf:
free(big_buf);
error_f:
fclose(f);
error_out:
my_end(0);
exit(1);
}

View File

@ -31,7 +31,7 @@
#define MY_CONTEXT_USE_X86_64_GCC_ASM
#elif defined(__GNUC__) && __GNUC__ >= 3 && defined(__i386__)
#define MY_CONTEXT_USE_I386_GCC_ASM
#elif defined(HAVE_UCONTEXT)
#elif defined(HAVE_UCONTEXT_H)
#define MY_CONTEXT_USE_UCONTEXT
#else
#define MY_CONTEXT_DISABLE

View File

@ -694,7 +694,7 @@ extern void my_mutex_end(void);
We need to have at least 256K stack to handle calls to myisamchk_init()
with the current number of keys and key parts.
*/
#define DEFAULT_THREAD_STACK (288*1024L)
#define DEFAULT_THREAD_STACK (289*1024L)
#endif
#define MY_PTHREAD_LOCK_READ 0

View File

@ -208,7 +208,7 @@ void vio_end(void);
/* shutdown(2) flags */
#ifndef SHUT_RD
#define SHUT_RD SD_BOTH
#define SHUT_RD SD_RECEIVE
#endif
/*

View File

@ -45,7 +45,13 @@ drop table t1;
connection slave;
flush tables with read lock;
start slave;
source include/wait_for_slave_to_start.inc;
# The IO thread will not be able to read the GTID because of flush tables
let $slave_param= Slave_IO_Running;
let $slave_param_value= Preparing;
source include/wait_for_slave_param.inc;
--source include/wait_for_slave_sql_to_start.inc
--error 1192
stop slave;

View File

@ -34,9 +34,11 @@ create table t1 (a mediumtext, fulltext key key1(a)) charset utf8 collate utf8_g
insert into t1 values ('hello');
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze Warning Engine-independent statistics are not collected for column 'a'
test.t1 analyze status OK
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze Warning Engine-independent statistics are not collected for column 'a'
test.t1 analyze status Table is already up to date
drop table t1;
CREATE TABLE t1 (a int);

View File

@ -0,0 +1,10 @@
INSTALL SONAME 'auth_named_pipe';
CREATE USER 'USERNAME' IDENTIFIED WITH named_pipe;
SELECT USER(),CURRENT_USER();
USER() CURRENT_USER()
USERNAME@localhost USERNAME@%
DROP USER 'USERNAME';
CREATE USER nosuchuser IDENTIFIED WITH named_pipe;
ERROR 28000: Access denied for user 'nosuchuser'@'localhost'
DROP USER nosuchuser;
UNINSTALL SONAME 'auth_named_pipe';

View File

@ -162,3 +162,10 @@ a
begin not atomic select a from t1 having a > 1; end|
a
drop table t1|
#
# MDEV-8615: Assertion `m_cpp_buf <= begin_ptr &&
# begin_ptr <= m_cpp_buf + m_buf_length' failed in
# Lex_input_stream::body_utf8_start
#
b'|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'b'' at line 1

View File

@ -5365,14 +5365,17 @@ DROP TABLE t1;
SET sql_mode=default;
#
# Bug#57687 crash when reporting duplicate group_key error and utf8
# Make sure to modify this when Bug#58081 is fixed.
# Bug#58081 Duplicate entry error when doing GROUP BY
# MDEV-9332 Bug after upgrade to 10.1.10
#
SET NAMES utf8;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0), (0), (1), (0), (0);
SELECT COUNT(*) FROM t1, t1 t2
GROUP BY INSERT('', t2.a, t1.a, (@@global.max_binlog_size));
ERROR 23000: Duplicate entry '107374182410737418241' for key 'group_key'
COUNT(*)
20
5
DROP TABLE t1;
#
# Bug#11764503 (Bug#57341) Query in EXPLAIN EXTENDED shows wrong characters

View File

@ -2,10 +2,10 @@ set sql_mode="";
drop database if exists events_test;
create database events_test;
use events_test;
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
create event e_26 on schedule at '2027-01-01 00:00:00' disable do set @a = 5;
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
db name body definer convert_tz(execute_at, 'UTC', 'SYSTEM') on_completion
events_test e_26 set @a = 5 root@localhost 2017-01-01 00:00:00 DROP
events_test e_26 set @a = 5 root@localhost 2027-01-01 00:00:00 DROP
drop event e_26;
create event e_26 on schedule at NULL disable do set @a = 5;
ERROR HY000: Incorrect AT value: 'NULL'

View File

@ -91,7 +91,7 @@ create table events_smode_test(ev_name char(10), a date);
"This should never insert something"
create event ee_16407_2 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
select get_lock('ee_16407_2', 60); /*ee_16407_2*/
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
end|
@ -100,7 +100,7 @@ ERROR 22007: Incorrect date value: '1980-19-02' for column 'a' at row 1
"This is ok"
create event ee_16407_3 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
select get_lock('ee_16407_2', 60); /*ee_16407_3*/
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-19');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
@ -109,7 +109,7 @@ set sql_mode=""|
"This will insert rows but they will be truncated"
create event ee_16407_4 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
select get_lock('ee_16407_2', 60); /*ee_16407_4*/
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
end|
@ -157,13 +157,13 @@ create procedure ee_16407_5_pendant() begin insert into events_test.events_smode
create procedure ee_16407_6_pendant() begin insert into events_test.events_smode_test values('ee_16407_6','2004-02-29'); end|
create event ee_16407_5 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
select get_lock('ee_16407_5', 60); /*ee_16407_5*/
select release_lock('ee_16407_5');
call events_test.ee_16407_5_pendant();
end|
create event ee_16407_6 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
select get_lock('ee_16407_5', 60); /*ee_16407_6*/
select release_lock('ee_16407_5');
call events_test.ee_16407_6_pendant();
end|

View File

@ -4571,5 +4571,17 @@ Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 18446744073709551615) and (format(`test`.`t1`.`a`,0) = '18,446,744,073,709,551,615'))
DROP TABLE t1;
#
# Bug#58081 Duplicate entry error when doing GROUP BY
# MDEV-9332 Bug after upgrade to 10.1.10
#
SET NAMES latin1;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0),(0),(1),(0),(0);
SELECT COUNT(*) FROM t1, t1 t2 GROUP BY INSERT('', t2.a, t1.a, @@global.max_binlog_size);
COUNT(*)
20
5
DROP TABLE t1;
#
# End of 10.1 tests
#

View File

@ -7,19 +7,34 @@ mtr.test_suppressions OK
mysql.column_stats OK
mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.event
Warning : Engine-independent statistics are not collected for column 'body'
Warning : Engine-independent statistics are not collected for column 'body_utf8'
status : OK
mysql.func OK
mysql.gtid_slave_pos OK
mysql.help_category OK
mysql.help_category
Warning : Engine-independent statistics are not collected for column 'url'
status : OK
mysql.help_keyword OK
mysql.help_relation OK
mysql.help_topic OK
mysql.help_topic
Warning : Engine-independent statistics are not collected for column 'description'
Warning : Engine-independent statistics are not collected for column 'example'
Warning : Engine-independent statistics are not collected for column 'url'
status : OK
mysql.host OK
mysql.index_stats OK
mysql.innodb_index_stats OK
mysql.innodb_table_stats OK
mysql.plugin OK
mysql.proc OK
mysql.proc
Warning : Engine-independent statistics are not collected for column 'param_list'
Warning : Engine-independent statistics are not collected for column 'returns'
Warning : Engine-independent statistics are not collected for column 'body'
Warning : Engine-independent statistics are not collected for column 'comment'
Warning : Engine-independent statistics are not collected for column 'body_utf8'
status : OK
mysql.procs_priv OK
mysql.proxies_priv OK
mysql.roles_mapping OK
@ -31,7 +46,12 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
mysql.user OK
mysql.user
Warning : Engine-independent statistics are not collected for column 'ssl_cipher'
Warning : Engine-independent statistics are not collected for column 'x509_issuer'
Warning : Engine-independent statistics are not collected for column 'x509_subject'
Warning : Engine-independent statistics are not collected for column 'authentication_string'
status : OK
mtr.global_suppressions Table is already up to date
mtr.test_suppressions Table is already up to date
mysql.column_stats OK
@ -69,19 +89,34 @@ mysql.user OK
mysql.column_stats OK
mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.event
Warning : Engine-independent statistics are not collected for column 'body'
Warning : Engine-independent statistics are not collected for column 'body_utf8'
status : OK
mysql.func OK
mysql.gtid_slave_pos OK
mysql.help_category OK
mysql.help_category
Warning : Engine-independent statistics are not collected for column 'url'
status : OK
mysql.help_keyword OK
mysql.help_relation OK
mysql.help_topic OK
mysql.help_topic
Warning : Engine-independent statistics are not collected for column 'description'
Warning : Engine-independent statistics are not collected for column 'example'
Warning : Engine-independent statistics are not collected for column 'url'
status : OK
mysql.host OK
mysql.index_stats OK
mysql.innodb_index_stats OK
mysql.innodb_table_stats OK
mysql.plugin OK
mysql.proc OK
mysql.proc
Warning : Engine-independent statistics are not collected for column 'param_list'
Warning : Engine-independent statistics are not collected for column 'returns'
Warning : Engine-independent statistics are not collected for column 'body'
Warning : Engine-independent statistics are not collected for column 'comment'
Warning : Engine-independent statistics are not collected for column 'body_utf8'
status : OK
mysql.procs_priv OK
mysql.proxies_priv OK
mysql.roles_mapping OK
@ -93,7 +128,12 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
mysql.user OK
mysql.user
Warning : Engine-independent statistics are not collected for column 'ssl_cipher'
Warning : Engine-independent statistics are not collected for column 'x509_issuer'
Warning : Engine-independent statistics are not collected for column 'x509_subject'
Warning : Engine-independent statistics are not collected for column 'authentication_string'
status : OK
mysql.column_stats Table is already up to date
mysql.columns_priv Table is already up to date
mysql.db Table is already up to date

View File

@ -133,6 +133,6 @@
-thread-pool-oversubscribe 3
-thread-pool-stall-limit 500
+thread-pool-min-threads 1
thread-stack 294912
thread-stack 295936
time-format %H:%i:%s
timed-mutexes FALSE

View File

@ -1431,7 +1431,7 @@ thread-pool-idle-timeout 60
thread-pool-max-threads 1000
thread-pool-oversubscribe 3
thread-pool-stall-limit 500
thread-stack 294912
thread-stack 295936
time-format %H:%i:%s
timed-mutexes FALSE
tmp-table-size 16777216

View File

@ -1465,5 +1465,65 @@ Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 2020) and ((case when 2020 = 2010 then NULL else `test`.`t1`.`a` end) = concat('2020',rand())))
DROP TABLE t1;
#
# MDEV-9181 (NULLIF(count(table.col)), 0) gives wrong result on 10.1.x
#
CREATE TABLE t1 (c1 varchar(50) DEFAULT NULL);
INSERT INTO t1 (c1) VALUES ('hello'), ('hello\r\n'), ('hello'),('hello');
SELECT NULLIF(COUNT(c1),0) FROM t1;
NULLIF(COUNT(c1),0)
4
SELECT CASE WHEN COUNT(c1)=0 THEN NULL ELSE COUNT(c1) END FROM t1;
CASE WHEN COUNT(c1)=0 THEN NULL ELSE COUNT(c1) END
4
SELECT NULLIF(COUNT(c1)+0,0) AS c1,NULLIF(CAST(COUNT(c1) AS SIGNED),0) AS c2,NULLIF(CONCAT(COUNT(c1)),0) AS c3 FROM t1;
c1 c2 c3
4 4 4
SELECT NULLIF(COUNT(DISTINCT c1),0) FROM t1;
NULLIF(COUNT(DISTINCT c1),0)
2
SELECT CASE WHEN COUNT(DISTINCT c1)=0 THEN NULL ELSE COUNT(DISTINCT c1) END FROM t1;
CASE WHEN COUNT(DISTINCT c1)=0 THEN NULL ELSE COUNT(DISTINCT c1) END
2
DROP TABLE t1;
CREATE TABLE t1 (
id INT NOT NULL,
c1 INT DEFAULT NULL
);
INSERT INTO t1 VALUES (1,1),(1,2),(2,3),(2,4);
SELECT NULLIF(COUNT(c1),0) AS c1,NULLIF(COUNT(c1)+0,0) AS c1_wrapped,CASE WHEN COUNT(c1) IS NULL THEN 0 ELSE COUNT(c1) END AS c1_case FROM t1 GROUP BY id;
c1 c1_wrapped c1_case
2 2 2
2 2 2
DROP TABLE t1;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
SET @a=0;
SELECT NULLIF(LAST_VALUE(@a:=@a+1,a),0) FROM t1;
NULLIF(LAST_VALUE(@a:=@a+1,a),0)
1
2
3
SELECT @a;
@a
6
SET @a=0;
SELECT NULLIF(AVG(a),0), NULLIF(AVG(LAST_VALUE(@a:=@a+1,a)),0) FROM t1;
NULLIF(AVG(a),0) NULLIF(AVG(LAST_VALUE(@a:=@a+1,a)),0)
2.0000 2.0000
SELECT @a;
@a
3
EXPLAIN EXTENDED SELECT NULLIF(a,0) FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 select nullif(`test`.`t1`.`a`,0) AS `NULLIF(a,0)` from `test`.`t1`
EXPLAIN EXTENDED SELECT NULLIF(AVG(a),0) FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 select nullif(<cache>(avg(`test`.`t1`.`a`)),0) AS `NULLIF(AVG(a),0)` from `test`.`t1`
DROP TABLE t1;
#
# End of 10.1 tests
#

View File

@ -11,3 +11,40 @@ a b c d
8 NULL 9 NULL
8 NULL 10 NULL
DROP TABLE t1;
#
# MDEV-9457: Poor query plan chosen for ORDER BY query by a recent 10.1
#
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (
pk int primary key,
key1 int,
key2 int,
col1 char(255),
key(key1),
key(key2)
) engine=innodb;
set @a=-1;
insert into t1
select
@a:=@a+1,
@a,
@a,
repeat('abcd', 63)
from t0 A, t0 B, t0 C, t0 D;
# The following must NOT use 'index' on PK.
# It should use index_merge(key1,key2) + filesort
explain
select *
from t1
where key1<3 or key2<3
order by pk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using sort_union(key1,key2); Using where; Using filesort
explain
select *
from t1
where key1<3 or key2<3;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using sort_union(key1,key2); Using where
drop table t0, t1;

View File

@ -3466,3 +3466,21 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
1 PRIMARY t2 p_1000 ref PRIMARY PRIMARY 8 const 2 Using index
1 PRIMARY t1 p_1000 ALL PRIMARY NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join)
drop table t1,t2;
#
# MDEV-9505: Valgrind failure in SEL_ARG::store_min,find_used_partitions,...
#
create table t1 (a int, b char(10), c varchar(5), d int)
partition by range columns(a,b,c)
subpartition by key (c,d)
subpartitions 3
( partition p0 values less than (1,'abc','abc'),
partition p1 values less than (2,'abc','abc'),
partition p2 values less than (3,'abc','abc'),
partition p3 values less than (4,'abc','abc')
);
insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3);
select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) OR
(a = 1 AND b >= 'a' AND (c = 'c' OR (c = 'd' AND d = 2))));
a b c d
1 a b 1
drop table t1;

View File

@ -1212,6 +1212,7 @@ test t2 PRIMARY 1 1.0000
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'b'
test.t1 analyze status OK
SELECT * FROM mysql.column_stats;
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
@ -1225,7 +1226,6 @@ test t1 c aaaa dddddddd 0.1250 6.6571 7.0000 0 NULL NULL
test t1 d 1989-03-12 1999-07-23 0.1500 3.0000 8.5000 0 NULL NULL
test t1 e 0.01 0.112 0.2250 8.0000 6.2000 0 NULL NULL
test t1 f 1 5 0.2000 1.0000 6.4000 0 NULL NULL
test t1 b NULL NULL 0.2000 17.1250 NULL NULL NULL NULL
SELECT * FROM mysql.index_stats;
db_name table_name index_name prefix_arity avg_frequency
test t1 idx2 1 7.0000
@ -1265,6 +1265,7 @@ set use_stat_tables='never';
ANALYZE TABLE t1 PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'b'
test.t1 analyze status Table is already up to date
SELECT * FROM mysql.table_stats;
db_name table_name cardinality
@ -1276,7 +1277,6 @@ test t1 c aaaa dddddddd 0.1250 6.6571 7.0000 0 NULL NULL
test t1 d 1989-03-12 1999-07-23 0.1500 3.0000 8.5000 0 NULL NULL
test t1 e 0.01 0.112 0.2250 8.0000 6.2000 0 NULL NULL
test t1 f 1 5 0.2000 1.0000 6.4000 0 NULL NULL
test t1 b NULL NULL 0.2000 17.1250 NULL NULL NULL NULL
SELECT * FROM mysql.index_stats;
db_name table_name index_name prefix_arity avg_frequency
test t1 PRIMARY 1 1.0000
@ -1291,6 +1291,28 @@ test t1 idx4 3 NULL
DELETE FROM mysql.table_stats;
DELETE FROM mysql.column_stats;
DELETE FROM mysql.index_stats;
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS(b) INDEXES();
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'b'
test.t1 analyze status Table is already up to date
ANALYZE TABLE t1 PERSISTENT FOR columns(a,b) INDEXES();
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'b'
test.t1 analyze status Table is already up to date
ANALYZE TABLE t1 PERSISTENT FOR columns(b) indexes(idx2);
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'b'
test.t1 analyze status Table is already up to date
ANALYZE TABLE t1 PERSISTENT FOR columns() indexes(idx2);
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
DELETE FROM mysql.table_stats;
DELETE FROM mysql.column_stats;
DELETE FROM mysql.index_stats;
DROP TABLE t1,t2;
set names utf8;
CREATE DATABASE world;

View File

@ -3,6 +3,7 @@ INSERT INTO t1 VALUES (unhex('3E0D0A4141414142334E7A6143317963324541414141424977
ANALYZE TABLE t1 PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'a'
test.t1 analyze status OK
SELECT * FROM mysql.index_stats WHERE index_name='a' AND table_name='t1';
db_name table_name index_name prefix_arity avg_frequency
@ -13,6 +14,7 @@ INSERT INTO t1 VALUES (unhex('3E0D0A4141414142334E7A6143317963324541414141424977
ANALYZE TABLE t1 PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'a'
test.t1 analyze status OK
SELECT * FROM mysql.index_stats WHERE index_name='a' AND table_name='t1';
db_name table_name index_name prefix_arity avg_frequency

View File

@ -309,3 +309,16 @@ a b c
1 1 1
2 5 3
drop table t1;
set session sql_mode ='no_auto_value_on_zero';
create table t1 (id int unsigned auto_increment primary key);
insert t1 values (0);
select * from t1;
id
0
delete from t1;
create trigger t1_bi before insert on t1 for each row begin end;
insert t1 values (0);
select * from t1;
id
0
drop table t1;

View File

@ -36,6 +36,7 @@ count
2
ANALYZE TABLE articles;
Table Op Msg_type Msg_text
test.articles analyze Warning Engine-independent statistics are not collected for column 'body'
test.articles analyze status OK
SELECT * FROM articles WHERE MATCH (title,body)
AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);

View File

@ -247,6 +247,7 @@ articles CREATE TABLE `articles` (
ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body);
ANALYZE TABLE articles;
Table Op Msg_type Msg_text
test.articles analyze Warning Engine-independent statistics are not collected for column 'body'
test.articles analyze status OK
SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will");
id title body
@ -569,6 +570,7 @@ select @@innodb_ft_enable_stopword;
1
ANALYZE TABLE articles;
Table Op Msg_type Msg_text
test.articles analyze Warning Engine-independent statistics are not collected for column 'body'
test.articles analyze status OK
SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will");
id title body

View File

@ -122,9 +122,11 @@ a left(b,40)
1 1abcdefghijklmnopqrstuvwxyzAAAAAAAAAAAAA
analyze table t1;
Table Op Msg_type Msg_text
mysqltest_innodb_zip.t1 analyze Warning Engine-independent statistics are not collected for column 'b'
mysqltest_innodb_zip.t1 analyze status OK
analyze table t2;
Table Op Msg_type Msg_text
mysqltest_innodb_zip.t2 analyze Warning Engine-independent statistics are not collected for column 'b'
mysqltest_innodb_zip.t2 analyze status OK
SELECT table_schema, table_name, row_format, data_length, index_length FROM information_schema.tables WHERE engine='innodb' AND table_schema != 'mysql';
table_schema table_name row_format data_length index_length

View File

@ -0,0 +1,16 @@
call mtr.add_suppression("file_key_management");
call mtr.add_suppression("System key id 1 is missing");
call mtr.add_suppression("Unknown key id 1");
call mtr.add_suppression("Failed to decrypt");
CREATE TABLE t1 (i INT, KEY(i)) ENGINE=Aria;
INSERT INTO t1 VALUES (1);
repair table t1;
Table Op Msg_type Msg_text
test.t1 repair info Wrong CRC on datapage at 1
test.t1 repair warning Number of rows changed from 1 to 0
test.t1 repair status OK
INSERT INTO t1 VALUES (2);
select * from t1;
ERROR HY000: failed to decrypt './test/t1' rc: -1 dstlen: 0 size: 8172
drop table t1;

View File

@ -0,0 +1,54 @@
--source include/not_embedded.inc
#
# Test what happens if one removes a decryption key for Aria
#
call mtr.add_suppression("file_key_management");
call mtr.add_suppression("System key id 1 is missing");
call mtr.add_suppression("Unknown key id 1");
call mtr.add_suppression("Failed to decrypt");
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
--source include/wait_until_disconnected.inc
--write_file $MYSQLTEST_VARDIR/keys1.txt
1;770A8A65DA156D24EE2A093277530142
EOF
--exec echo "restart:--aria-encrypt-tables=1 --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
CREATE TABLE t1 (i INT, KEY(i)) ENGINE=Aria;
INSERT INTO t1 VALUES (1);
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
--source include/wait_until_disconnected.inc
--write_file $MYSQLTEST_VARDIR/keys2.txt
2;770A8A65DA156D24EE2A093277530143
EOF
--exec echo "restart:--aria-encrypt-tables=1 --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys2.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
repair table t1;
INSERT INTO t1 VALUES (2);
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
--source include/wait_until_disconnected.inc
--exec echo "restart:--aria-encrypt-tables=1 --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
--replace_result \\ /
--error 192
select * from t1;
drop table t1;

View File

@ -322,6 +322,7 @@ FLUSH TABLES;
# replacing p6 with a crashed MYD file (1) (splitted dynamic record)
ANALYZE TABLE t1_will_crash;
Table Op Msg_type Msg_text
test.t1_will_crash analyze Warning Engine-independent statistics are not collected for column 'c'
test.t1_will_crash analyze status OK
OPTIMIZE TABLE t1_will_crash;
Table Op Msg_type Msg_text

View File

@ -8,6 +8,7 @@ server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000
server_audit_file_rotations 9
server_audit_incl_users
server_audit_loc_info
server_audit_logging OFF
server_audit_mode 0
server_audit_output_type file
@ -71,6 +72,7 @@ server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000
server_audit_file_rotations 9
server_audit_incl_users odin, root, dva, tri
server_audit_loc_info
server_audit_logging ON
server_audit_mode 0
server_audit_output_type file
@ -216,6 +218,7 @@ server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000
server_audit_file_rotations 9
server_audit_incl_users odin, root, dva, tri
server_audit_loc_info
server_audit_logging ON
server_audit_mode 1
server_audit_output_type file
@ -289,7 +292,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,READ,mysql,proc,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proc,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,event,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop database sa_db',0
TIME,HOSTNAME,root,localhost,ID,0,DISCONNECT,sa_db,,0
TIME,HOSTNAME,root,localhost,ID,0,DISCONNECT,,,0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'create database sa_db',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'use sa_db',0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,

View File

@ -79,6 +79,7 @@ ERROR HY000: Your password does not satisfy the current policy requirements
grant select on *.* to `BarFoo1!` identified by 'FooBar1!';
drop user `BarFoo1!`;
create user foo1 identified by 'aA.12345';
grant select on *.* to foo1;
drop user foo1;
set global simple_password_check_digits=3;
set global simple_password_check_letters_same_case=3;
@ -129,7 +130,7 @@ ERROR HY000: The MariaDB server is running with the --strict-password-validation
create user foo2 identified with mysql_native_password using '';
ERROR HY000: Your password does not satisfy the current policy requirements
grant select on *.* to foo2 identified with mysql_old_password;
ERROR HY000: Your password does not satisfy the current policy requirements
ERROR 28000: Can't find any matching row in the user table
update mysql.user set password='xxx' where user='foo1';
set global strict_password_validation=0;
set password for foo1 = '';

View File

@ -35,6 +35,15 @@ SET SQL_MODE = '';
drop table t1;
SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'not_exists' AND TABLE_NAME = 'not_exists';
TABLE_NAME
CREATE procedure e1()
BEGIN
START TRANSACTION;
INSERT INTO test.non_exists VALUES (0,0,0) /* e1 */;
COMMIT;
END|
CALL e1();
ERROR 42S02: Table 'test.non_exists' doesn't exist
DROP PROCEDURE e1;
uninstall plugin SQL_ERROR_LOG;
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
@ -45,3 +54,4 @@ TIME HOSTNAME ERROR 1000: new message : RESIGNAL SQLSTATE '40000' SET
MYSQL_ERRNO = 1000,
MESSAGE_TEXT = 'new message'
TIME HOSTNAME ERROR 1366: Incorrect integer value: 'aa' for column 'id' at row 1 : insert into t1 values ('aa')
TIME HOSTNAME ERROR 1146: Table 'test.non_exists' doesn't exist : INSERT INTO test.non_exists VALUES (0,0,0) /* e1 */

View File

@ -8,6 +8,7 @@ server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000
server_audit_file_rotations 9
server_audit_incl_users
server_audit_loc_info
server_audit_logging OFF
server_audit_mode 0
server_audit_output_type file
@ -71,6 +72,7 @@ server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000
server_audit_file_rotations 9
server_audit_incl_users odin, root, dva, tri
server_audit_loc_info
server_audit_logging ON
server_audit_mode 0
server_audit_output_type file
@ -216,6 +218,7 @@ server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000
server_audit_file_rotations 9
server_audit_incl_users odin, root, dva, tri
server_audit_loc_info
server_audit_logging ON
server_audit_mode 1
server_audit_output_type file
@ -289,7 +292,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,READ,mysql,proc,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proc,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,event,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop database sa_db',0
TIME,HOSTNAME,root,localhost,ID,0,DISCONNECT,sa_db,,0
TIME,HOSTNAME,root,localhost,ID,0,DISCONNECT,,,0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'create database sa_db',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'use sa_db',0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,

View File

@ -26,6 +26,7 @@ grant select on *.* to `BarFoo1!` identified by 'FooBar1!';
drop user `BarFoo1!`;
create user foo1 identified by 'aA.12345';
grant select on *.* to foo1;
drop user foo1;
set global simple_password_check_digits=3;
@ -78,7 +79,7 @@ create user foo2 identified with mysql_native_password using '111111111111111111
grant select on *.* to foo2 identified with mysql_old_password using '2222222222222222';
--error ER_NOT_VALID_PASSWORD
create user foo2 identified with mysql_native_password using '';
--error ER_NOT_VALID_PASSWORD
--error ER_PASSWORD_NO_MATCH
grant select on *.* to foo2 identified with mysql_old_password;
# direct updates are not protected

View File

@ -48,6 +48,24 @@ drop table t1;
SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'not_exists' AND TABLE_NAME = 'not_exists';
#
# MDEV-6421 SQL_ERROR_LOG doesn't log comments in Events
# actually testing SP call is enough for that.
DELIMITER |;
CREATE procedure e1()
BEGIN
START TRANSACTION;
INSERT INTO test.non_exists VALUES (0,0,0) /* e1 */;
COMMIT;
END|
DELIMITER ;|
--error ER_NO_SUCH_TABLE
CALL e1();
DROP PROCEDURE e1;
uninstall plugin SQL_ERROR_LOG;
let $MYSQLD_DATADIR= `SELECT @@datadir`;

View File

@ -930,6 +930,8 @@ a
31
32
SET sql_slave_skip_counter= 1;
ERROR HY000: When using parallel replication and GTID with multiple replication domains, @@sql_slave_skip_counter can not be used. Instead, setting @@gtid_slave_pos explicitly can be used to skip to after a given GTID position.
include/stop_slave_io.inc
include/start_slave.inc
include/sync_with_master_gtid.inc
SELECT * FROM t2 WHERE a >= 30 ORDER BY a;

View File

@ -22,7 +22,8 @@ include/wait_for_slave_to_stop.inc
drop table t1;
flush tables with read lock;
start slave;
include/wait_for_slave_to_start.inc
include/wait_for_slave_param.inc [Slave_IO_Running]
include/wait_for_slave_sql_to_start.inc
stop slave;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
unlock tables;

View File

@ -14,6 +14,10 @@ DROP TABLE t1;
[connection slave]
include/install_semisync.inc
[connection slave]
show global status like "Slave%_running";
Variable_name Value
Slave_running ON
Slaves_running 1
UNINSTALL PLUGIN rpl_semi_sync_slave;
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
@ -21,6 +25,10 @@ select plugin_name,plugin_status from information_schema.plugins where plugin_na
plugin_name plugin_status
rpl_semi_sync_slave DELETED
[connection master]
show global status like "Slave%_connect%";
Variable_name Value
Slave_connections 2
Slaves_connected 1
UNINSTALL PLUGIN rpl_semi_sync_master;
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown

View File

@ -22,7 +22,8 @@ include/wait_for_slave_to_stop.inc
drop table t1;
flush tables with read lock;
start slave;
include/wait_for_slave_to_start.inc
include/wait_for_slave_param.inc [Slave_IO_Running]
include/wait_for_slave_sql_to_start.inc
stop slave;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
unlock tables;

View File

@ -1422,6 +1422,7 @@ SELECT * FROM t6 ORDER BY a;
--connection server_1
INSERT INTO t2 VALUES (31);
--let $gtid1= `SELECT @@LAST_GTID`
--source include/save_master_gtid.inc
--connection server_2
@ -1437,6 +1438,7 @@ SET sql_log_bin= 1;
--connection server_1
INSERT INTO t2 VALUES (32);
--let $gtid2= `SELECT @@LAST_GTID`
# Rotate the binlog; the bug is triggered when the master binlog file changes
# after the event group that causes the duplicate key error.
FLUSH LOGS;
@ -1469,7 +1471,12 @@ START SLAVE SQL_THREAD;
SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
# Skip the duplicate error, so we can proceed.
--error ER_SLAVE_SKIP_NOT_IN_GTID
SET sql_slave_skip_counter= 1;
--source include/stop_slave_io.inc
--disable_query_log
eval SET GLOBAL gtid_slave_pos = REPLACE(@@gtid_slave_pos, "$gtid1", "$gtid2");
--enable_query_log
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc

View File

@ -57,6 +57,8 @@ DROP TABLE t1;
# possible at this state
--connection slave
--echo [connection slave]
show global status like "Slave%_running";
UNINSTALL PLUGIN rpl_semi_sync_slave;
select plugin_name,plugin_status from information_schema.plugins where plugin_name like 'rpl_%';
@ -64,6 +66,10 @@ select plugin_name,plugin_status from information_schema.plugins where plugin_na
# possible at this state
--connection master
--echo [connection master]
# The following is to catch errors if the next uninstall plugin would succeed
show global status like "Slave%_connect%";
UNINSTALL PLUGIN rpl_semi_sync_master;
select plugin_name,plugin_status from information_schema.plugins where plugin_name like 'rpl_%';

View File

@ -3861,9 +3861,9 @@ READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME THREAD_STACK
SESSION_VALUE NULL
GLOBAL_VALUE 294912
GLOBAL_VALUE 295936
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 294912
DEFAULT_VALUE 295936
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT The stack size for each thread

View File

@ -4645,9 +4645,9 @@ READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME THREAD_STACK
SESSION_VALUE NULL
GLOBAL_VALUE 294912
GLOBAL_VALUE 295936
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 294912
DEFAULT_VALUE 295936
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT The stack size for each thread

View File

@ -1,20 +1,20 @@
select @@global.thread_stack;
@@global.thread_stack
294912
295936
select @@session.thread_stack;
ERROR HY000: Variable 'thread_stack' is a GLOBAL variable
show global variables like 'thread_stack';
Variable_name Value
thread_stack 294912
thread_stack 295936
show session variables like 'thread_stack';
Variable_name Value
thread_stack 294912
thread_stack 295936
select * from information_schema.global_variables where variable_name='thread_stack';
VARIABLE_NAME VARIABLE_VALUE
THREAD_STACK 294912
THREAD_STACK 295936
select * from information_schema.session_variables where variable_name='thread_stack';
VARIABLE_NAME VARIABLE_VALUE
THREAD_STACK 294912
THREAD_STACK 295936
set global thread_stack=1;
ERROR HY000: Variable 'thread_stack' is a read only variable
set session thread_stack=1;

View File

@ -0,0 +1 @@
--loose-enable-named-pipe

View File

@ -0,0 +1,23 @@
--source include/windows.inc
INSTALL SONAME 'auth_named_pipe';
--replace_result $USERNAME USERNAME
eval CREATE USER '$USERNAME' IDENTIFIED WITH named_pipe;
# Connect using named pipe, correct username
connect(pipe_con,localhost,$USERNAME,,,,,PIPE);
--replace_result $USERNAME USERNAME
SELECT USER(),CURRENT_USER();
disconnect pipe_con;
connection default;
--replace_result $USERNAME USERNAME
eval DROP USER '$USERNAME';
# test invalid user name
CREATE USER nosuchuser IDENTIFIED WITH named_pipe;
--disable_query_log
--error ER_ACCESS_DENIED_NO_PASSWORD_ERROR
connect(pipe_con,localhost,nosuchuser,,,,,PIPE);
--enable_query_log
DROP USER nosuchuser;
UNINSTALL SONAME 'auth_named_pipe';

View File

@ -150,3 +150,10 @@ select a from t1 having a > 1|
begin not atomic select a from t1 having a > 1; end|
drop table t1|
--echo #
--echo # MDEV-8615: Assertion `m_cpp_buf <= begin_ptr &&
--echo # begin_ptr <= m_cpp_buf + m_buf_length' failed in
--echo # Lex_input_stream::body_utf8_start
--echo #
--error ER_PARSE_ERROR
--query b'

View File

@ -1577,12 +1577,12 @@ SET NAMES utf8;
--echo #
--echo # Bug#57687 crash when reporting duplicate group_key error and utf8
--echo # Make sure to modify this when Bug#58081 is fixed.
--echo # Bug#58081 Duplicate entry error when doing GROUP BY
--echo # MDEV-9332 Bug after upgrade to 10.1.10
--echo #
SET NAMES utf8;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0), (0), (1), (0), (0);
--error ER_DUP_ENTRY
SELECT COUNT(*) FROM t1, t1 t2
GROUP BY INSERT('', t2.a, t1.a, (@@global.max_binlog_size));
DROP TABLE t1;

View File

@ -15,7 +15,7 @@ use events_test;
# mysql.event intact checking end
#
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
create event e_26 on schedule at '2027-01-01 00:00:00' disable do set @a = 5;
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
drop event e_26;
--error ER_WRONG_VALUE

View File

@ -306,7 +306,7 @@ create table events_smode_test(ev_name char(10), a date);
delimiter |;
create event ee_16407_2 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
select get_lock('ee_16407_2', 60); /*ee_16407_2*/
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
end|
@ -315,7 +315,7 @@ insert into events_test.events_smode_test values ('test','1980-19-02')|
--echo "This is ok"
create event ee_16407_3 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
select get_lock('ee_16407_2', 60); /*ee_16407_3*/
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-19');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
@ -324,7 +324,7 @@ set sql_mode=""|
--echo "This will insert rows but they will be truncated"
create event ee_16407_4 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
select get_lock('ee_16407_2', 60); /*ee_16407_4*/
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
end|
@ -412,13 +412,13 @@ create procedure ee_16407_5_pendant() begin insert into events_test.events_smode
create procedure ee_16407_6_pendant() begin insert into events_test.events_smode_test values('ee_16407_6','2004-02-29'); end|
create event ee_16407_5 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
select get_lock('ee_16407_5', 60); /*ee_16407_5*/
select release_lock('ee_16407_5');
call events_test.ee_16407_5_pendant();
end|
create event ee_16407_6 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
select get_lock('ee_16407_5', 60); /*ee_16407_6*/
select release_lock('ee_16407_5');
call events_test.ee_16407_6_pendant();
end|

View File

@ -1773,6 +1773,16 @@ EXPLAIN EXTENDED
SELECT * FROM t1 WHERE a=18446744073709551615 AND FORMAT(a,0)='18,446,744,073,709,551,615';
DROP TABLE t1;
--echo #
--echo # Bug#58081 Duplicate entry error when doing GROUP BY
--echo # MDEV-9332 Bug after upgrade to 10.1.10
--echo #
SET NAMES latin1;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0),(0),(1),(0),(0);
SELECT COUNT(*) FROM t1, t1 t2 GROUP BY INSERT('', t2.a, t1.a, @@global.max_binlog_size);
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
--echo #

View File

@ -909,6 +909,45 @@ EXPLAIN EXTENDED
SELECT * FROM t1 WHERE a=2020 AND NULLIF(a,2010)=CONCAT('2020',RAND());
DROP TABLE t1;
--echo #
--echo # MDEV-9181 (NULLIF(count(table.col)), 0) gives wrong result on 10.1.x
--echo #
CREATE TABLE t1 (c1 varchar(50) DEFAULT NULL);
INSERT INTO t1 (c1) VALUES ('hello'), ('hello\r\n'), ('hello'),('hello');
SELECT NULLIF(COUNT(c1),0) FROM t1;
SELECT CASE WHEN COUNT(c1)=0 THEN NULL ELSE COUNT(c1) END FROM t1;
SELECT NULLIF(COUNT(c1)+0,0) AS c1,NULLIF(CAST(COUNT(c1) AS SIGNED),0) AS c2,NULLIF(CONCAT(COUNT(c1)),0) AS c3 FROM t1;
SELECT NULLIF(COUNT(DISTINCT c1),0) FROM t1;
SELECT CASE WHEN COUNT(DISTINCT c1)=0 THEN NULL ELSE COUNT(DISTINCT c1) END FROM t1;
DROP TABLE t1;
CREATE TABLE t1 (
id INT NOT NULL,
c1 INT DEFAULT NULL
);
INSERT INTO t1 VALUES (1,1),(1,2),(2,3),(2,4);
SELECT NULLIF(COUNT(c1),0) AS c1,NULLIF(COUNT(c1)+0,0) AS c1_wrapped,CASE WHEN COUNT(c1) IS NULL THEN 0 ELSE COUNT(c1) END AS c1_case FROM t1 GROUP BY id;
DROP TABLE t1;
# Testing with side effects
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
SET @a=0;
SELECT NULLIF(LAST_VALUE(@a:=@a+1,a),0) FROM t1;
SELECT @a;
SET @a=0;
SELECT NULLIF(AVG(a),0), NULLIF(AVG(LAST_VALUE(@a:=@a+1,a)),0) FROM t1;
SELECT @a;
# There should not be cache in here:
EXPLAIN EXTENDED SELECT NULLIF(a,0) FROM t1;
# But there should be a cache in here:
EXPLAIN EXTENDED SELECT NULLIF(AVG(a),0) FROM t1;
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests

View File

@ -21,3 +21,43 @@ SELECT * FROM t1 WHERE a = 8 AND (b = 1 OR b IS NULL) ORDER BY c;
DROP TABLE t1;
--echo #
--echo # MDEV-9457: Poor query plan chosen for ORDER BY query by a recent 10.1
--echo #
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (
pk int primary key,
key1 int,
key2 int,
col1 char(255),
key(key1),
key(key2)
) engine=innodb;
set @a=-1;
insert into t1
select
@a:=@a+1,
@a,
@a,
repeat('abcd', 63)
from t0 A, t0 B, t0 C, t0 D;
--echo # The following must NOT use 'index' on PK.
--echo # It should use index_merge(key1,key2) + filesort
--replace_column 9 #
explain
select *
from t1
where key1<3 or key2<3
order by pk;
--replace_column 9 #
explain
select *
from t1
where key1<3 or key2<3;
drop table t0, t1;

View File

@ -1517,3 +1517,22 @@ and dept_id in (select dept_id from t2 where COMPANY_ID = 1000);
drop table t1,t2;
--echo #
--echo # MDEV-9505: Valgrind failure in SEL_ARG::store_min,find_used_partitions,...
--echo #
create table t1 (a int, b char(10), c varchar(5), d int)
partition by range columns(a,b,c)
subpartition by key (c,d)
subpartitions 3
( partition p0 values less than (1,'abc','abc'),
partition p1 values less than (2,'abc','abc'),
partition p2 values less than (3,'abc','abc'),
partition p3 values less than (4,'abc','abc')
);
insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3);
select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) OR
(a = 1 AND b >= 'a' AND (c = 'c' OR (c = 'd' AND d = 2))));
drop table t1;

View File

@ -494,6 +494,17 @@ DELETE FROM mysql.table_stats;
DELETE FROM mysql.column_stats;
DELETE FROM mysql.index_stats;
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS(b) INDEXES();
ANALYZE TABLE t1 PERSISTENT FOR columns(a,b) INDEXES();
ANALYZE TABLE t1 PERSISTENT FOR columns(b) indexes(idx2);
ANALYZE TABLE t1 PERSISTENT FOR columns() indexes(idx2);
DELETE FROM mysql.table_stats;
DELETE FROM mysql.column_stats;
DELETE FROM mysql.index_stats;
DROP TABLE t1,t2;
set names utf8;

View File

@ -325,3 +325,17 @@ insert t1 values (9, 9, 2);
insert t1 (a,c) values (9, 3);
select * from t1;
drop table t1;
#
# MDEV-9428 NO_AUTO_VALUE_ON_ZERO is ignored when a trigger before insert is defined
#
set session sql_mode ='no_auto_value_on_zero';
create table t1 (id int unsigned auto_increment primary key);
insert t1 values (0);
select * from t1;
delete from t1;
create trigger t1_bi before insert on t1 for each row begin end;
insert t1 values (0);
select * from t1;
drop table t1;

View File

@ -1277,6 +1277,15 @@
fun:dlopen@@GLIBC_2.2.5
}
{
vasprintf in OpenSuse 12.3
Memcheck:Leak
fun:malloc
fun:vasprintf
fun:asprintf
fun:dlerror
}
{
GitHub codership/galera#308
Memcheck:Leak

View File

@ -14,11 +14,13 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef FLOGGER_SKIP_INCLUDES
#include "my_global.h"
#include <my_sys.h>
#include <m_string.h>
#include <mysql/service_logger.h>
#include <my_pthread.h>
#endif /*FLOGGER_SKIP_INCLUDES*/
#ifndef flogger_mutex_init
#define flogger_mutex_init(A,B,C) mysql_mutex_init(A,B,C)

View File

@ -145,30 +145,75 @@ static int initialized= 0;
static char output[1024];
int my_addr_resolve(void *ptr, my_addr_loc *loc)
{
char input[32], *s;
char input[32];
size_t len;
ssize_t total_bytes_read = 0;
ssize_t extra_bytes_read = 0;
fd_set set;
struct timeval timeout;
int filename_start = -1;
int line_number_start = -1;
ssize_t i;
FD_ZERO(&set);
FD_SET(out[0], &set);
len= my_snprintf(input, sizeof(input), "%p\n", ptr - offset);
if (write(in[1], input, len) <= 0)
return 1;
if (read(out[0], output, sizeof(output)) <= 0)
return 1;
loc->func= s= output;
while (*s != '\n')
s++;
*s++= 0;
loc->file= s;
while (*s != ':')
s++;
*s++= 0;
/* 10 ms should be plenty of time for addr2line to issue a response. */
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
/* Read in a loop till all the output from addr2line is complete. */
while (select(out[0] + 1, &set, NULL, NULL, &timeout) > 0)
{
extra_bytes_read= read(out[0], output + total_bytes_read,
sizeof(output) - total_bytes_read);
if (extra_bytes_read < 0)
return 1;
/* Timeout or max bytes read. */
if (extra_bytes_read == 0)
break;
total_bytes_read += extra_bytes_read;
}
/* Failed starting addr2line. */
if (total_bytes_read == 0)
return 1;
/* Go through the addr2line response and get the required data.
The response is structured in 2 lines. The first line contains the function
name, while the second one contains <filename>:<line number> */
for (i = 0; i < total_bytes_read; i++) {
if (output[i] == '\n') {
filename_start = i + 1;
output[i] = '\0';
}
if (filename_start != -1 && output[i] == ':') {
line_number_start = i + 1;
output[i] = '\0';
}
if (line_number_start != -1) {
loc->line= atoi(output + line_number_start);
break;
}
}
/* Response is malformed. */
if (filename_start == -1 || line_number_start == -1)
return 1;
loc->func= output;
loc->file= output + filename_start;
/* Addr2line was unable to extract any meaningful information. */
if (strcmp(loc->file, "??") == 0)
return 1;
loc->line= 0;
while (isdigit(*s))
loc->line = loc->line * 10 + (*s++ - '0');
*s = 0;
loc->file= strip_path(loc->file);
return 0;

View File

@ -15,4 +15,4 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
MYSQL_ADD_PLUGIN(dialog dialog.c ${CMAKE_SOURCE_DIR}/libmysql/get_password.c
MODULE_ONLY COMPONENT ClientPlugins)
MODULE_ONLY CLIENT COMPONENT ClientPlugins)

View File

@ -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 ClientPlugins)
MODULE_ONLY CLIENT COMPONENT ClientPlugins)

View File

@ -0,0 +1,36 @@
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)
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)

View File

@ -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 enviroment).
#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 occured. 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.

View File

@ -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;

View File

@ -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 PATHS
/opt/local/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)

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -0,0 +1,247 @@
#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>
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))
{
sql_print_warning("GSSAPI plugin : krb5_init_context failed");
goto cleanup;
}
if (krb5_sname_to_principal(context, NULL, "mariadb", KRB5_NT_SRV_HST, &principal))
{
sql_print_warning("GSSAPI plugin : krb5_sname_to_principal failed");
goto cleanup;
}
if (krb5_unparse_name(context, principal, &unparsed_name))
{
sql_print_warning("GSSAPI plugin : krb5_unparse_name failed");
goto cleanup;
}
/* Check for entry in keytab */
if (krb5_kt_read_service_key(context, NULL, principal, 0, (krb5_enctype)0, &key))
{
sql_print_warning("GSSAPI plugin : default principal '%s' not found in keytab", 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])
{
sql_print_information("GSSAPI plugin : using principal name '%s'", 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);
}

View File

@ -0,0 +1,18 @@
INSTALL SONAME 'auth_gssapi';
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';

View File

@ -0,0 +1,45 @@
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';

View File

@ -0,0 +1 @@
--loose-gssapi-keytab-path=$GSSAPI_KEYTAB_PATH --loose-gssapi-principal-name=$GSSAPI_PRINCIPAL_NAME

View File

@ -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 |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 { };

View File

@ -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_BETA
}
maria_declare_plugin_end;

View File

@ -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);

38
plugin/auth_gssapi/sspi.h Normal file
View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -0,0 +1,312 @@
/* 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", MYF(0), msg, buf);
}
else
{
my_printf_error(ER_UNKNOWN_ERROR, "SSPI server error %s", MYF(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);
FreeContextBuffer(&native_names);
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();
}
sql_print_information("SSPI: using principal name '%s', mech '%s'",
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;
}

View File

@ -127,13 +127,13 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
s++;
}
from= s;
skip(isalnum(*s) || (*s == '_'));
skip(isalnum(*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;

View File

@ -0,0 +1,3 @@
IF(WIN32)
MYSQL_ADD_PLUGIN(auth_named_pipe auth_pipe.c)
ENDIF()

View File

@ -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-1301 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;

View File

@ -13,4 +13,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
MYSQL_ADD_PLUGIN(server_audit server_audit.c MODULE_ONLY)
SET(SERVER_AUDIT_SOURCES
server_audit.c test_audit_v4.c plugin_audit_v4.h)
MYSQL_ADD_PLUGIN(server_audit ${SERVER_AUDIT_SOURCES} MODULE_ONLY)

View File

@ -0,0 +1,561 @@
/* Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
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-1301 USA */
#ifndef _my_audit_h
#define _my_audit_h
#ifndef PLUGIN_CONTEXT
#include "plugin.h"
#include "mysql/mysql_lex_string.h"
#ifndef MYSQL_ABI_CHECK
#include "m_string.h"
#endif
#include "my_command.h"
#include "my_sqlcommand.h"
#endif /*PLUGIN_CONTEXT*/
#define MYSQL_AUDIT_INTERFACE_VERSION 0x0401
/**
@enum mysql_event_class_t
Audit event classes.
*/
typedef enum
{
MYSQL_AUDIT_GENERAL_CLASS = 0,
MYSQL_AUDIT_CONNECTION_CLASS = 1,
MYSQL_AUDIT_PARSE_CLASS = 2,
MYSQL_AUDIT_AUTHORIZATION_CLASS = 3,
MYSQL_AUDIT_TABLE_ACCESS_CLASS = 4,
MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS = 5,
MYSQL_AUDIT_SERVER_STARTUP_CLASS = 6,
MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS = 7,
MYSQL_AUDIT_COMMAND_CLASS = 8,
MYSQL_AUDIT_QUERY_CLASS = 9,
MYSQL_AUDIT_STORED_PROGRAM_CLASS = 10,
/* This item must be last in the list. */
MYSQL_AUDIT_CLASS_MASK_SIZE
} mysql_event_class_t;
/**
@struct st_mysql_audit
The descriptor structure that is referred from st_mysql_plugin.
*/
struct st_mysql_audit
{
/**
Interface version.
*/
int interface_version;
/**
Event occurs when the event class consumer is to be
disassociated from the specified THD.This would typically occur
before some operation which may require sleeping - such as when
waiting for the next query from the client.
*/
void (*release_thd)(MYSQL_THD);
/**
Invoked whenever an event occurs which is of any
class for which the plugin has interest.The second argument
indicates the specific event class and the third argument is data
as required for that class.
*/
int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);
/**
An array of bits used to indicate what event classes
that this plugin wants to receive.
*/
unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
};
/**
@typedef enum_sql_command_t
SQL command type definition.
*/
typedef enum enum_sql_command enum_sql_command_t;
/**
@enum mysql_event_general_subclass_t
Events for the MYSQL_AUDIT_GENERAL_CLASS event class.
*/
typedef enum
{
/** occurs before emitting to the general query log. */
MYSQL_AUDIT_GENERAL_LOG = 1 << 0,
/** occurs before transmitting errors to the user. */
MYSQL_AUDIT_GENERAL_ERROR = 1 << 1,
/** occurs after transmitting a resultset to the user. */
MYSQL_AUDIT_GENERAL_RESULT = 1 << 2,
/** occurs after transmitting a resultset or errors */
MYSQL_AUDIT_GENERAL_STATUS = 1 << 3
} mysql_event_general_subclass_t;
#define MYSQL_AUDIT_GENERAL_ALL (MYSQL_AUDIT_GENERAL_LOG | \
MYSQL_AUDIT_GENERAL_ERROR | \
MYSQL_AUDIT_GENERAL_RESULT | \
MYSQL_AUDIT_GENERAL_STATUS)
/**
@struct mysql_event_general
Structure for the MYSQL_AUDIT_GENERAL_CLASS event class.
*/
struct mysql_event_general
{
mysql_event_general_subclass_t event_subclass;
int general_error_code;
unsigned long general_thread_id;
MYSQL_LEX_CSTRING general_user;
MYSQL_LEX_CSTRING general_command;
MYSQL_LEX_CSTRING general_query;
struct charset_info_st *general_charset;
unsigned long long general_time;
unsigned long long general_rows;
MYSQL_LEX_CSTRING general_host;
MYSQL_LEX_CSTRING general_sql_command;
MYSQL_LEX_CSTRING general_external_user;
MYSQL_LEX_CSTRING general_ip;
};
/**
@enum mysql_event_connection_subclass_t
Events for MYSQL_AUDIT_CONNECTION_CLASS event class.
*/
typedef enum
{
/** occurs after authentication phase is completed. */
MYSQL_AUDIT_CONNECTION_CONNECT = 1 << 0,
/** occurs after connection is terminated. */
MYSQL_AUDIT_CONNECTION_DISCONNECT = 1 << 1,
/** occurs after COM_CHANGE_USER RPC is completed. */
MYSQL_AUDIT_CONNECTION_CHANGE_USER = 1 << 2,
/** occurs before authentication. */
MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE = 1 << 3
} mysql_event_connection_subclass_t;
#define MYSQL_AUDIT_CONNECTION_ALL (MYSQL_AUDIT_CONNECTION_CONNECT | \
MYSQL_AUDIT_CONNECTION_DISCONNECT | \
MYSQL_AUDIT_CONNECTION_CHANGE_USER | \
MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE)
/**
@struct mysql_event_connection
Structure for the MYSQL_AUDIT_CONNECTION_CLASS event class.
*/
struct mysql_event_connection
{
/** Event subclass. */
mysql_event_connection_subclass_t event_subclass;
/** Current status of the connection. */
int status;
/** Connection id. */
unsigned long connection_id;
/** User name of this connection. */
MYSQL_LEX_CSTRING user;
/** Priv user name. */
MYSQL_LEX_CSTRING priv_user;
/** External user name. */
MYSQL_LEX_CSTRING external_user;
/** Proxy user used for this connection. */
MYSQL_LEX_CSTRING proxy_user;
/** Connection host. */
MYSQL_LEX_CSTRING host;
/** IP of the connection. */
MYSQL_LEX_CSTRING ip;
/** Database name specified at connection time. */
MYSQL_LEX_CSTRING database;
/** Connection type:
- 0 Undefined
- 1 TCP/IP
- 2 Socket
- 3 Named pipe
- 4 SSL
- 5 Shared memory
*/
int connection_type;
};
/**
@enum mysql_event_parse_subclass_t
Events for MYSQL_AUDIT_PARSE_CLASS event class.
*/
typedef enum
{
/** occurs before the query parsing. */
MYSQL_AUDIT_PARSE_PREPARSE = 1 << 0,
/** occurs after the query parsing. */
MYSQL_AUDIT_PARSE_POSTPARSE = 1 << 1
} mysql_event_parse_subclass_t;
#define MYSQL_AUDIT_PARSE_ALL (MYSQL_AUDIT_PARSE_PREPARSE | \
MYSQL_AUDIT_PARSE_POSTPARSE)
typedef enum
{
MYSQL_AUDIT_PARSE_REWRITE_PLUGIN_NONE = 0,
/// mysql_event_parse::flags Must be set by a plugin if the query is rewritten.
MYSQL_AUDIT_PARSE_REWRITE_PLUGIN_QUERY_REWRITTEN = 1 << 0,
/// mysql_event_parse::flags Is set by the server if the query is prepared statement.
MYSQL_AUDIT_PARSE_REWRITE_PLUGIN_IS_PREPARED_STATEMENT = 1 << 1
} mysql_event_parse_rewrite_plugin_flag;
/** Data for the MYSQL_AUDIT_PARSE events */
struct mysql_event_parse
{
/** MYSQL_AUDIT_[PRE|POST]_PARSE event id */
mysql_event_parse_subclass_t event_subclass;
/** one of FLAG_REWRITE_PLUGIN_* */
mysql_event_parse_rewrite_plugin_flag *flags;
/** input: the original query text */
MYSQL_LEX_CSTRING query;
/** output: returns the null-terminated rewriten query allocated by my_malloc() */
MYSQL_LEX_CSTRING *rewritten_query;
};
/**
@enum mysql_event_authorization_subclass_t
Events for MYSQL_AUDIT_AUTHORIZATION_CLASS event class.
*/
typedef enum
{
MYSQL_AUDIT_AUTHORIZATION_USER = 1 << 0,
/** Occurs when database privilege is checked. */
MYSQL_AUDIT_AUTHORIZATION_DB = 1 << 1,
/** Occurs when table privilege is checked. */
MYSQL_AUDIT_AUTHORIZATION_TABLE = 1 << 2,
/** Occurs when column privilege is checked. */
MYSQL_AUDIT_AUTHORIZATION_COLUMN = 1 << 3,
/** Occurs when procedure privilege is checked. */
MYSQL_AUDIT_AUTHORIZATION_PROCEDURE = 1 << 4,
/** Occurs when proxy privilege is checked. */
MYSQL_AUDIT_AUTHORIZATION_PROXY = 1 << 5
} mysql_event_authorization_subclass_t;
#define MYSQL_AUDIT_AUTHORIZATION_ALL (MYSQL_AUDIT_AUTHORIZATION_USER | \
MYSQL_AUDIT_AUTHORIZATION_DB | \
MYSQL_AUDIT_AUTHORIZATION_TABLE | \
MYSQL_AUDIT_AUTHORIZATION_COLUMN | \
MYSQL_AUDIT_AUTHORIZATION_PROCEDURE | \
MYSQL_AUDIT_AUTHORIZATION_PROXY)
/**
@struct mysql_event_authorization
Structure for MYSQL_AUDIT_AUTHORIZATION_CLASS event class.
*/
struct mysql_event_authorization
{
/** Event subclass. */
mysql_event_authorization_subclass_t event_subclass;
/** Event status. */
int status;
/** Connection id. */
unsigned int connection_id;
/** SQL command id. */
enum_sql_command_t sql_command_id;
/** SQL query text. */
MYSQL_LEX_CSTRING query;
/** SQL query charset. */
const struct charset_info_st *query_charset;
/** Database name. */
MYSQL_LEX_CSTRING database;
/** Table name. */
MYSQL_LEX_CSTRING table;
/** Other name associated with the event. */
MYSQL_LEX_CSTRING object;
/** Requested authorization privileges. */
unsigned long requested_privilege;
/** Currently granted authorization privileges. */
unsigned long granted_privilege;
};
/**
@enum mysql_event_table_row_access_subclass_t
Events for MYSQL_AUDIT_TABLE_ACCES_CLASS event class.
*/
typedef enum
{
/** Occurs when table data are read. */
MYSQL_AUDIT_TABLE_ACCESS_READ = 1 << 0,
/** Occurs when table data are inserted. */
MYSQL_AUDIT_TABLE_ACCESS_INSERT = 1 << 1,
/** Occurs when table data are updated. */
MYSQL_AUDIT_TABLE_ACCESS_UPDATE = 1 << 2,
/** Occurs when table data are deleted. */
MYSQL_AUDIT_TABLE_ACCESS_DELETE = 1 << 3
} mysql_event_table_access_subclass_t;
#define MYSQL_AUDIT_TABLE_ACCESS_ALL (MYSQL_AUDIT_TABLE_ACCESS_READ | \
MYSQL_AUDIT_TABLE_ACCESS_INSERT | \
MYSQL_AUDIT_TABLE_ACCESS_UPDATE | \
MYSQL_AUDIT_TABLE_ACCESS_DELETE)
/**
@struct mysql_event_table_row_access
Structure for MYSQL_AUDIT_TABLE_ACCES_CLASS event class.
*/
struct mysql_event_table_access
{
/** Event subclass. */
mysql_event_table_access_subclass_t event_subclass;
/** Connection id. */
unsigned long connection_id;
/** SQL command id. */
enum_sql_command_t sql_command_id;
/** SQL query. */
MYSQL_LEX_CSTRING query;
/** SQL query charset. */
const struct charset_info_st *query_charset;
/** Database name. */
MYSQL_LEX_CSTRING table_database;
/** Table name. */
MYSQL_LEX_CSTRING table_name;
};
/**
@enum mysql_event_global_variable_subclass_t
Events for MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS event class.
*/
typedef enum
{
/** Occurs when global variable is retrieved. */
MYSQL_AUDIT_GLOBAL_VARIABLE_GET = 1 << 0,
/** Occurs when global variable is set. */
MYSQL_AUDIT_GLOBAL_VARIABLE_SET = 1 << 1
} mysql_event_global_variable_subclass_t;
#define MYSQL_AUDIT_GLOBAL_VARIABLE_ALL (MYSQL_AUDIT_GLOBAL_VARIABLE_GET | \
MYSQL_AUDIT_GLOBAL_VARIABLE_SET)
/** Events for MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS event class. */
struct mysql_event_global_variable
{
/** Event subclass. */
mysql_event_global_variable_subclass_t event_subclass;
/** Connection id. */
unsigned long connection_id;
/** SQL command id. */
enum_sql_command_t sql_command_id;
/** Variable name. */
MYSQL_LEX_CSTRING variable_name;
/** Variable value. */
MYSQL_LEX_CSTRING variable_value;
};
/**
@enum mysql_event_server_startup_subclass_t
Events for MYSQL_AUDIT_SERVER_STARTUP_CLASS event class.
*/
typedef enum
{
/** Occurs after all subsystem are initialized during system start. */
MYSQL_AUDIT_SERVER_STARTUP_STARTUP = 1 << 0
} mysql_event_server_startup_subclass_t;
#define MYSQL_AUDIT_SERVER_STARTUP_ALL (MYSQL_AUDIT_SERVER_STARTUP_STARTUP)
/**
@struct mysql_event_server_startup
Structure for MYSQL_AUDIT_SERVER_STARTUP_CLASS event class.
*/
struct mysql_event_server_startup
{
/** Event subclass. */
mysql_event_server_startup_subclass_t event_subclass;
/** Command line arguments. */
const char **argv;
/** Command line arguments count. */
unsigned int argc;
};
/**
@enum mysql_event_server_shutdown_subclass_t
Events for MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS event class.
*/
typedef enum
{
/** Occurs when global variable is set. */
MYSQL_AUDIT_SERVER_SHUTDOWN_SHUTDOWN = 1 << 0
} mysql_event_server_shutdown_subclass_t;
#define MYSQL_AUDIT_SERVER_SHUTDOWN_ALL (MYSQL_AUDIT_SERVER_SHUTDOWN_SHUTDOWN)
/**
@enum mysql_server_shutdown_reason_t
Server shutdown reason.
*/
typedef enum
{
/** User requested shut down. */
MYSQL_AUDIT_SERVER_SHUTDOWN_REASON_SHUTDOWN,
/** The server aborts. */
MYSQL_AUDIT_SERVER_SHUTDOWN_REASON_ABORT
} mysql_server_shutdown_reason_t;
/**
@struct mysql_event_server_shutdown
Structure for MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS event class.
*/
struct mysql_event_server_shutdown
{
/** Shutdown event. */
mysql_event_server_shutdown_subclass_t event_subclass;
/** Exit code associated with the shutdown event. */
int exit_code;
/** Shutdown reason. */
mysql_server_shutdown_reason_t reason;
};
/**
@enum mysql_event_command_subclass_t
Events for MYSQL_AUDIT_COMMAND_CLASS event class.
*/
typedef enum
{
/** Command start event. */
MYSQL_AUDIT_COMMAND_START = 1 << 0,
/** Command end event. */
MYSQL_AUDIT_COMMAND_END = 1 << 1
} mysql_event_command_subclass_t;
#define MYSQL_AUDIT_COMMAND_ALL (MYSQL_AUDIT_COMMAND_START | \
MYSQL_AUDIT_COMMAND_END)
/**
@typedef enum_server_command_t
Server command type definition.
*/
typedef enum enum_server_command enum_server_command_t;
/**
@struct mysql_event_command
Event for MYSQL_AUDIT_COMMAND_CLASS event class.
Events generated as a result of RPC command requests.
*/
struct mysql_event_command
{
/** Command event subclass. */
mysql_event_command_subclass_t event_subclass;
/** Command event status. */
int status;
/** Connection id. */
unsigned long connection_id;
/** Command id. */
enum_server_command_t command_id;
};
/**
@enum mysql_event_query_subclass_t
Events for MYSQL_AUDIT_QUERY_CLASS event class.
*/
typedef enum
{
/** Query start event. */
MYSQL_AUDIT_QUERY_START = 1 << 0,
/** Nested query start event. */
MYSQL_AUDIT_QUERY_NESTED_START = 1 << 1,
/** Query post parse event. */
MYSQL_AUDIT_QUERY_STATUS_END = 1 << 2,
/** Nested query status end event. */
MYSQL_AUDIT_QUERY_NESTED_STATUS_END = 1 << 3
} mysql_event_query_subclass_t;
#define MYSQL_AUDIT_QUERY_ALL (MYSQL_AUDIT_QUERY_START | \
MYSQL_AUDIT_QUERY_NESTED_START | \
MYSQL_AUDIT_QUERY_STATUS_END | \
MYSQL_AUDIT_QUERY_NESTED_STATUS_END)
/**
@struct mysql_event_command
Event for MYSQL_AUDIT_COMMAND_CLASS event class.
*/
struct mysql_event_query
{
/** Event subclass. */
mysql_event_query_subclass_t event_subclass;
/** Event status. */
int status;
/** Connection id. */
unsigned long connection_id;
/** SQL command id. */
enum_sql_command_t sql_command_id;
/** SQL query. */
MYSQL_LEX_CSTRING query;
/** SQL query charset. */
const struct charset_info_st *query_charset;
};
/**
@enum mysql_event_stored_program_subclass_t
Events for MYSQL_AUDIT_STORED_PROGRAM_CLASS event class.
*/
typedef enum
{
/** Stored program execution event. */
MYSQL_AUDIT_STORED_PROGRAM_EXECUTE = 1 << 0
} mysql_event_stored_program_subclass_t;
#define MYSQL_AUDIT_STORED_PROGRAM_ALL (MYSQL_AUDIT_STORED_PROGRAM_EXECUTE)
/**
@struct mysql_event_command
Event for MYSQL_AUDIT_COMMAND_CLASS event class.
*/
struct mysql_event_stored_program
{
/** Event subclass. */
mysql_event_stored_program_subclass_t event_subclass;
/** Connection id. */
unsigned long connection_id;
/** SQL command id. */
enum_sql_command_t sql_command_id;
/** SQL query text. */
MYSQL_LEX_CSTRING query;
/** SQL query charset. */
const struct charset_info_st *query_charset;
/** The Database the procedure is defined in. */
MYSQL_LEX_CSTRING database;
/** Name of the stored program. */
MYSQL_LEX_CSTRING name;
/** Stored program parameters. */
void *parameters;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,162 @@
#define PLUGIN_CONTEXT
#include <stdio.h>
typedef void *MYSQL_THD;
struct st_mysql_const_lex_string
{
const char *str;
size_t length;
};
typedef struct st_mysql_const_lex_string MYSQL_LEX_CSTRING;
enum enum_sql_command{ SQLCOM_A, SQLCOM_B };
enum enum_server_command{ SERVCOM_A, SERVCOM_B };
#include "plugin_audit_v4.h"
extern void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev);
extern int get_db_mysql57(MYSQL_THD thd, char **name, int *len);
struct mysql_event_general_302
{
unsigned int event_subclass;
int general_error_code;
unsigned long general_thread_id;
const char *general_user;
unsigned int general_user_length;
const char *general_command;
unsigned int general_command_length;
const char *general_query;
unsigned int general_query_length;
struct charset_info_st *general_charset;
unsigned long long general_time;
unsigned long long general_rows;
unsigned long long query_id;
char *database;
int database_length;
};
static int auditing_v4(MYSQL_THD thd, mysql_event_class_t class, const void *ev)
{
int *subclass= (int *)ev;
struct mysql_event_general_302 ev_302;
int subclass_v3, subclass_orig;
if (class != MYSQL_AUDIT_GENERAL_CLASS &&
class != MYSQL_AUDIT_CONNECTION_CLASS)
return 0;
subclass_orig= *subclass;
if (class == MYSQL_AUDIT_GENERAL_CLASS)
{
struct mysql_event_general *event= (struct mysql_event_general *) ev;
ev_302.general_error_code= event->general_error_code;
ev_302.general_thread_id= event->general_thread_id;
ev_302.general_user= event->general_user.str;
ev_302.general_user_length= event->general_user.length;
ev_302.general_command= event->general_command.str;
ev_302.general_command_length= event->general_command.length;
ev_302.general_query= event->general_query.str;
ev_302.general_query_length= event->general_query.length;
ev_302.general_charset= event->general_charset;
ev_302.general_time= event->general_time;
ev_302.general_rows= event->general_rows;
if (get_db_mysql57(thd, &ev_302.database, &ev_302.database_length))
{
ev_302.database= 0;
ev_302.database_length= 0;
}
ev= &ev_302;
switch (subclass_orig)
{
case MYSQL_AUDIT_GENERAL_LOG:
subclass_v3= 0;
ev_302.event_subclass= 0;
break;
case MYSQL_AUDIT_GENERAL_ERROR:
subclass_v3= 1;
ev_302.event_subclass= 1;
break;
case MYSQL_AUDIT_GENERAL_RESULT:
subclass_v3= 2;
ev_302.event_subclass= 2;
break;
case MYSQL_AUDIT_GENERAL_STATUS:
{
subclass_v3= 3;
ev_302.event_subclass= 3;
break;
}
default:
return 0;
}
}
else /* if (class == MYSQL_AUDIT_CONNECTION_CLASS) */
{
switch (subclass_orig)
{
case MYSQL_AUDIT_CONNECTION_CONNECT:
subclass_v3= 0;
break;
case MYSQL_AUDIT_CONNECTION_DISCONNECT:
subclass_v3= 1;
break;
default:
return 0;
}
}
*subclass= subclass_v3;
auditing(thd, (int) class, ev);
*subclass= subclass_orig;
return 0;
}
static struct st_mysql_audit mysql_descriptor =
{
MYSQL_AUDIT_INTERFACE_VERSION,
NULL,
auditing_v4,
{ (unsigned long) MYSQL_AUDIT_GENERAL_ALL,
(unsigned long) MYSQL_AUDIT_CONNECTION_ALL,
(unsigned long) MYSQL_AUDIT_PARSE_ALL,
0, /* This event class is currently not supported. */
0, /* This event class is currently not supported. */
(unsigned long) MYSQL_AUDIT_GLOBAL_VARIABLE_ALL,
(unsigned long) MYSQL_AUDIT_SERVER_STARTUP_ALL,
(unsigned long) MYSQL_AUDIT_SERVER_SHUTDOWN_ALL,
(unsigned long) MYSQL_AUDIT_COMMAND_ALL,
(unsigned long) MYSQL_AUDIT_QUERY_ALL,
(unsigned long) MYSQL_AUDIT_STORED_PROGRAM_ALL }
#ifdef WHEN_MYSQL_BUG_FIXED
/*
By this moment MySQL just sends no notifications at all
when we request only those we actually need.
So we have to request everything and filter them inside the
handling function.
*/
{ (unsigned long) MYSQL_AUDIT_GENERAL_ALL,
(unsigned long) (MYSQL_AUDIT_CONNECTION_CONNECT |
MYSQL_AUDIT_CONNECTION_DISCONNECT),
0,
0, /* This event class is currently not supported. */
0, /* This event class is currently not supported. */
0,
0,
0,
0,
0,
0
}
#endif /*WHEN_MYSQL_BUG_FIXED*/
};
void *mysql_v4_descriptor= &mysql_descriptor;

View File

@ -79,8 +79,6 @@ INSTALL(FILES
${CMAKE_CURRENT_SOURCE_DIR}/mysql_performance_tables.sql
${CMAKE_CURRENT_SOURCE_DIR}/fill_help_tables.sql
${CMAKE_CURRENT_SOURCE_DIR}/mysql_test_data_timezone.sql
${CMAKE_CURRENT_SOURCE_DIR}/maria_add_gis_sp.sql
${CMAKE_CURRENT_SOURCE_DIR}/maria_add_gis_sp_bootstrap.sql
${FIX_PRIVILEGES_SQL}
DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server
)
@ -287,6 +285,34 @@ ELSE()
ENDFOREACH()
ENDIF()
# Configure two scripts from one 'in' file.
# The maria_add_gis_sp.sql - to be sent to 'mysql' tool
# and the maria_add_gis_sp_bootstrap.sql, that can be sent to
# the server as a bootstrap command.
SET(ADD_GIS_SP_SET_DELIMITER "delimiter |")
SET(ADD_GIS_SP_RESET_DELIMITER "delimiter ;")
SET(ADD_GIS_SP_EOL "|")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/maria_add_gis_sp.sql.in
${CMAKE_CURRENT_BINARY_DIR}/maria_add_gis_sp.sql ESCAPE_QUOTES @ONLY)
INSTALL_SCRIPT(${CMAKE_CURRENT_BINARY_DIR}/maria_add_gis_sp.sql
DESTINATION ${INSTALL_BINDIR}
COMPONENT Server
)
SET(ADD_GIS_SP_SET_DELIMITER "")
SET(ADD_GIS_SP_RESET_DELIMITER "")
SET(ADD_GIS_SP_EOL ";")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/maria_add_gis_sp.sql.in
${CMAKE_CURRENT_BINARY_DIR}/maria_add_gis_sp_bootstrap.sql ESCAPE_QUOTES @ONLY)
INSTALL_SCRIPT(${CMAKE_CURRENT_BINARY_DIR}/maria_add_gis_sp.sql
${CMAKE_CURRENT_BINARY_DIR}/maria_add_gis_sp_bootstrap.sql
DESTINATION ${INSTALL_MYSQLSHAREDIR}
COMPONENT Server
)
# Install libgcc as mylibgcc.a
IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_FLAGS MATCHES "-static")
EXECUTE_PROCESS (

View File

@ -1,48 +0,0 @@
-- Copyright (C) 2014 MariaDB 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-1301 USA
-- This part creates stored procedures required by the OpenGIS standards.
-- Proc privilege is needed to run it.
-- To use this file, load its contents into the mysql database like that:
-- mysql -u root -p mysql < scripts/maria_add_gis_sp.sql
SET sql_mode='';
DROP PROCEDURE IF EXISTS AddGeometryColumn;
DROP PROCEDURE IF EXISTS DropGeometryColumn;
delimiter |
CREATE PROCEDURE AddGeometryColumn(catalog varchar(64), t_schema varchar(64),
t_name varchar(64), geometry_column varchar(64), t_srid int)
begin
set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' ADD ', geometry_column,' GEOMETRY REF_SYSTEM_ID=', t_srid);
PREPARE ls from @qwe;
execute ls;
deallocate prepare ls;
end|
CREATE PROCEDURE DropGeometryColumn(catalog varchar(64), t_schema varchar(64),
t_name varchar(64), geometry_column varchar(64))
begin
set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' DROP ', geometry_column);
PREPARE ls from @qwe;
execute ls;
deallocate prepare ls;
end|
delimiter ;

View File

@ -18,17 +18,20 @@
SET sql_mode='';
@ADD_GIS_SP_SET_DELIMITER@
DROP PROCEDURE IF EXISTS AddGeometryColumn;
DROP PROCEDURE IF EXISTS DropGeometryColumn;
CREATE PROCEDURE AddGeometryColumn(catalog varchar(64), t_schema varchar(64),
t_name varchar(64), geometry_column varchar(64), t_srid int)
begin
set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' ADD ', geometry_column,' GEOMETRY REF_SYSTEM_ID=', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end;
set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' ADD ', geometry_column,' GEOMETRY REF_SYSTEM_ID=', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end @ADD_GIS_SP_EOL@
CREATE PROCEDURE DropGeometryColumn(catalog varchar(64), t_schema varchar(64),
t_name varchar(64), geometry_column varchar(64))
begin
set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' DROP ', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end;
set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' DROP ', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end @ADD_GIS_SP_EOL@
@ADD_GIS_SP_RESET_DELIMITER@

View File

@ -4337,6 +4337,7 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
stacksize= ASYNC_CONTEXT_DEFAULT_STACK_SIZE;
if (my_context_init(&ctxt->async_context, stacksize))
{
set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
my_free(ctxt);
DBUG_RETURN(1);
}

Some files were not shown because too many files have changed in this diff Show More