Commit c9552533 authored by Alexey Botchkov's avatar Alexey Botchkov

MDEV-9106 Audit plugin compiled with MariaDB can't install on MySQL 5.7.

        The audit API was seriously changed in MySQL 5.7.
        so we had to adapt the plugin's code to that.
parent 5f48b615
...@@ -8,6 +8,7 @@ server_audit_file_rotate_now OFF ...@@ -8,6 +8,7 @@ server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000 server_audit_file_rotate_size 1000000
server_audit_file_rotations 9 server_audit_file_rotations 9
server_audit_incl_users server_audit_incl_users
server_audit_loc_info
server_audit_logging OFF server_audit_logging OFF
server_audit_mode 0 server_audit_mode 0
server_audit_output_type file server_audit_output_type file
...@@ -71,6 +72,7 @@ server_audit_file_rotate_now OFF ...@@ -71,6 +72,7 @@ server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000 server_audit_file_rotate_size 1000000
server_audit_file_rotations 9 server_audit_file_rotations 9
server_audit_incl_users odin, root, dva, tri server_audit_incl_users odin, root, dva, tri
server_audit_loc_info
server_audit_logging ON server_audit_logging ON
server_audit_mode 0 server_audit_mode 0
server_audit_output_type file server_audit_output_type file
...@@ -216,6 +218,7 @@ server_audit_file_rotate_now OFF ...@@ -216,6 +218,7 @@ server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000 server_audit_file_rotate_size 1000000
server_audit_file_rotations 9 server_audit_file_rotations 9
server_audit_incl_users odin, root, dva, tri server_audit_incl_users odin, root, dva, tri
server_audit_loc_info
server_audit_logging ON server_audit_logging ON
server_audit_mode 1 server_audit_mode 1
server_audit_output_type file server_audit_output_type file
...@@ -229,9 +232,9 @@ Warnings: ...@@ -229,9 +232,9 @@ Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown Warning 1620 Plugin is busy and will be uninstalled on shutdown
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_logging=on',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_logging=on',0
TIME,HOSTNAME,root,localhost,ID,0,CONNECT,mysql,,0 TIME,HOSTNAME,root,localhost,ID,0,CONNECT,mysql,,0
TIME,HOSTNAME,root,localhost,ID,0,DISCONNECT,mysql,,0 TIME,HOSTNAME,,,ID,0,DISCONNECT,,,0
TIME,HOSTNAME,no_such_user,localhost,ID,0,FAILED_CONNECT,,,ID TIME,HOSTNAME,no_such_user,localhost,ID,0,FAILED_CONNECT,,,ID
TIME,HOSTNAME,no_such_user,localhost,ID,0,DISCONNECT,,,0 TIME,HOSTNAME,,,ID,0,DISCONNECT,,,0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_incl_users=\'odin, root, dva, tri\'',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_incl_users=\'odin, root, dva, tri\'',0
TIME,HOSTNAME,root,localhost,ID,ID,CREATE,test,t2, TIME,HOSTNAME,root,localhost,ID,ID,CREATE,test,t2,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'create table t2 (id int)',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'create table t2 (id int)',0
...@@ -281,7 +284,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,READ,mysql,proc, ...@@ -281,7 +284,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,proc,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,event, 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,ID,QUERY,sa_db,'drop database sa_db',0
TIME,HOSTNAME,root,localhost,ID,0,DISCONNECT,sa_db,,0 TIME,HOSTNAME,,,ID,0,DISCONNECT,,,0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'create database sa_db',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,QUERY,sa_db,'use sa_db',0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,
......
...@@ -14,11 +14,13 @@ ...@@ -14,11 +14,13 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef FLOGGER_SKIP_INCLUDES
#include "my_global.h" #include "my_global.h"
#include <my_sys.h> #include <my_sys.h>
#include <m_string.h> #include <m_string.h>
#include <mysql/service_logger.h> #include <mysql/service_logger.h>
#include <my_pthread.h> #include <my_pthread.h>
#endif /*FLOGGER_SKIP_INCLUDES*/
#ifndef flogger_mutex_init #ifndef flogger_mutex_init
#define flogger_mutex_init(A,B,C) mysql_mutex_init(A,B,C) #define flogger_mutex_init(A,B,C) mysql_mutex_init(A,B,C)
......
...@@ -13,4 +13,7 @@ ...@@ -13,4 +13,7 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # 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)
/* 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
/* Copyright (C) 2013 Alexey Botchkov and SkySQL Ab /* Copyright (C) 2013, 2015, Alexey Botchkov and SkySQL Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -14,13 +14,16 @@ ...@@ -14,13 +14,16 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define PLUGIN_VERSION 0x103 #define PLUGIN_VERSION 0x104
#define PLUGIN_STR_VERSION "1.3.0" #define PLUGIN_STR_VERSION "1.4.0"
#define _my_thread_var loc_thread_var
#include <my_config.h> #include <my_config.h>
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#include <string.h> #include <string.h>
#include <fcntl.h>
#ifndef _WIN32 #ifndef _WIN32
#include <syslog.h> #include <syslog.h>
...@@ -80,8 +83,7 @@ static void closelog() {} ...@@ -80,8 +83,7 @@ static void closelog() {}
#endif /*MARIADB_ONLY*/ #endif /*MARIADB_ONLY*/
#include <my_base.h> #include <my_base.h>
//#include <hash.h> //#include <my_dir.h>
#include <my_dir.h>
#include <typelib.h> #include <typelib.h>
#include <mysql/plugin.h> #include <mysql/plugin.h>
#include <mysql/plugin_audit.h> #include <mysql/plugin_audit.h>
...@@ -89,65 +91,135 @@ static void closelog() {} ...@@ -89,65 +91,135 @@ static void closelog() {}
#define RTLD_DEFAULT NULL #define RTLD_DEFAULT NULL
#endif #endif
#undef my_init_dynamic_array_ci
#define init_dynamic_array2 loc_init_dynamic_array2
#define my_init_dynamic_array_ci(A,B,C,D) loc_init_dynamic_array2(A,B,NULL,C,D)
#define _my_hash_init loc_my_hash_init
#define my_hash_search loc_my_hash_search
#define my_hash_insert loc_my_hash_insert
#define my_hash_delete loc_my_hash_delete
#define my_hash_update loc_my_hash_update
#define my_hash_free loc_my_hash_free
#define my_hash_first loc_my_hash_first
#define my_hash_reset loc_my_hash_reset
#define my_hash_search_using_hash_value loc_my_hash_search_using_hash_value
#define my_hash_first_from_hash_value loc_my_hash_first_from_hash_value
#define my_calc_hash loc_my_calc_hash
#undef my_hash_first_from_hash_value
#define my_hash_first_from_hash_value loc_my_my_hash_first_from_hash_value
#define my_hash_next loc_my_hash_next
#define my_hash_element loc_my_hash_element
#define my_hash_replace loc_my_hash_replace
#define my_hash_iterate loc_my_hash_iterate
#define alloc_dynamic loc_alloc_dynamic
#define pop_dynamic loc_pop_dynamic
#define delete_dynamic loc_delete_dynamic
uchar *loc_alloc_dynamic(DYNAMIC_ARRAY *array);
#ifdef my_strnncoll
#undef my_strnncoll
#define my_strnncoll(s, a, b, c, d) (my_strnncoll_binary((s), (a), (b), (c), (d), 0))
#endif
static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)),
const uchar *s, size_t slen,
const uchar *t, size_t tlen,
my_bool t_is_prefix)
{
size_t len=min(slen,tlen);
int cmp= memcmp(s,t,len);
return cmp ? cmp : (int)((t_is_prefix ? len : slen) - tlen);
}
#include "../../mysys/array.c"
#include "../../mysys/hash.c"
#ifndef MARIADB_ONLY #ifndef MARIADB_ONLY
#undef MYSQL_SERVICE_LOGGER_INCLUDED #undef MYSQL_SERVICE_LOGGER_INCLUDED
#undef MYSQL_DYNAMIC_PLUGIN #undef MYSQL_DYNAMIC_PLUGIN
#define FLOGGER_NO_PSI #define FLOGGER_NO_PSI
#define flogger_mutex_init(A,B,C) pthread_mutex_init(&(B)->m_mutex, C)
#define flogger_mutex_destroy(A) pthread_mutex_destroy(&(A)->m_mutex) /* How to access the pthread_mutex in mysql_mutex_t */
#define flogger_mutex_lock(A) pthread_mutex_lock(&(A)->m_mutex) //#ifdef SAFE_MUTEX
#define flogger_mutex_unlock(A) pthread_mutex_unlock(&(A)->m_mutex) //#define mysql_mutex_real_mutex(A) &(A)->m_mutex.mutex
//#elif defined(MY_PTHREAD_FASTMUTEX)
//#define mysql_mutex_real_mutex(A) &(A)->m_mutex.mutex
//#else
#define mysql_mutex_real_mutex(A) &(A)->m_mutex
//#endif
#define flogger_mutex_init(A,B,C) do{}while(0)
#define flogger_mutex_destroy(A) do{}while(0)
#define flogger_mutex_lock(A) do{}while(0)
#define flogger_mutex_unlock(A) do{}while(0)
static char **int_mysql_data_home; static char **int_mysql_data_home;
static char *default_home= (char *)"."; static char *default_home= (char *)".";
#define mysql_data_home (*int_mysql_data_home) #define mysql_data_home (*int_mysql_data_home)
#define FLOGGER_SKIP_INCLUDES
#define my_open(A, B, C) loc_open(A, B)
#define my_close(A, B) close(A)
#define my_rename(A, B, C) loc_rename(A, B)
#define my_tell(A, B) loc_tell(A)
#define my_write(A, B, C, D) write(A, B, C)
#define my_malloc(A, B) malloc(A)
#define my_free(A) free(A)
#ifdef my_vsnprintf
#undef my_vsnprintf
#endif
#define my_vsnprintf vsnprintf
File loc_open(const char *FileName, int Flags)
/* Path-name of file */
/* Read | write .. */
/* Special flags */
{
File fd;
#if defined(_WIN32)
fd= my_win_open(FileName, Flags);
#elif !defined(NO_OPEN_3)
fd = open(FileName, Flags, my_umask); /* Normal unix */
#else
fd = open((char *) FileName, Flags);
#endif
return fd;
}
static int loc_rename(const char *from, const char *to)
{
int error = 0;
#if defined(__WIN__)
if (!MoveFileEx(from, to, MOVEFILE_COPY_ALLOWED |
MOVEFILE_REPLACE_EXISTING))
{
my_osmaperr(GetLastError());
#elif defined(HAVE_RENAME)
if (rename(from,to))
{
#else
if (link(from, to) || unlink(from))
{
#endif
my_errno=errno;
error = -1;
}
return error;
}
static my_off_t loc_seek(File fd, my_off_t pos, int whence)
{
os_off_t newpos= -1;
#ifdef _WIN32
newpos= my_win_lseek(fd, pos, whence);
#else
newpos= lseek(fd, pos, whence);
#endif
if (newpos == (os_off_t) -1)
{
my_errno= errno;
return MY_FILEPOS_ERROR;
}
return (my_off_t) newpos;
}
static my_off_t loc_tell(File fd)
{
os_off_t pos;
#if defined (HAVE_TELL) && !defined (_WIN32)
pos= tell(fd);
#else
pos= loc_seek(fd, 0L, MY_SEEK_CUR);
#endif
if (pos == (os_off_t) -1)
{
my_errno= errno;
}
return (my_off_t) pos;
}
#ifdef HAVE_PSI_INTERFACE
#undef HAVE_PSI_INTERFACE
#include <mysql/service_logger.h>
#include "../../mysys/file_logger.c"
#define HAVE_PSI_INTERFACE
#else
#include <mysql/service_logger.h>
#include "../../mysys/file_logger.c" #include "../../mysys/file_logger.c"
#endif
#endif /*!MARIADB_ONLY*/ #endif /*!MARIADB_ONLY*/
#undef flogger_mutex_init
#undef flogger_mutex_destroy
#undef flogger_mutex_lock
#undef flogger_mutex_unlock
#define flogger_mutex_init(A,B,C) pthread_mutex_init(mysql_mutex_real_mutex(B), C)
#define flogger_mutex_destroy(A) pthread_mutex_destroy(mysql_mutex_real_mutex(A))
#define flogger_mutex_lock(A) pthread_mutex_lock(mysql_mutex_real_mutex(A))
#define flogger_mutex_unlock(A) pthread_mutex_unlock(mysql_mutex_real_mutex(A))
#ifndef DBUG_OFF #ifndef DBUG_OFF
#define PLUGIN_DEBUG_VERSION "-debug" #define PLUGIN_DEBUG_VERSION "-debug"
#else #else
...@@ -168,7 +240,11 @@ static char *default_home= (char *)"."; ...@@ -168,7 +240,11 @@ static char *default_home= (char *)".";
extern char server_version[]; extern char server_version[];
static const char *serv_ver= NULL; static const char *serv_ver= NULL;
static int started_mysql= 0; static int started_mysql= 0;
static int mysql_57_started= 0;
static int debug_server_started= 0;
static int use_event_data_for_disconnect= 0;
static int started_mariadb= 0; static int started_mariadb= 0;
static int maria_55_started= 0;
static int maria_above_5= 0; static int maria_above_5= 0;
static char *incl_users, *excl_users, static char *incl_users, *excl_users,
*file_path, *syslog_info; *file_path, *syslog_info;
...@@ -193,6 +269,27 @@ static char servhost[256]; ...@@ -193,6 +269,27 @@ static char servhost[256];
static size_t servhost_len; static size_t servhost_len;
static char *syslog_ident; static char *syslog_ident;
static char syslog_ident_buffer[128]= "mysql-server_auditing"; static char syslog_ident_buffer[128]= "mysql-server_auditing";
struct connection_info
{
int header;
unsigned long thread_id;
unsigned long long query_id;
char db[256];
int db_length;
char user[64];
int user_length;
char host[64];
int host_length;
char ip[64];
int ip_length;
const char *query;
int query_length;
char query_buffer[1024];
time_t query_time;
int log_always;
};
#define DEFAULT_FILENAME_LEN 16 #define DEFAULT_FILENAME_LEN 16
static char default_file_name[DEFAULT_FILENAME_LEN+1]= "server_audit.log"; static char default_file_name[DEFAULT_FILENAME_LEN+1]= "server_audit.log";
...@@ -246,7 +343,8 @@ static TYPELIB events_typelib= ...@@ -246,7 +343,8 @@ static TYPELIB events_typelib=
array_elements(event_names) - 1, "", event_names, NULL array_elements(event_names) - 1, "", event_names, NULL
}; };
static MYSQL_SYSVAR_SET(events, events, PLUGIN_VAR_RQCMDARG, static MYSQL_SYSVAR_SET(events, events, PLUGIN_VAR_RQCMDARG,
"Specifies the set of events to monitor. Can be CONNECT, QUERY, TABLE, QUERY_DDL, QUERY_DML.", "Specifies the set of events to monitor. Can be CONNECT, QUERY, TABLE,"
" QUERY_DDL, QUERY_DML, QUERY_DCL.",
NULL, NULL, 0, &events_typelib); NULL, NULL, 0, &events_typelib);
#define OUTPUT_SYSLOG 0 #define OUTPUT_SYSLOG 0
#define OUTPUT_FILE 1 #define OUTPUT_FILE 1
...@@ -287,6 +385,13 @@ static MYSQL_SYSVAR_UINT(query_log_limit, query_log_limit, ...@@ -287,6 +385,13 @@ static MYSQL_SYSVAR_UINT(query_log_limit, query_log_limit,
PLUGIN_VAR_OPCMDARG, "Limit on the length of the query string in a record.", PLUGIN_VAR_OPCMDARG, "Limit on the length of the query string in a record.",
NULL, NULL, 1024, 0, 0x7FFFFFFF, 1); NULL, NULL, 1024, 0, 0x7FFFFFFF, 1);
char locinfo_ini_value[sizeof(struct connection_info)+4];
static MYSQL_THDVAR_STR(loc_info,
PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC,
"Auxiliary info.", NULL, NULL,
locinfo_ini_value);
static const char *syslog_facility_names[]= static const char *syslog_facility_names[]=
{ {
"LOG_USER", "LOG_MAIL", "LOG_DAEMON", "LOG_AUTH", "LOG_USER", "LOG_MAIL", "LOG_DAEMON", "LOG_AUTH",
...@@ -366,6 +471,7 @@ static struct st_mysql_sys_var* vars[] = { ...@@ -366,6 +471,7 @@ static struct st_mysql_sys_var* vars[] = {
MYSQL_SYSVAR(syslog_facility), MYSQL_SYSVAR(syslog_facility),
MYSQL_SYSVAR(syslog_priority), MYSQL_SYSVAR(syslog_priority),
MYSQL_SYSVAR(query_log_limit), MYSQL_SYSVAR(query_log_limit),
MYSQL_SYSVAR(loc_info),
NULL NULL
}; };
...@@ -376,6 +482,8 @@ static long log_write_failures= 0; ...@@ -376,6 +482,8 @@ static long log_write_failures= 0;
static char current_log_buf[FN_REFLEN]= ""; static char current_log_buf[FN_REFLEN]= "";
static char last_error_buf[512]= ""; static char last_error_buf[512]= "";
extern void *mysql_v4_descriptor;
static struct st_mysql_show_var audit_status[]= static struct st_mysql_show_var audit_status[]=
{ {
{"server_audit_active", (char *)&is_active, SHOW_BOOL}, {"server_audit_active", (char *)&is_active, SHOW_BOOL},
...@@ -415,7 +523,7 @@ static uchar *getkey_user(const char *entry, size_t *length, ...@@ -415,7 +523,7 @@ static uchar *getkey_user(const char *entry, size_t *length,
} }
static void blank_user(uchar *user) static void blank_user(char *user)
{ {
for (; *user && *user != ','; user++) for (; *user && *user != ','; user++)
*user= ' '; *user= ' ';
...@@ -475,19 +583,98 @@ static void remove_blanks(char *user) ...@@ -475,19 +583,98 @@ static void remove_blanks(char *user)
} }
static int user_hash_fill(HASH *h, char *users, struct user_name
HASH *cmp_hash, int take_over_cmp) {
int name_len;
char *name;
};
struct user_coll
{
int n_users;
struct user_name *users;
int n_alloced;
};
static void coll_init(struct user_coll *c)
{
c->n_users= 0;
c->users= 0;
c->n_alloced= 0;
}
static void coll_free(struct user_coll *c)
{
if (c->users)
{
free(c->users);
coll_init(c);
}
}
static int cmp_users(const void *ia, const void *ib)
{
const struct user_name *a= (const struct user_name *) ia;
const struct user_name *b= (const struct user_name *) ib;
int dl= a->name_len - b->name_len;
if (dl != 0)
return dl;
return strncmp(a->name, b->name, a->name_len);
}
static char *coll_search(struct user_coll *c, const char *n, int len)
{
struct user_name un;
struct user_name *found;
un.name_len= len;
un.name= (char *) n;
found= (struct user_name*) bsearch(&un, c->users, c->n_users,
sizeof(c->users[0]), cmp_users);
return found ? found->name : 0;
}
static int coll_insert(struct user_coll *c, char *n, int len)
{
if (c->n_users >= c->n_alloced)
{
c->n_alloced+= 128;
if (c->users == NULL)
c->users= malloc(c->n_alloced * sizeof(c->users[0]));
else
c->users= realloc(c->users, c->n_alloced * sizeof(c->users[0]));
if (c->users == NULL)
return 1;
}
c->users[c->n_users].name= n;
c->users[c->n_users].name_len= len;
c->n_users++;
return 0;
}
static void coll_sort(struct user_coll *c)
{
qsort(c->users, c->n_users, sizeof(c->users[0]), cmp_users);
}
static int user_coll_fill(struct user_coll *c, char *users,
struct user_coll *cmp_c, int take_over_cmp)
{ {
char *orig_users= users; char *orig_users= users;
uchar *cmp_user= 0; char *cmp_user= 0;
size_t cmp_length; size_t cmp_length;
int refill_cmp_hash= 0; int refill_cmp_coll= 0;
if (my_hash_inited(h)) c->n_users= 0;
my_hash_reset(h);
else
loc_my_hash_init(h, 0, &my_charset_bin, 0x100, 0, 0,
(my_hash_get_key) getkey_user, 0, 0);
while (*users) while (*users)
{ {
...@@ -496,11 +683,10 @@ static int user_hash_fill(HASH *h, char *users, ...@@ -496,11 +683,10 @@ static int user_hash_fill(HASH *h, char *users,
if (!*users) if (!*users)
return 0; return 0;
(void) getkey_user(users, &cmp_length, FALSE);
if (cmp_hash) if (cmp_c)
{ {
(void) getkey_user(users, &cmp_length, FALSE); cmp_user= coll_search(cmp_c, users, cmp_length);
cmp_user= my_hash_search(cmp_hash, (const uchar *) users, cmp_length);
if (cmp_user && take_over_cmp) if (cmp_user && take_over_cmp)
{ {
...@@ -510,7 +696,7 @@ static int user_hash_fill(HASH *h, char *users, ...@@ -510,7 +696,7 @@ static int user_hash_fill(HASH *h, char *users,
MYF(ME_JUST_WARNING), (int) cmp_length, users); MYF(ME_JUST_WARNING), (int) cmp_length, users);
internal_stop_logging= 0; internal_stop_logging= 0;
blank_user(cmp_user); blank_user(cmp_user);
refill_cmp_hash= 1; refill_cmp_coll= 1;
} }
else if (cmp_user) else if (cmp_user)
{ {
...@@ -522,7 +708,7 @@ static int user_hash_fill(HASH *h, char *users, ...@@ -522,7 +708,7 @@ static int user_hash_fill(HASH *h, char *users,
continue; continue;
} }
} }
if (my_hash_insert(h, (const uchar *) users)) if (coll_insert(c, users, cmp_length))
return 1; return 1;
while (*users && *users != ',') while (*users && *users != ',')
users++; users++;
...@@ -531,15 +717,17 @@ static int user_hash_fill(HASH *h, char *users, ...@@ -531,15 +717,17 @@ static int user_hash_fill(HASH *h, char *users,
users++; users++;
} }
if (refill_cmp_hash) if (refill_cmp_coll)
{ {
remove_blanks(excl_users); remove_blanks(excl_users);
return user_hash_fill(cmp_hash, excl_users, 0, 0); return user_coll_fill(cmp_c, excl_users, 0, 0);
} }
if (users > orig_users && users[-1] == ',') if (users > orig_users && users[-1] == ',')
users[-1]= 0; users[-1]= 0;
coll_sort(c);
return 0; return 0;
} }
...@@ -668,48 +856,19 @@ static void error_header() ...@@ -668,48 +856,19 @@ static void error_header()
static LOGGER_HANDLE *logfile; static LOGGER_HANDLE *logfile;
static HASH incl_user_hash, excl_user_hash; static struct user_coll incl_user_coll, excl_user_coll;
static unsigned long long query_counter= 1; static unsigned long long query_counter= 1;
struct connection_info
{
unsigned long thread_id;
unsigned long long query_id;
char db[256];
int db_length;
char user[64];
int user_length;
char host[64];
int host_length;
char ip[64];
int ip_length;
const char *query;
int query_length;
char query_buffer[1024];
time_t query_time;
int log_always;
};
static HASH connection_hash;
struct connection_info *alloc_connection()
{
return malloc(ALIGN_SIZE(sizeof(struct connection_info)));
}
void free_connection(void* pconn) static struct connection_info *get_loc_info(MYSQL_THD thd)
{ {
(void) free(pconn); return (struct connection_info *) THDVAR(thd, loc_info);
} }
static struct connection_info *find_connection(unsigned long id) static int ci_needs_setup(const struct connection_info *ci)
{ {
return (struct connection_info *) return ci->header != 0;
my_hash_search(&connection_hash, (const uchar *) &id, sizeof(id));
} }
...@@ -873,15 +1032,24 @@ static int stop_logging() ...@@ -873,15 +1032,24 @@ static int stop_logging()
return 0; return 0;
} }
static struct connection_info *
add_connection(const struct mysql_event_connection *event) static void setup_connection_simple(struct connection_info *ci)
{
ci->db_length= 0;
ci->user_length= 0;
ci->host_length= 0;
ci->ip_length= 0;
ci->query_length= 0;
ci->header= 0;
}
static void setup_connection_connect(struct connection_info *cn,
const struct mysql_event_connection *event)
{ {
struct connection_info *cn= alloc_connection();
if (!cn)
return 0;
cn->thread_id= event->thread_id;
cn->query_id= 0; cn->query_id= 0;
cn->log_always= 0; cn->log_always= 0;
cn->thread_id= event->thread_id;
get_str_n(cn->db, &cn->db_length, sizeof(cn->db), get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
event->database, event->database_length); event->database, event->database_length);
get_str_n(cn->user, &cn->user_length, sizeof(cn->db), get_str_n(cn->user, &cn->user_length, sizeof(cn->db),
...@@ -890,11 +1058,7 @@ static struct connection_info * ...@@ -890,11 +1058,7 @@ static struct connection_info *
event->host, event->host_length); event->host, event->host_length);
get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip), get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
event->ip, event->ip_length); event->ip, event->ip_length);
cn->header= 0;
if (my_hash_insert(&connection_hash, (const uchar *) cn))
return 0;
return cn;
} }
...@@ -917,46 +1081,43 @@ do { \ ...@@ -917,46 +1081,43 @@ do { \
static struct connection_info * static void setup_connection_initdb(struct connection_info *cn,
add_connection_initdb(const struct mysql_event_general *event) const struct mysql_event_general *event)
{ {
struct connection_info *cn;
size_t user_len, host_len, ip_len; size_t user_len, host_len, ip_len;
char uh_buffer[512]; char uh_buffer[512];
if (get_user_host(event->general_user, event->general_user_length,
uh_buffer, sizeof(uh_buffer),
&user_len, &host_len, &ip_len) ||
(cn= alloc_connection()) == NULL)
return 0;
cn->thread_id= event->general_thread_id; cn->thread_id= event->general_thread_id;
cn->query_id= 0; cn->query_id= 0;
cn->log_always= 0; cn->log_always= 0;
get_str_n(cn->db, &cn->db_length, sizeof(cn->db), get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
event->general_query, event->general_query_length); event->general_query, event->general_query_length);
get_str_n(cn->user, &cn->user_length, sizeof(cn->db),
uh_buffer, user_len);
get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
uh_buffer+user_len+1, host_len);
get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
uh_buffer+user_len+1+host_len+1, ip_len);
if (my_hash_insert(&connection_hash, (const uchar *) cn)) if (get_user_host(event->general_user, event->general_user_length,
return 0; uh_buffer, sizeof(uh_buffer),
&user_len, &host_len, &ip_len))
return cn; {
/* The user@host line is incorrect. */
cn->user_length= 0;
cn->host_length= 0;
cn->ip_length= 0;
}
else
{
get_str_n(cn->user, &cn->user_length, sizeof(cn->db),
uh_buffer, user_len);
get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
uh_buffer+user_len+1, host_len);
get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
uh_buffer+user_len+1+host_len+1, ip_len);
}
cn->header= 0;
} }
static struct connection_info * static void setup_connection_table(struct connection_info *cn,
add_connection_table(const struct mysql_event_table *event) const struct mysql_event_table *event)
{ {
struct connection_info *cn;
if ((cn= alloc_connection()) == NULL)
return 0;
cn->thread_id= event->thread_id; cn->thread_id= event->thread_id;
cn->query_id= query_counter++; cn->query_id= query_counter++;
cn->log_always= 0; cn->log_always= 0;
...@@ -968,42 +1129,40 @@ static struct connection_info * ...@@ -968,42 +1129,40 @@ static struct connection_info *
event->host, SAFE_STRLEN(event->host)); event->host, SAFE_STRLEN(event->host));
get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip), get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
event->ip, SAFE_STRLEN(event->ip)); event->ip, SAFE_STRLEN(event->ip));
cn->header= 0;
if (my_hash_insert(&connection_hash, (const uchar *) cn))
return 0;
return cn;
} }
static struct connection_info * static void setup_connection_query(struct connection_info *cn,
add_connection_query(const struct mysql_event_general *event) const struct mysql_event_general *event)
{ {
struct connection_info *cn;
size_t user_len, host_len, ip_len; size_t user_len, host_len, ip_len;
char uh_buffer[512]; char uh_buffer[512];
if (get_user_host(event->general_user, event->general_user_length,
uh_buffer, sizeof(uh_buffer),
&user_len, &host_len, &ip_len) ||
(cn= alloc_connection()) == NULL)
return 0;
cn->thread_id= event->general_thread_id; cn->thread_id= event->general_thread_id;
cn->query_id= query_counter++; cn->query_id= query_counter++;
cn->log_always= 0; cn->log_always= 0;
get_str_n(cn->db, &cn->db_length, sizeof(cn->db), "", 0); get_str_n(cn->db, &cn->db_length, sizeof(cn->db), "", 0);
get_str_n(cn->user, &cn->user_length, sizeof(cn->db),
uh_buffer, user_len);
get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
uh_buffer+user_len+1, host_len);
get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
uh_buffer+user_len+1+host_len+1, ip_len);
if (my_hash_insert(&connection_hash, (const uchar *) cn))
return 0;
return cn; if (get_user_host(event->general_user, event->general_user_length,
uh_buffer, sizeof(uh_buffer),
&user_len, &host_len, &ip_len))
{
/* The user@host line is incorrect. */
cn->user_length= 0;
cn->host_length= 0;
cn->ip_length= 0;
}
else
{
get_str_n(cn->user, &cn->user_length, sizeof(cn->db),
uh_buffer, user_len);
get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
uh_buffer+user_len+1, host_len);
get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
uh_buffer+user_len+1+host_len+1, ip_len);
}
cn->header= 0;
} }
...@@ -1095,6 +1254,27 @@ static int log_connection(const struct connection_info *cn, ...@@ -1095,6 +1254,27 @@ static int log_connection(const struct connection_info *cn,
} }
static int log_connection_event(const struct mysql_event_connection *event,
const char *type)
{
time_t ctime;
size_t csize;
char message[1024];
(void) time(&ctime);
csize= log_header(message, sizeof(message)-1, &ctime,
servhost, servhost_len,
event->user, event->user_length,
event->host, event->host_length,
event->ip, event->ip_length,
event->thread_id, 0, type);
csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize,
",%.*s,,%d", event->database_length, event->database, event->status);
message[csize]= '\n';
return write_log(message, csize + 1);
}
static size_t escape_string(const char *str, unsigned int len, static size_t escape_string(const char *str, unsigned int len,
char *result, size_t result_len) char *result, size_t result_len)
{ {
...@@ -1240,11 +1420,11 @@ static int do_log_user(const char *name) ...@@ -1240,11 +1420,11 @@ static int do_log_user(const char *name)
return 0; return 0;
len= strlen(name); len= strlen(name);
if (incl_user_hash.records) if (incl_user_coll.n_users)
return my_hash_search(&incl_user_hash, (const uchar *) name, len) != 0; return coll_search(&incl_user_coll, name, len) != 0;
if (excl_user_hash.records) if (excl_user_coll.n_users)
return my_hash_search(&excl_user_hash, (const uchar *) name, len) == 0; return coll_search(&excl_user_coll, name, len) == 0;
return 1; return 1;
} }
...@@ -1582,14 +1762,14 @@ static void update_general_user(struct connection_info *cn, ...@@ -1582,14 +1762,14 @@ static void update_general_user(struct connection_info *cn,
} }
static struct connection_info ci_disconnect_buffer;
#define AA_FREE_CONNECTION 1 #define AA_FREE_CONNECTION 1
#define AA_CHANGE_USER 2 #define AA_CHANGE_USER 2
static struct connection_info *update_connection_hash(unsigned int event_class, static void update_connection_info(struct connection_info *cn,
const void *ev, unsigned int event_class, const void *ev, int *after_action)
int *after_action)
{ {
struct connection_info *cn= NULL;
*after_action= 0; *after_action= 0;
switch (event_class) { switch (event_class) {
...@@ -1602,13 +1782,17 @@ static struct connection_info *update_connection_hash(unsigned int event_class, ...@@ -1602,13 +1782,17 @@ static struct connection_info *update_connection_hash(unsigned int event_class,
{ {
int init_db_command= event->general_command_length == 7 && int init_db_command= event->general_command_length == 7 &&
strncmp(event->general_command, "Init DB", 7) == 0; strncmp(event->general_command, "Init DB", 7) == 0;
if ((cn= find_connection(event->general_thread_id))) if (!ci_needs_setup(cn))
{ {
if (init_db_command) if (init_db_command)
{ {
/* Change DB */ /* Change DB */
get_str_n(cn->db, &cn->db_length, sizeof(cn->db), if (mysql_57_started)
event->general_query, event->general_query_length); get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
event->database, event->database_length);
else
get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
event->general_query, event->general_query_length);
} }
cn->query_id= mode ? query_counter++ : event->query_id; cn->query_id= mode ? query_counter++ : event->query_id;
cn->query= event->general_query; cn->query= event->general_query;
...@@ -1617,18 +1801,19 @@ static struct connection_info *update_connection_hash(unsigned int event_class, ...@@ -1617,18 +1801,19 @@ static struct connection_info *update_connection_hash(unsigned int event_class,
update_general_user(cn, event); update_general_user(cn, event);
} }
else if (init_db_command) else if (init_db_command)
cn= add_connection_initdb(event); setup_connection_initdb(cn, event);
else if (event_query_command(event)) else if (event_query_command(event))
cn= add_connection_query(event); setup_connection_query(cn, event);
else
setup_connection_simple(cn);
break; break;
} }
case MYSQL_AUDIT_GENERAL_STATUS: case MYSQL_AUDIT_GENERAL_STATUS:
if (event_query_command(event)) if (event_query_command(event))
{ {
if (!(cn= find_connection(event->general_thread_id)) && if (ci_needs_setup(cn))
!(cn= add_connection_query(event))) setup_connection_query(cn, event);
return 0;
if (mode == 0 && cn->db_length == 0 && event->database_length > 0) if (mode == 0 && cn->db_length == 0 && event->database_length > 0)
get_str_n(cn->db, &cn->db_length, sizeof(cn->db), get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
...@@ -1654,13 +1839,13 @@ static struct connection_info *update_connection_hash(unsigned int event_class, ...@@ -1654,13 +1839,13 @@ static struct connection_info *update_connection_hash(unsigned int event_class,
} }
break; break;
case MYSQL_AUDIT_GENERAL_ERROR: case MYSQL_AUDIT_GENERAL_ERROR:
/* We need this because of a bug in the MariaDB */ /*
/* that it returns NULL query field for the */ We need this because the MariaDB returns NULL query field for the
/* MYSQL_AUDIT_GENERAL_STATUS in the mysqld_stmt_prepare. */ MYSQL_AUDIT_GENERAL_STATUS in the mysqld_stmt_prepare.
/* As a result we get empty QUERY field for errors. */ As a result we get empty QUERY field for errors.
if (!(cn= find_connection(event->general_thread_id)) && */
!(cn= add_connection_query(event))) if (ci_needs_setup(cn))
return 0; setup_connection_query(cn, event);
cn->query_id= mode ? query_counter++ : event->query_id; cn->query_id= mode ? query_counter++ : event->query_id;
get_str_n(cn->query_buffer, &cn->query_length, sizeof(cn->query_buffer), get_str_n(cn->query_buffer, &cn->query_length, sizeof(cn->query_buffer),
event->general_query, event->general_query_length); event->general_query, event->general_query_length);
...@@ -1675,9 +1860,9 @@ static struct connection_info *update_connection_hash(unsigned int event_class, ...@@ -1675,9 +1860,9 @@ static struct connection_info *update_connection_hash(unsigned int event_class,
{ {
const struct mysql_event_table *event = const struct mysql_event_table *event =
(const struct mysql_event_table *) ev; (const struct mysql_event_table *) ev;
if (!(cn= find_connection(event->thread_id)) && if (ci_needs_setup(cn))
!(cn= add_connection_table(event))) setup_connection_table(cn, event);
return 0;
if (cn->user_length == 0 && cn->host_length == 0 && cn->ip_length == 0) if (cn->user_length == 0 && cn->host_length == 0 && cn->ip_length == 0)
{ {
get_str_n(cn->user, &cn->user_length, sizeof(cn->user), get_str_n(cn->user, &cn->user_length, sizeof(cn->user),
...@@ -1703,17 +1888,10 @@ static struct connection_info *update_connection_hash(unsigned int event_class, ...@@ -1703,17 +1888,10 @@ static struct connection_info *update_connection_hash(unsigned int event_class,
switch (event->event_subclass) switch (event->event_subclass)
{ {
case MYSQL_AUDIT_CONNECTION_CONNECT: case MYSQL_AUDIT_CONNECTION_CONNECT:
cn= add_connection(ev); setup_connection_connect(cn, event);
break;
case MYSQL_AUDIT_CONNECTION_DISCONNECT:
cn= find_connection(event->thread_id);
if (cn)
*after_action= AA_FREE_CONNECTION;
break; break;
case MYSQL_AUDIT_CONNECTION_CHANGE_USER: case MYSQL_AUDIT_CONNECTION_CHANGE_USER:
cn= find_connection(event->thread_id); *after_action= AA_CHANGE_USER;
if (cn)
*after_action= AA_CHANGE_USER;
break; break;
default:; default:;
} }
...@@ -1722,17 +1900,17 @@ static struct connection_info *update_connection_hash(unsigned int event_class, ...@@ -1722,17 +1900,17 @@ static struct connection_info *update_connection_hash(unsigned int event_class,
default: default:
break; break;
} }
return cn;
} }
struct connection_info cn_error_buffer;
#define FILTER(MASK) (events == 0 || (events & MASK)) #define FILTER(MASK) (events == 0 || (events & MASK))
static void auditing(MYSQL_THD thd __attribute__((unused)), void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev)
unsigned int event_class,
const void *ev)
{ {
struct connection_info *cn; struct connection_info *cn= 0;
int after_action; int after_action= 0;
/* That one is important as this function can be called with */ /* That one is important as this function can be called with */
/* &lock_operations locked when the server logs an error reported */ /* &lock_operations locked when the server logs an error reported */
...@@ -1742,8 +1920,23 @@ static void auditing(MYSQL_THD thd __attribute__((unused)), ...@@ -1742,8 +1920,23 @@ static void auditing(MYSQL_THD thd __attribute__((unused)),
flogger_mutex_lock(&lock_operations); flogger_mutex_lock(&lock_operations);
if (!(cn= update_connection_hash(event_class, ev, &after_action))) cn= get_loc_info(thd);
goto exit_func;
if (ci_needs_setup(cn) && maria_55_started &&
(event_class == MYSQL_AUDIT_GENERAL_CLASS &&
*((int*)ev) == MYSQL_AUDIT_GENERAL_ERROR))
{
/*
There's a bug in MariaDB 5.5 that prevents using thread local
variables in some cases.
The 'select * from notexisting_table;' query produces such case.
So just use the static buffer in this case.
*/
cn= &cn_error_buffer;
cn->header= 1;
}
update_connection_info(cn, event_class, ev, &after_action);
if (!logging) if (!logging)
goto exit_func; goto exit_func;
...@@ -1757,8 +1950,11 @@ static void auditing(MYSQL_THD thd __attribute__((unused)), ...@@ -1757,8 +1950,11 @@ static void auditing(MYSQL_THD thd __attribute__((unused)),
/* /*
Only one subclass is logged. Only one subclass is logged.
*/ */
if (event->event_subclass == MYSQL_AUDIT_GENERAL_STATUS) if (event->event_subclass == MYSQL_AUDIT_GENERAL_STATUS &&
event_query_command(event))
{
log_statement(cn, event, "QUERY"); log_statement(cn, event, "QUERY");
}
} }
else if (event_class == MYSQL_AUDIT_TABLE_CLASS && FILTER(EVENT_TABLE) && cn) else if (event_class == MYSQL_AUDIT_TABLE_CLASS && FILTER(EVENT_TABLE) && cn)
{ {
...@@ -1799,7 +1995,10 @@ static void auditing(MYSQL_THD thd __attribute__((unused)), ...@@ -1799,7 +1995,10 @@ static void auditing(MYSQL_THD thd __attribute__((unused)),
log_connection(cn, event, event->status ? "FAILED_CONNECT": "CONNECT"); log_connection(cn, event, event->status ? "FAILED_CONNECT": "CONNECT");
break; break;
case MYSQL_AUDIT_CONNECTION_DISCONNECT: case MYSQL_AUDIT_CONNECTION_DISCONNECT:
log_connection(cn, event, "DISCONNECT"); if (use_event_data_for_disconnect)
log_connection_event(event, "DISCONNECT");
else
log_connection(&ci_disconnect_buffer, event, "DISCONNECT");
break; break;
case MYSQL_AUDIT_CONNECTION_CHANGE_USER: case MYSQL_AUDIT_CONNECTION_CHANGE_USER:
log_connection(cn, event, "CHANGEUSER"); log_connection(cn, event, "CHANGEUSER");
...@@ -1814,10 +2013,6 @@ exit_func: ...@@ -1814,10 +2013,6 @@ exit_func:
if (after_action) if (after_action)
{ {
switch (after_action) { switch (after_action) {
case AA_FREE_CONNECTION:
my_hash_delete(&connection_hash, (uchar *) cn);
cn= 0;
break;
case AA_CHANGE_USER: case AA_CHANGE_USER:
{ {
const struct mysql_event_connection *event = const struct mysql_event_connection *event =
...@@ -1835,28 +2030,6 @@ exit_func: ...@@ -1835,28 +2030,6 @@ exit_func:
} }
#ifdef DBUG_OFF
#ifdef __x86_64__
static const int cmd_off= 4200;
static const int db_off= 120;
static const int db_len_off= 128;
#else
static const int cmd_off= 2668;
static const int db_off= 60;
static const int db_len_off= 64;
#endif /*x86_64*/
#else
#ifdef __x86_64__
static const int cmd_off= 4432;
static const int db_off= 120;
static const int db_len_off= 128;
#else
static const int cmd_off= 2808;
static const int db_off= 64;
static const int db_len_off= 68;
#endif /*x86_64*/
#endif /*DBUG_OFF*/
struct mysql_event_general_v8 struct mysql_event_general_v8
{ {
unsigned int event_class; unsigned int event_class;
...@@ -1874,8 +2047,31 @@ struct mysql_event_general_v8 ...@@ -1874,8 +2047,31 @@ struct mysql_event_general_v8
unsigned long long general_rows; unsigned long long general_rows;
}; };
static void auditing_v8(MYSQL_THD thd, struct mysql_event_general_v8 *ev_v8) static void auditing_v8(MYSQL_THD thd, struct mysql_event_general_v8 *ev_v8)
{ {
#ifdef DBUG_OFF
#ifdef __x86_64__
static const int cmd_off= 4200;
static const int db_off= 120;
static const int db_len_off= 128;
#else
static const int cmd_off= 2668;
static const int db_off= 60;
static const int db_len_off= 64;
#endif /*x86_64*/
#else
#ifdef __x86_64__
static const int cmd_off= 4432;
static const int db_off= 120;
static const int db_len_off= 128;
#else
static const int cmd_off= 2808;
static const int db_off= 64;
static const int db_len_off= 68;
#endif /*x86_64*/
#endif /*DBUG_OFF*/
struct mysql_event_general event; struct mysql_event_general event;
if (ev_v8->event_class != MYSQL_AUDIT_GENERAL_CLASS) if (ev_v8->event_class != MYSQL_AUDIT_GENERAL_CLASS)
...@@ -1934,6 +2130,41 @@ static void auditing_v13(MYSQL_THD thd, unsigned int *ev_v0) ...@@ -1934,6 +2130,41 @@ static void auditing_v13(MYSQL_THD thd, unsigned int *ev_v0)
} }
int get_db_mysql57(MYSQL_THD thd, char **name, int *len)
{
int db_off;
int db_len_off;
if (debug_server_started)
{
#ifdef __x86_64__
db_off= 608;
db_len_off= 616;
#else
db_off= 0;
db_len_off= 0;
#endif /*x86_64*/
}
else
{
#ifdef __x86_64__
db_off= 536;
db_len_off= 544;
#else
db_off= 0;
db_len_off= 0;
#endif /*x86_64*/
}
#ifdef __linux__
*name= *(char **) (((char *) thd) + db_off);
*len= *((int *) (((char*) thd) + db_len_off));
if (*name && (*name)[*len] != 0)
return 1;
return 0;
#else
return 1;
#endif
}
/* /*
As it's just too difficult to #include "sql_class.h", As it's just too difficult to #include "sql_class.h",
let's just copy the necessary part of the system_variables let's just copy the necessary part of the system_variables
...@@ -2060,8 +2291,8 @@ static int server_audit_init(void *p __attribute__((unused))) ...@@ -2060,8 +2291,8 @@ static int server_audit_init(void *p __attribute__((unused)))
flogger_mutex_init(key_LOCK_operations, &lock_operations, MY_MUTEX_INIT_FAST); flogger_mutex_init(key_LOCK_operations, &lock_operations, MY_MUTEX_INIT_FAST);
flogger_mutex_init(key_LOCK_operations, &lock_bigbuffer, MY_MUTEX_INIT_FAST); flogger_mutex_init(key_LOCK_operations, &lock_bigbuffer, MY_MUTEX_INIT_FAST);
my_hash_clear(&incl_user_hash); coll_init(&incl_user_coll);
my_hash_clear(&excl_user_hash); coll_init(&excl_user_coll);
if (incl_users) if (incl_users)
{ {
...@@ -2079,9 +2310,6 @@ static int server_audit_init(void *p __attribute__((unused))) ...@@ -2079,9 +2310,6 @@ static int server_audit_init(void *p __attribute__((unused)))
update_excl_users(NULL, NULL, NULL, &excl_users); update_excl_users(NULL, NULL, NULL, &excl_users);
} }
loc_my_hash_init(&connection_hash, 0, &my_charset_bin, 0x100, 0,
sizeof(unsigned long), 0, free_connection, 0);
error_header(); error_header();
fprintf(stderr, "MariaDB Audit Plugin version %s%s STARTED.\n", fprintf(stderr, "MariaDB Audit Plugin version %s%s STARTED.\n",
PLUGIN_STR_VERSION, PLUGIN_DEBUG_VERSION); PLUGIN_STR_VERSION, PLUGIN_DEBUG_VERSION);
...@@ -2105,6 +2333,16 @@ static int server_audit_init(void *p __attribute__((unused))) ...@@ -2105,6 +2333,16 @@ static int server_audit_init(void *p __attribute__((unused)))
} }
} }
ci_disconnect_buffer.header= 10;
ci_disconnect_buffer.thread_id= 0;
ci_disconnect_buffer.query_id= 0;
ci_disconnect_buffer.db_length= 0;
ci_disconnect_buffer.user_length= 0;
ci_disconnect_buffer.host_length= 0;
ci_disconnect_buffer.ip_length= 0;
ci_disconnect_buffer.query= empty_str;
ci_disconnect_buffer.query_length= 0;
if (logging) if (logging)
start_logging(); start_logging();
...@@ -2123,13 +2361,8 @@ static int server_audit_init_mysql(void *p) ...@@ -2123,13 +2361,8 @@ static int server_audit_init_mysql(void *p)
static int server_audit_deinit(void *p __attribute__((unused))) static int server_audit_deinit(void *p __attribute__((unused)))
{ {
if (my_hash_inited(&incl_user_hash)) coll_free(&incl_user_coll);
my_hash_free(&incl_user_hash); coll_free(&excl_user_coll);
if (my_hash_inited(&excl_user_hash))
my_hash_free(&excl_user_hash);
my_hash_free(&connection_hash);
if (output_type == OUTPUT_FILE && logfile) if (output_type == OUTPUT_FILE && logfile)
logger_close(logfile); logger_close(logfile);
...@@ -2164,6 +2397,7 @@ static struct st_mysql_audit mysql_descriptor = ...@@ -2164,6 +2397,7 @@ static struct st_mysql_audit mysql_descriptor =
{ MYSQL_AUDIT_GENERAL_CLASSMASK | MYSQL_AUDIT_CONNECTION_CLASSMASK } { MYSQL_AUDIT_GENERAL_CLASSMASK | MYSQL_AUDIT_CONNECTION_CLASSMASK }
}; };
mysql_declare_plugin(server_audit) mysql_declare_plugin(server_audit)
{ {
MYSQL_AUDIT_PLUGIN, MYSQL_AUDIT_PLUGIN,
...@@ -2206,7 +2440,7 @@ maria_declare_plugin(server_audit) ...@@ -2206,7 +2440,7 @@ maria_declare_plugin(server_audit)
audit_status, audit_status,
vars, vars,
PLUGIN_STR_VERSION, PLUGIN_STR_VERSION,
MariaDB_PLUGIN_MATURITY_GAMMA MariaDB_PLUGIN_MATURITY_STABLE
} }
maria_declare_plugin_end; maria_declare_plugin_end;
...@@ -2214,22 +2448,21 @@ maria_declare_plugin_end; ...@@ -2214,22 +2448,21 @@ maria_declare_plugin_end;
static void mark_always_logged(MYSQL_THD thd) static void mark_always_logged(MYSQL_THD thd)
{ {
struct connection_info *cn; struct connection_info *cn;
if (thd && (cn= find_connection(thd_get_thread_id(thd)))) if (thd && (cn= get_loc_info(thd)))
cn->log_always= 1; cn->log_always= 1;
} }
static void log_current_query(MYSQL_THD thd) static void log_current_query(MYSQL_THD thd)
{ {
unsigned long thd_id;
struct connection_info *cn; struct connection_info *cn;
if (!thd || if (!thd)
!(cn= find_connection((thd_id= thd_get_thread_id(thd)))))
return; return;
if (FILTER(EVENT_QUERY) && do_log_user(cn->user)) cn= get_loc_info(thd);
if (!ci_needs_setup(cn) && FILTER(EVENT_QUERY) && do_log_user(cn->user))
{ {
log_statement_ex(cn, cn->query_time, thd_id, cn->query, cn->query_length, log_statement_ex(cn, cn->query_time, thd_get_thread_id(thd),
0, "QUERY"); cn->query, cn->query_length, 0, "QUERY");
cn->log_always= 1; cn->log_always= 1;
} }
} }
...@@ -2325,7 +2558,7 @@ static void update_incl_users(MYSQL_THD thd, ...@@ -2325,7 +2558,7 @@ static void update_incl_users(MYSQL_THD thd,
mark_always_logged(thd); mark_always_logged(thd);
strncpy(incl_user_buffer, new_users, sizeof(incl_user_buffer)); strncpy(incl_user_buffer, new_users, sizeof(incl_user_buffer));
incl_users= incl_user_buffer; incl_users= incl_user_buffer;
user_hash_fill(&incl_user_hash, incl_users, &excl_user_hash, 1); user_coll_fill(&incl_user_coll, incl_users, &excl_user_coll, 1);
error_header(); error_header();
fprintf(stderr, "server_audit_incl_users set to '%s'.\n", incl_users); fprintf(stderr, "server_audit_incl_users set to '%s'.\n", incl_users);
flogger_mutex_unlock(&lock_operations); flogger_mutex_unlock(&lock_operations);
...@@ -2341,7 +2574,7 @@ static void update_excl_users(MYSQL_THD thd __attribute__((unused)), ...@@ -2341,7 +2574,7 @@ static void update_excl_users(MYSQL_THD thd __attribute__((unused)),
mark_always_logged(thd); mark_always_logged(thd);
strncpy(excl_user_buffer, new_users, sizeof(excl_user_buffer)); strncpy(excl_user_buffer, new_users, sizeof(excl_user_buffer));
excl_users= excl_user_buffer; excl_users= excl_user_buffer;
user_hash_fill(&excl_user_hash, excl_users, &incl_user_hash, 0); user_coll_fill(&excl_user_coll, excl_users, &incl_user_coll, 0);
error_header(); error_header();
fprintf(stderr, "server_audit_excl_users set to '%s'.\n", excl_users); fprintf(stderr, "server_audit_excl_users set to '%s'.\n", excl_users);
flogger_mutex_unlock(&lock_operations); flogger_mutex_unlock(&lock_operations);
...@@ -2480,6 +2713,13 @@ static void update_syslog_ident(MYSQL_THD thd __attribute__((unused)), ...@@ -2480,6 +2713,13 @@ static void update_syslog_ident(MYSQL_THD thd __attribute__((unused)),
} }
struct st_my_thread_var *loc_thread_var(void)
{
return 0;
}
#ifdef _WIN32 #ifdef _WIN32
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{ {
...@@ -2497,9 +2737,18 @@ void __attribute__ ((constructor)) audit_plugin_so_init(void) ...@@ -2497,9 +2737,18 @@ void __attribute__ ((constructor)) audit_plugin_so_init(void)
goto exit; goto exit;
started_mariadb= strstr(serv_ver, "MariaDB") != 0; started_mariadb= strstr(serv_ver, "MariaDB") != 0;
debug_server_started= strstr(serv_ver, "debug") != 0;
if (!started_mariadb) if (started_mariadb)
{
if (serv_ver[0] == '1')
use_event_data_for_disconnect= 1;
else
maria_55_started= 1;
}
else
{ {
/* Started MySQL. */
if (serv_ver[0] == '5' && serv_ver[2] == '5') if (serv_ver[0] == '5' && serv_ver[2] == '5')
{ {
int sc= serv_ver[4] - '0'; int sc= serv_ver[4] - '0';
...@@ -2516,7 +2765,25 @@ void __attribute__ ((constructor)) audit_plugin_so_init(void) ...@@ -2516,7 +2765,25 @@ void __attribute__ ((constructor)) audit_plugin_so_init(void)
mysql_descriptor.event_notify= (void *) auditing_v13; mysql_descriptor.event_notify= (void *) auditing_v13;
} }
} }
else if (serv_ver[0] == '5' && serv_ver[2] == '6')
{
int sc= serv_ver[4] - '0';
if (serv_ver[5] >= '0' && serv_ver[5] <= '9')
sc= sc * 10 + serv_ver[5] - '0';
if (sc >= 24)
use_event_data_for_disconnect= 1;
}
else if (serv_ver[0] == '5' && serv_ver[2] == '7')
{
mysql_57_started= 1;
_mysql_plugin_declarations_[0].info= mysql_v4_descriptor;
use_event_data_for_disconnect= 1;
}
} }
memset(locinfo_ini_value, 'O', sizeof(locinfo_ini_value)-1);
locinfo_ini_value[sizeof(locinfo_ini_value)]= 0;
exit: exit:
#ifdef _WIN32 #ifdef _WIN32
return 1; return 1;
......
#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;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment