You've already forked mysql-audit
mirror of
https://github.com/trellix-enterprise/mysql-audit.git
synced 2025-12-17 18:24:02 +08:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e38bc05f0f | ||
|
|
6dae35653a | ||
|
|
23259986a0 | ||
|
|
59f5b82cc9 | ||
|
|
eddd9e65e2 | ||
|
|
23dd5f824c | ||
|
|
3595c3b6f4 | ||
|
|
68a25232ec | ||
|
|
ed048a30bb | ||
|
|
60f1b8e6d7 | ||
|
|
eb3e38116c | ||
|
|
88159229da | ||
|
|
2109a1030d | ||
|
|
6db2a9f158 | ||
|
|
144a8bf69b | ||
|
|
d9955f7840 | ||
|
|
026fdbf505 |
54
README.md
Normal file
54
README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
MySQL AUDIT Plugin
|
||||
===================
|
||||
|
||||
MySQL AUDIT Plugin is a MySQL plugin from McAfee providing audit capabilities for MySQL,
|
||||
designed with an emphasis on security and audit requirements. The plugin may be used
|
||||
as a standalone audit solution or configured to feed data to external monitoring tools.
|
||||
|
||||
|
||||
Installation and Configuration
|
||||
------------------------------
|
||||
|
||||
Please check out our wiki on github for detailed installation and configuration instructions:
|
||||
|
||||
https://github.com/mcafee/mysql-audit/wiki
|
||||
|
||||
|
||||
Issues
|
||||
------------------------------
|
||||
|
||||
Found a bug? Got a feature request or question?
|
||||
|
||||
Please feel free to report to: https://github.com/mcafee/mysql-audit/issues
|
||||
|
||||
If reporting a bug, please describe the problem verbosely. Try to see if it reproduces and
|
||||
include a detailed description on how to reproduce.
|
||||
|
||||
Make sure to include your MySQL Server version and Audit Plugin version.
|
||||
To print MySQL Server version: log into MySQL and execute the command:
|
||||
|
||||
status
|
||||
|
||||
Please include with the bug the MySQL error log.
|
||||
Log file location can be queried by running the following command:
|
||||
|
||||
show global variables like 'log_error'
|
||||
|
||||
|
||||
Source Code
|
||||
-------------------------------
|
||||
Source code of AUDIT plugin is available at: https://github.com/mcafee/mysql-audit
|
||||
|
||||
|
||||
License
|
||||
-------------------------------
|
||||
Copyright (C) 2012 McAfee, Inc.
|
||||
|
||||
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.
|
||||
|
||||
See COPYING file for a copy of the GPL Version 2 license.
|
||||
104
README.txt
104
README.txt
@@ -1,104 +0,0 @@
|
||||
Audit Plugin
|
||||
|
||||
This is a release of Audit Plugin for MySQL 5.1 and 5.5.
|
||||
|
||||
Audit Plugin is brought to you by McAfee, Inc (www.mcafee.com).
|
||||
|
||||
|
||||
==== INSTALLATION =====
|
||||
|
||||
Make sure to download the proper binary distribution. There are separate binaries for MySQL 5.1 and 5.5 according
|
||||
to platform (32 or 64 bit).
|
||||
|
||||
Audit Plugin is available in the binary distribution under the lib dir. File name: libaudit_plugin.so.
|
||||
To install Audit Plugin, copy libaudit_plugin.so to the plugin_dir (for example /usr/lib/mysql/plugin or /usr/lib64/mysql/plugin) of MySQL.
|
||||
|
||||
To see the configured plugin dir login to MySQL and issue the following command:
|
||||
|
||||
show global variables like 'plugin_dir';
|
||||
|
||||
There are 2 options for installing the plugin via plugin-load configuration option or by issuing the
|
||||
INSTALL PLUGIN statement.
|
||||
|
||||
* Installing via: plugin-load
|
||||
|
||||
Add to the MySQL option file (my.cnf) at the [mysqld] section the option:
|
||||
plugin-load=AUDIT=libaudit_plugin.so
|
||||
|
||||
Restart the mysqld server for the changes to take effect.
|
||||
|
||||
* Installing via: INSTALL PLUGIN
|
||||
|
||||
You will need to issue the following sql command to install the plugin:
|
||||
|
||||
INSTALL PLUGIN AUDIT SONAME 'libaudit_plugin.so';
|
||||
|
||||
A restart to the mysqld server is not necessary.
|
||||
|
||||
Note: On production systems, McAfee recommends using the plugin-load option for installing
|
||||
the audit plugin.
|
||||
|
||||
More info on installing MySQL plugins is available at:
|
||||
http://dev.mysql.com/doc/refman/5.1/en/plugin-installing-uninstalling.html
|
||||
|
||||
===== VERIFICATION =====
|
||||
|
||||
To check if the plugin is installed successfully you can issue the following command, which will show all installed plugins:
|
||||
|
||||
show plugins;
|
||||
|
||||
The Audit plugin will show up with the name AUDIT.
|
||||
|
||||
Additionally you can verify the version of the Audit Plugin by running the following command:
|
||||
|
||||
show global status like 'AUDIT_version';
|
||||
|
||||
|
||||
===== CONFIGURATION =====
|
||||
|
||||
By default, after installation the Audit Plugin doesn't log activity. You must explicitly enable
|
||||
the type of logging desired. Configuration is done through the use of MySQL system variables.
|
||||
Audit Plugin system variables can be set at server startup using options on the command line or in an option file.
|
||||
Additionally, the Audit Plugin system variables can be changed dynamically while the server is running
|
||||
by means of the SET statement.
|
||||
|
||||
Available Audit Plugin command line options:
|
||||
|
||||
--audit-json-file AUDIT plugin json log file Enable|Disable
|
||||
--audit-json-file-sync=#
|
||||
AUDIT plugin json log file sync period. If the value of
|
||||
this variable is greater than 0, audit log will sync to
|
||||
disk after every audit_json_file_sync writes.
|
||||
--audit-json-log-file=name
|
||||
AUDIT plugin json log file name
|
||||
--audit-json-socket AUDIT plugin json log unix socket Enable|Disable
|
||||
--audit-json-socket-name=name
|
||||
AUDIT plugin json log unix socket name
|
||||
--audit-uninstall-plugin
|
||||
AUDIT uninstall plugin Enable|Disable.
|
||||
If disabled attempts to uninstall the AUDIT plugin via the sql UNINSTALL command will fail.
|
||||
Provides added security from uninstalling the plugin. Also protection from
|
||||
CVE-2010-1621 (http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-1621)
|
||||
affecting versions upto 5.1.46.
|
||||
|
||||
|
||||
===== REPORTING BUGS =====
|
||||
|
||||
Please describe the problem verbosely. Try to see if it reproduces and
|
||||
include a detailed description on how to reproduce.
|
||||
|
||||
Make sure to include your MySQL Server version and Audit Plugin version.
|
||||
To print MySQL Server version log into MySQL and execute the command: status.
|
||||
|
||||
Please include with the bug the log files:
|
||||
|
||||
* mysql-audit.log
|
||||
* MySQL error log: log file location can be queried by running the following
|
||||
command: show global variables like 'log_error'
|
||||
|
||||
|
||||
===== LICENSE =====
|
||||
|
||||
The software included in this product contains copyrighted software that is licensed under the GPL Version 2.
|
||||
See COPYING file for a copy of the GPL Version 2 license.
|
||||
Source code is available at: https://github.com/mcafee/mysql-audit
|
||||
129
compiling.txt
Normal file → Executable file
129
compiling.txt
Normal file → Executable file
@@ -1,63 +1,66 @@
|
||||
Compiling instructions:
|
||||
|
||||
make sure you have installed the following packages:
|
||||
|
||||
autoconf
|
||||
automake
|
||||
gcc-c++
|
||||
|
||||
To compile you will need to obtain the MySQL source code.
|
||||
|
||||
==== MySQL 5.1 ======
|
||||
|
||||
Extract the MySQL source code in the root directory. For example:
|
||||
|
||||
unzip zip-sources/mysql-5.1.40.zip
|
||||
|
||||
|
||||
Then run the following command:
|
||||
|
||||
cd mysql-5.1.40
|
||||
CXX=gcc ./configure
|
||||
cd include
|
||||
make
|
||||
|
||||
Then goto top dir and run:
|
||||
|
||||
chmod +x bootstrap.sh
|
||||
./bootstrap.sh
|
||||
|
||||
This will create configure script. Then run:
|
||||
|
||||
CXX='gcc -static-libgcc' CC='gcc -static-libgcc' ./configure --with-mysql=mysql-5.1.40
|
||||
|
||||
|
||||
==== MySQL 5.5 ======
|
||||
|
||||
Extract MySQL 5.5 source code
|
||||
|
||||
go to mysql-src dir and run:
|
||||
|
||||
cd mysql-5.5.8
|
||||
cmake .
|
||||
make
|
||||
|
||||
back to working dir and run:
|
||||
|
||||
CXX='gcc -static-libgcc' CC='gcc -static-libgcc' ./configure --with-mysql=mysql-5.5.8 --with-mysql-libservices=mysql-5.5.8/libservices/libmysqlservices.a
|
||||
make
|
||||
|
||||
==== Compiling with make =====
|
||||
|
||||
Go to top source dir and run:
|
||||
|
||||
make
|
||||
|
||||
Plugin will be compiled at:
|
||||
|
||||
src/.libs/libaudit_plugin.so
|
||||
|
||||
Some documentation about configure command for mysql:
|
||||
|
||||
http://dev.mysql.com/doc/refman/5.1/en/source-configuration-options.html
|
||||
|
||||
Compiling instructions
|
||||
=======================
|
||||
|
||||
Make sure you have installed the following packages:
|
||||
|
||||
autoconf
|
||||
automake
|
||||
gcc-c++
|
||||
|
||||
To compile you will need to obtain the MySQL source code. MySQL source code is available at:
|
||||
|
||||
http://dev.mysql.com/downloads/mysql/
|
||||
|
||||
==== MySQL 5.1 ======
|
||||
|
||||
Extract the MySQL source code in the root directory. For example:
|
||||
|
||||
unzip zip-sources/mysql-5.1.40.zip
|
||||
|
||||
|
||||
Then run the following command:
|
||||
|
||||
cd mysql-5.1.40
|
||||
CXX=gcc ./configure
|
||||
cd include
|
||||
make
|
||||
|
||||
Then goto top dir and run:
|
||||
|
||||
chmod +x bootstrap.sh
|
||||
./bootstrap.sh
|
||||
|
||||
This will create configure script. Then run:
|
||||
|
||||
CXX='gcc -static-libgcc' CC='gcc -static-libgcc' ./configure --with-mysql=mysql-5.1.40
|
||||
|
||||
|
||||
==== MySQL 5.5 ======
|
||||
|
||||
Extract MySQL 5.5 source code
|
||||
|
||||
go to mysql-src dir and run:
|
||||
|
||||
cd mysql-5.5.8
|
||||
cmake .
|
||||
make
|
||||
|
||||
back to working dir and run:
|
||||
|
||||
CXX='gcc -static-libgcc' CC='gcc -static-libgcc' ./configure --with-mysql=mysql-5.5.8 --with-mysql-libservices=mysql-5.5.8/libservices/libmysqlservices.a
|
||||
make
|
||||
|
||||
==== Compiling with make =====
|
||||
|
||||
Go to top source dir and run:
|
||||
|
||||
make
|
||||
|
||||
Plugin will be compiled at:
|
||||
|
||||
src/.libs/libaudit_plugin.so
|
||||
|
||||
Some documentation about configure command for mysql:
|
||||
|
||||
http://dev.mysql.com/doc/refman/5.1/en/source-configuration-options.html
|
||||
|
||||
|
||||
@@ -95,6 +95,9 @@ CXXFLAGS="-fno-implicit-templates -fno-exceptions -fno-rtti "
|
||||
#add pthread libs
|
||||
LIBS="$LIBS -lpthread"
|
||||
|
||||
|
||||
|
||||
|
||||
#make sure we have const
|
||||
AC_C_CONST
|
||||
AC_TYPE_SIZE_T
|
||||
@@ -113,11 +116,13 @@ echo "Version: $MYSQL_AUDIT_PLUGIN_VERSION-$MYSQL_AUDIT_PLUGIN_REVISION"
|
||||
CPPFLAGS="$CPPFLAGS -DMYSQL_AUDIT_PLUGIN_VERSION='\"$MYSQL_AUDIT_PLUGIN_VERSION\"'"
|
||||
CPPFLAGS="$CPPFLAGS -DMYSQL_AUDIT_PLUGIN_REVISION='\"$MYSQL_AUDIT_PLUGIN_REVISION\"'"
|
||||
|
||||
|
||||
#subst the relevant variables
|
||||
AC_SUBST(CPPFLAGS)
|
||||
AC_SUBST(CXXLAGS)
|
||||
AC_SUBST(CLAGS)
|
||||
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
src/Makefile
|
||||
yajl/Makefile
|
||||
|
||||
15
include/audit_handler.h
Normal file → Executable file
15
include/audit_handler.h
Normal file → Executable file
@@ -33,6 +33,10 @@ typedef struct _THDPRINTED {
|
||||
const char * retrieve_command (THD * thd);
|
||||
typedef size_t OFFSET;
|
||||
|
||||
#define MAX_COM_STATUS_VARS_RECORDS 512
|
||||
|
||||
#define MAX_OBJECT_CHAR_NUMBERS 130
|
||||
#define MAX_NUM_OBJECT_ELEM 256
|
||||
|
||||
/**
|
||||
* The struct usd to hold offsets. We should have one per version.
|
||||
@@ -158,7 +162,7 @@ public:
|
||||
return thd->query;
|
||||
#endif
|
||||
}
|
||||
//virtual char * retrieve_command (THD * thd);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -209,8 +213,8 @@ public:
|
||||
|
||||
|
||||
static const size_t MAX_AUDIT_HANDLERS_NUM = 4;
|
||||
static const size_t BSON_FILE_HANDLER = 1;
|
||||
static const size_t BSON_SOCKET_HANDLER = 3;
|
||||
static const size_t JSON_FILE_HANDLER = 1;
|
||||
static const size_t JSON_SOCKET_HANDLER = 3;
|
||||
|
||||
static Audit_handler * m_audit_handler_list[];
|
||||
|
||||
@@ -273,6 +277,11 @@ public:
|
||||
}
|
||||
|
||||
void set_enable(bool val);
|
||||
|
||||
/**
|
||||
* will close and start the handler
|
||||
*/
|
||||
void flush();
|
||||
|
||||
/**
|
||||
* Will get relevant shared lock and call internal method of handler
|
||||
|
||||
47
offset-extract/offset-extract.sh
Normal file
47
offset-extract/offset-extract.sh
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $# = 0 ]; then
|
||||
echo "Usage: $0 <mysqld executable> [optional mysqld symbols]"
|
||||
echo "Will extract offsets from mysqld. Requires gdb, md5sum and mysqld symbols."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#extract the version of mysqld
|
||||
|
||||
FULL_MYVER=`$1 --version | grep -P -o 'Ver\s+[\w\.-]+'| awk '{print $2}'`
|
||||
|
||||
#extract the md5 digest
|
||||
|
||||
MYMD5=`md5sum -b $1 | awk -v Field=1 '{print $1}'`
|
||||
|
||||
MYVER="$FULL_MYVER"
|
||||
echo $FULL_MYVER | grep 'log' > /dev/null
|
||||
|
||||
|
||||
if [ $? = 0 ]; then
|
||||
MYVER=`echo "$MYVER" | grep -P -o '.+(?=-log)'`
|
||||
fi
|
||||
|
||||
echo "set logging on" > offsets.gdb
|
||||
echo 'printf "{\"'$MYVER'\",\"'$MYMD5'\", %d, %d, %d, %d, %d, %d}", ((size_t)&((THD *)log_slow_statement)->query_id) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->thread_id) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->main_security_ctx) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->command) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->lex) - (size_t)log_slow_statement, (size_t)&((LEX*)log_slow_statement)->comment - (size_t) log_slow_statement' >> offsets.gdb
|
||||
|
||||
SYMPARAM=""
|
||||
if [ -n "$2" ]; then
|
||||
SYMPARAM="-s $2 -e"
|
||||
fi
|
||||
|
||||
gdb -n -q -batch -x offsets.gdb $SYMPARAM $1 > /dev/null 2>&1
|
||||
|
||||
if [ $? != 0 ]; then
|
||||
echo "GDB failed!!!" > /dev/stderr
|
||||
exit 2
|
||||
fi
|
||||
|
||||
OFFSETS=`cat gdb.txt`
|
||||
echo "//offsets for: $1 ($FULL_MYVER)"
|
||||
echo "$OFFSETS,"
|
||||
|
||||
#clean up
|
||||
rm gdb.txt
|
||||
rm offsets.gdb
|
||||
|
||||
@@ -18,11 +18,11 @@ INCLUDES = $(MYSQL_INC) $(YAJL_INC) $(UDIS_INC)
|
||||
pkgplugindir = $(MYSQL_PLUGIN_DIR)
|
||||
|
||||
pkgplugin_LTLIBRARIES = libaudit_plugin.la
|
||||
libaudit_plugin_la_LDFLAGS = -module
|
||||
libaudit_plugin_la_LDFLAGS = -module -Wl,--version-script=MySQLPlugin.map
|
||||
|
||||
libaudit_plugin_la_SOURCES = hot_patch.cc audit_plugin.cc audit_handler.cc
|
||||
|
||||
libaudit_plugin_la_LIBADD = $(top_srcdir)/yajl/src/libyajl.la $(top_srcdir)/udis86/libudis86/libudis86.la $(MYSQL_LIBSERVICES)
|
||||
libaudit_plugin_la_LIBADD = $(top_srcdir)/yajl/src/libyajl.la $(top_srcdir)/udis86/libudis86/libudis86.la $(MYSQL_LIBSERVICES)
|
||||
|
||||
|
||||
|
||||
|
||||
10
src/MySQLPlugin.map
Normal file
10
src/MySQLPlugin.map
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
global:
|
||||
_mysql_plugin_declarations_;
|
||||
_mysql_plugin_interface_version_;
|
||||
_mysql_sizeof_struct_st_plugin_;
|
||||
audit_plugin_so_init;
|
||||
thd_alloc_service;
|
||||
|
||||
local: *;
|
||||
};
|
||||
130
src/audit_handler.cc
Normal file → Executable file
130
src/audit_handler.cc
Normal file → Executable file
@@ -78,52 +78,6 @@ const char * Audit_formatter::retrive_object_type (TABLE_LIST *pObj)
|
||||
return "TABLE";
|
||||
}
|
||||
|
||||
const char * retrieve_command (THD * thd)
|
||||
{
|
||||
const char *cmd;
|
||||
SHOW_VAR *com_status_vars;
|
||||
int sv_idx =0;
|
||||
int command = Audit_formatter::thd_inst_command(thd);
|
||||
if (command < 0 || command > COM_END)
|
||||
{
|
||||
command = COM_END;
|
||||
}
|
||||
const int sql_command = thd_sql_command(thd);
|
||||
while (strcmp (status_vars[sv_idx].name,"Com") !=0 && status_vars[sv_idx].name != NullS)
|
||||
{
|
||||
sv_idx ++;
|
||||
}
|
||||
if (strcmp (status_vars[sv_idx].name,"Com")==0)
|
||||
{
|
||||
int status_vars_index =0;
|
||||
com_status_vars = (SHOW_VAR*)status_vars[sv_idx].value;
|
||||
size_t initial_offset = (size_t) com_status_vars[0].value;
|
||||
while (com_status_vars[status_vars_index].value != (char*) (sizeof (ulong) * (sql_command + 1) + initial_offset)
|
||||
&& com_status_vars[status_vars_index].name != NullS)
|
||||
{
|
||||
status_vars_index ++;
|
||||
}
|
||||
if (com_status_vars[status_vars_index].value != NullS)
|
||||
{
|
||||
cmd = com_status_vars[status_vars_index].name;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = command_name[command].str;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = "UNKNOWN";
|
||||
}
|
||||
Security_context * sctx = Audit_formatter::thd_inst_main_security_ctx(thd);
|
||||
if (strcmp (cmd, "Connect") ==0 && (sctx->priv_user == NULL || *sctx->priv_user ==0x0))
|
||||
{
|
||||
cmd = "Failed Login";
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
void Audit_handler::stop_all()
|
||||
{
|
||||
@@ -169,6 +123,22 @@ void Audit_handler::set_enable(bool val)
|
||||
unlock();
|
||||
}
|
||||
|
||||
void Audit_handler::flush()
|
||||
{
|
||||
lock_exclusive();
|
||||
if (!m_enabled) //if not running we don't flush
|
||||
{
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
//call the cleanup of the handler
|
||||
handler_stop();
|
||||
//call the startup of the handler
|
||||
handler_start();
|
||||
sql_print_information("%s Log flush complete.", AUDIT_LOG_PREFIX);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void Audit_handler::log_audit(ThdSesData *pThdData)
|
||||
{
|
||||
lock_shared();
|
||||
@@ -363,6 +333,15 @@ static inline void yajl_add_uint64(yajl_gen gen, const char * name, uint64 num)
|
||||
snprintf(buf, max_int64_str_len, "%llu", num);
|
||||
yajl_add_string_val(gen, name, buf);
|
||||
}
|
||||
static inline void yajl_add_obj( yajl_gen gen, const char *db,const char* ptype,const char * name =NULL)
|
||||
{
|
||||
yajl_add_string_val(gen, "db", db);
|
||||
if (name)
|
||||
{
|
||||
yajl_add_string_val(gen, "name", name);
|
||||
}
|
||||
yajl_add_string_val(gen, "obj_type",ptype);
|
||||
}
|
||||
|
||||
//void Audit_file_handler::print_sleep (THD *thd, int delay_ms)
|
||||
//{
|
||||
@@ -388,7 +367,7 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
||||
unsigned long thdid = thd_get_thread_id(pThdData->getTHD());
|
||||
query_id_t qid = thd_inst_query_id(pThdData->getTHD());
|
||||
int command = thd_inst_command(pThdData->getTHD());
|
||||
const char *cmd = pThdData->getCmdName();
|
||||
|
||||
|
||||
Security_context * sctx = thd_inst_main_security_ctx(pThdData->getTHD());
|
||||
|
||||
@@ -407,7 +386,31 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
||||
yajl_add_string_val(gen, "priv_user", sctx->priv_user);
|
||||
yajl_add_string_val(gen, "host", sctx->host);
|
||||
yajl_add_string_val(gen, "ip", sctx->ip);
|
||||
yajl_add_string_val(gen, "cmd", cmd);
|
||||
const char *cmd = pThdData->getCmdName();
|
||||
//only print tables if lex is not null and it is not a quit command
|
||||
LEX * pLex = Audit_formatter::thd_lex(pThdData->getTHD());
|
||||
QueryTableInf *pQuery_cache_table_list = getQueryCacheTableList1 (pThdData->getTHD());
|
||||
if (pLex && command != COM_QUIT && pLex->query_tables == NULL && pQuery_cache_table_list)
|
||||
{
|
||||
yajl_add_string_val(gen, "cmd", "select");
|
||||
yajl_add_string(gen, "objects");
|
||||
yajl_gen_array_open(gen);
|
||||
for (int i=0;i<pQuery_cache_table_list->num_of_elem && i < MAX_NUM_QUERY_TABLE_ELEM && pQuery_cache_table_list->num_of_elem >=0;i++)
|
||||
{
|
||||
yajl_gen_map_open(gen);
|
||||
yajl_add_obj (gen, pQuery_cache_table_list->db[i],pQuery_cache_table_list->object_type[i],pQuery_cache_table_list->table_name[i] );
|
||||
yajl_gen_map_close(gen);
|
||||
|
||||
}
|
||||
yajl_gen_array_close(gen);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
yajl_add_string_val(gen, "cmd", cmd);
|
||||
}
|
||||
|
||||
|
||||
if (strcmp (cmd,"Init DB") ==0 || strcmp (cmd, "SHOW TABLES")== 0 || strcmp (cmd, "SHOW TABLE")==0)
|
||||
{
|
||||
@@ -415,14 +418,12 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
||||
{
|
||||
yajl_add_string(gen, "objects");
|
||||
yajl_gen_array_open(gen);
|
||||
yajl_add_string_val(gen, "db",(pThdData->getTHD())->db);
|
||||
yajl_add_string_val(gen, "obj_type","database");
|
||||
yajl_add_obj (gen,(pThdData->getTHD())->db,"database", NULL);
|
||||
yajl_gen_array_close(gen);
|
||||
}
|
||||
}
|
||||
|
||||
//only print tables if lex is not null and it is not a quit command
|
||||
LEX * pLex = Audit_formatter::thd_lex(pThdData->getTHD());
|
||||
|
||||
if (pLex && command != COM_QUIT && pLex->query_tables)
|
||||
{
|
||||
yajl_add_string(gen, "objects");
|
||||
@@ -433,16 +434,14 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
||||
while (table)
|
||||
{
|
||||
yajl_gen_map_open(gen);
|
||||
yajl_add_string_val(gen, "db", table->get_db_name());
|
||||
yajl_add_string_val(gen, "name", table->get_table_name());
|
||||
if (isFirstElementInView && strstr (cmd,"_view")!=NULL )
|
||||
{
|
||||
yajl_add_string_val(gen, "obj_type","view");
|
||||
yajl_add_obj (gen,table->get_db_name(), "view",table->get_table_name());
|
||||
isFirstElementInView = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
yajl_add_string_val(gen, "obj_type",retrive_object_type(table));
|
||||
yajl_add_obj (gen,table->get_db_name(), retrive_object_type(table),table->get_table_name());
|
||||
}
|
||||
yajl_gen_map_close(gen);
|
||||
table = table->next_global;
|
||||
@@ -450,25 +449,6 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
||||
yajl_gen_array_close(gen);
|
||||
}
|
||||
|
||||
QueryTableInf *pQuery_cache_table_list = getQueryCacheTableList1 (pThdData->getTHD());
|
||||
|
||||
if (pLex && command != COM_QUIT && pLex->query_tables == NULL && pQuery_cache_table_list)
|
||||
{
|
||||
yajl_add_string(gen, "objects");
|
||||
yajl_gen_array_open(gen);
|
||||
|
||||
for (int i=0;i<pQuery_cache_table_list->num_of_elem && i < MAX_NUM_QUERY_TABLE_ELEM && pQuery_cache_table_list->num_of_elem >=0;i++)
|
||||
{
|
||||
yajl_gen_map_open(gen);
|
||||
yajl_add_string_val(gen, "db", pQuery_cache_table_list->db[i]);
|
||||
yajl_add_string_val(gen, "name", pQuery_cache_table_list->table_name[i]);
|
||||
yajl_add_string_val(gen,"type",pQuery_cache_table_list->object_type[i]);
|
||||
yajl_gen_map_close(gen);
|
||||
|
||||
}
|
||||
|
||||
yajl_gen_array_close(gen);
|
||||
}
|
||||
|
||||
size_t qlen = 0;
|
||||
|
||||
|
||||
651
src/audit_plugin.cc
Normal file → Executable file
651
src/audit_plugin.cc
Normal file → Executable file
@@ -103,7 +103,11 @@ static const ThdOffsets thd_offsets_arr[] =
|
||||
//offsets for: /mysqlrpm/5.1.60/usr/sbin/mysqld (5.1.60-community)
|
||||
{"5.1.60-community","d9497964e8983a348538c0d05eaee7f0", 6328, 6392, 3688, 3960, 88, 2048},
|
||||
//offsets for: /mysqlrpm/5.1.61/usr/sbin/mysqld (5.1.61-community)
|
||||
{"5.1.61-community","bda6030d35e7fafa5b1e57154a53b804", 6328, 6392, 3688, 3960, 88, 2048},
|
||||
{"5.1.61-community","bda6030d35e7fafa5b1e57154a53b804", 6328, 6392, 3688, 3960, 88, 2048},
|
||||
//offsets for: /mysqlrpm/5.1.62/usr/sbin/mysqld (5.1.62-community)
|
||||
{"5.1.62-community","a4e8de89e0d9a353d09687d3b4560cb3", 6328, 6392, 3688, 3960, 88, 2048},
|
||||
//offsets for: /mysqlrpm/5.1.63/usr/sbin/mysqld (5.1.63-community)
|
||||
{"5.1.63-community","0f4d7e3b17eb36f17aafe4360993a769", 6328, 6392, 3688, 3960, 88, 2048},
|
||||
//offsets for: mysqlrpm/5.5.8/usr/sbin/mysqld (5.5.8)
|
||||
{"5.5.8","70a882693d54df8ab7c7d9f256e317bb", 6032, 6080, 3776, 4200, 88, 2560},
|
||||
//offsets for: mysqlrpm/5.5.9/usr/sbin/mysqld (5.5.9)
|
||||
@@ -132,7 +136,18 @@ static const ThdOffsets thd_offsets_arr[] =
|
||||
{"5.5.19","0765dadb23315bb076bc6e21cfb2de40", 6048, 6096, 3800, 4224, 88, 2560},
|
||||
//offsets for: /mysqlrpm/5.5.20/usr/sbin/mysqld (5.5.20)
|
||||
{"5.5.20","9f6122576930c5d09ca9244094c83f24", 6048, 6096, 3800, 4224, 88, 2560},
|
||||
|
||||
//offsets for: mysqlrpm/5.5.21/usr/sbin/mysqld (5.5.21)
|
||||
{"5.5.21","4a03ad064ed393dabdde175f3ea05ff2", 6048, 6096, 3800, 4224, 88, 2560},
|
||||
//offsets for: mysqlrpm/5.5.22/usr/sbin/mysqld (5.5.22)
|
||||
{"5.5.22","f3592147108e65d92cb18fb4d900c4ab", 6048, 6096, 3800, 4224, 88, 2560},
|
||||
//offsets for: mysqlrpm/5.5.23/usr/sbin/mysqld (5.5.23)
|
||||
{"5.5.23","aac33433f75b9758e7f42fad6991fa9e", 6048, 6096, 3800, 4224, 88, 2568},
|
||||
//offsets for: mysqlrpm/5.5.24/usr/sbin/mysqld (5.5.24)
|
||||
{"5.5.24","2915a9dd079446149b17d0d1c478fb11", 6048, 6096, 3800, 4224, 88, 2568},
|
||||
//offsets for: /mysqlrpm/5.5.25/usr/sbin/mysqld (5.5.25)
|
||||
{"5.5.25","6043eff2cfa493d4e020cae65c41b030", 6056, 6104, 3808, 4232, 88, 2568},
|
||||
//offsets for: mysqlrpm/5.5.25a/usr/sbin/mysqld (5.5.25a)
|
||||
{"5.5.25a","b59c03244daf51d4327409288d8c889f", 6056, 6104, 3808, 4232, 88, 2568},
|
||||
|
||||
//DISTRIBUTION: tar.gz
|
||||
//offsets for: /mysql/5.1.30/bin/mysqld (5.1.30)
|
||||
@@ -199,7 +214,13 @@ static const ThdOffsets thd_offsets_arr[] =
|
||||
//offsets for: /mysql/5.1.60/bin/mysqld (5.1.60)
|
||||
{"5.1.60","5407e492f802cca03eccb2211205632d", 6336, 6400, 3696, 3968, 88, 2048},
|
||||
//offsets for: /mysql/5.1.61/bin/mysqld (5.1.61)
|
||||
{"5.1.61","c2ce56446b33ee22c16160b3f8206541", 6336, 6400, 3696, 3968, 88, 2048},
|
||||
{"5.1.61","c2ce56446b33ee22c16160b3f8206541", 6336, 6400, 3696, 3968, 88, 2048},
|
||||
//offsets for: /mysql/5.1.62/bin/mysqld (5.1.62)
|
||||
{"5.1.62","5ab9ae376d93b71120e1c9dc2129c580", 6336, 6400, 3696, 3968, 88, 2048},
|
||||
//offsets for: /mysql/5.1.63/bin/mysqld (5.1.63)
|
||||
{"5.1.63","ea56cc85859f146c42957177524492c3", 6336, 6400, 3696, 3968, 88, 2048},
|
||||
//offsets set by https://github.com/creechy
|
||||
{"5.1.63","2a6d7c81179baf6bc6bbb807b8b54967", 6336, 6400, 3696, 3968, 88, 2048},
|
||||
//offsets for: mysql/5.5.8/bin/mysqld (5.5.8)
|
||||
{"5.5.8","a32b163f08ca8bfd7486cd77200d9df3", 6032, 6080, 3776, 4200, 88, 2560},
|
||||
//offsets for: mysql/5.5.9/bin/mysqld (5.5.9)
|
||||
@@ -228,10 +249,17 @@ static const ThdOffsets thd_offsets_arr[] =
|
||||
{"5.5.18","099d31c0cd0754934b84c17f683d019e", 6040, 6088, 3792, 4216, 88, 2560},
|
||||
{"5.5.19","f000f941c4e4f7b84e66d7b8c115ca8f", 6048, 6096, 3800, 4224, 88, 2560},
|
||||
//offsets for: /mysql/5.5.20/bin/mysqld (5.5.20)
|
||||
{"5.5.20","8b68e84332b442d58a46ae4299380a99", 6048, 6096, 3800, 4224, 88, 2560}
|
||||
|
||||
|
||||
|
||||
{"5.5.20","8b68e84332b442d58a46ae4299380a99", 6048, 6096, 3800, 4224, 88, 2560},
|
||||
//offsets for: mysql/5.5.21/bin/mysqld (5.5.21)
|
||||
{"5.5.21","66d23cb577e2bcfe29da08833f5e7d8b", 6048, 6096, 3800, 4224, 88, 2560},
|
||||
//offsets for: /mysql/5.5.22/bin/mysqld (5.5.22)
|
||||
{"5.5.22","9152de65a0de0594f46e1db0d0c9a182", 6048, 6096, 3800, 4224, 88, 2560},
|
||||
//offsets for: /mysql/5.5.23/bin/mysqld (5.5.23)
|
||||
{"5.5.23","da3c9d8e3bf1c1235d283cbfad1631ab", 6048, 6096, 3800, 4224, 88, 2568},
|
||||
//offsets for: /mysql/5.5.24/bin/mysqld (5.5.24)
|
||||
{"5.5.24","5cb90eb8d4080f50fd7a432ad9eb75e0", 6048, 6096, 3800, 4224, 88, 2568},
|
||||
//offsets for: /mysql/5.5.25/bin/mysqld (5.5.25)
|
||||
{"5.5.25","3c19465f6b6f2daecb7a2d7ac1592824", 6056, 6104, 3808, 4232, 88, 2568}
|
||||
};
|
||||
|
||||
#else
|
||||
@@ -305,7 +333,11 @@ static const ThdOffsets thd_offsets_arr[] =
|
||||
//offsets for: /mysqlrpm/5.1.60/usr/sbin/mysqld (5.1.60-community)
|
||||
{"5.1.60-community","bc2d74ea58d22d998f8f8c88139fc5f7", 4096, 4136, 2240, 2420, 44, 1176},
|
||||
//offsets for: /mysqlrpm/5.1.61/usr/sbin/mysqld (5.1.61-community)
|
||||
{"5.1.61-community","f73013eb2001a02c84ddd0ac42a307ac", 4096, 4136, 2240, 2420, 44, 1176},
|
||||
{"5.1.61-community","f73013eb2001a02c84ddd0ac42a307ac", 4096, 4136, 2240, 2420, 44, 1176},
|
||||
//offsets for: /mysqlrpm/5.1.62/usr/sbin/mysqld (5.1.62-community)
|
||||
{"5.1.62-community","f410638e7414c6cc709b7d5cda24669c", 4096, 4136, 2240, 2420, 44, 1176},
|
||||
//offsets for: /mysqlrpm/5.1.63/usr/sbin/mysqld (5.1.63-community)
|
||||
{"5.1.63-community","2b39264a67466c6f1dfa37c37a8a6bd0", 4096, 4136, 2240, 2420, 44, 1176},
|
||||
//offsets for: mysqlrpm/5.5.8/usr/sbin/mysqld (5.5.8)
|
||||
{"5.5.8","3132e8c883f72caf4c8eddb24fd005b4", 3792, 3820, 2336, 2668, 44, 1640},
|
||||
//offsets for: mysqlrpm/5.5.9/usr/sbin/mysqld (5.5.9)
|
||||
@@ -332,7 +364,16 @@ static const ThdOffsets thd_offsets_arr[] =
|
||||
{"5.5.19","f3c31e2a5d95d3511b7106441f38929e", 3808, 3836, 2360, 2692, 44, 1640},
|
||||
//offsets for: /mysqlrpm/5.5.20/usr/sbin/mysqld (5.5.20)
|
||||
{"5.5.20","c73100bcb0d967b627cad72e66503194", 3808, 3836, 2360, 2692, 44, 1640},
|
||||
|
||||
//offsets for: mysqlrpm/5.5.21/usr/sbin/mysqld (5.5.21)
|
||||
{"5.5.21","18d78ced97227b83e62e9b43ba5b3883", 3808, 3836, 2360, 2692, 44, 1640},
|
||||
//offsets for: /mysqlrpm/5.5.22/usr/sbin/mysqld (5.5.22)
|
||||
{"5.5.22","9da3081f83069a2762831d0ead5a97c8", 3808, 3836, 2360, 2692, 44, 1640},
|
||||
//offsets for: /mysqlrpm/5.5.23/usr/sbin/mysqld (5.5.23)
|
||||
{"5.5.23","c94f20f31cfa674d5763da7d2344c219", 3808, 3836, 2360, 2692, 44, 1644},
|
||||
//offsets for: /mysqlrpm/5.5.24/usr/sbin/mysqld (5.5.24)
|
||||
{"5.5.24","10e0ced8d28daf6a9c16d2b57be7c6af", 3808, 3836, 2360, 2692, 44, 1644},
|
||||
//offsets for: /mysqlrpm/5.5.25/usr/sbin/mysqld (5.5.25)
|
||||
{"5.5.25","bd20af37978967a145724098e913eeda", 3812, 3840, 2364, 2696, 44, 1644},
|
||||
|
||||
//DISTRIBUTION: tar.gz
|
||||
//offsets for: mysql/5.1.30/bin/mysqld (5.1.30)
|
||||
@@ -399,7 +440,11 @@ static const ThdOffsets thd_offsets_arr[] =
|
||||
//offsets for: /mysql/5.1.60/bin/mysqld (5.1.60)
|
||||
{"5.1.60","520270041d8c490d49233e88741c025c", 4104, 4144, 2248, 2428, 44, 1176},
|
||||
//offsets for: /mysql/5.1.61/bin/mysqld (5.1.61)
|
||||
{"5.1.61","1a7a0981d77f4d212e899efaa581bd42", 4104, 4144, 2248, 2428, 44, 1176},
|
||||
{"5.1.61","1a7a0981d77f4d212e899efaa581bd42", 4104, 4144, 2248, 2428, 44, 1176},
|
||||
//offsets for: /mysql/5.1.62/bin/mysqld (5.1.62)
|
||||
{"5.1.62","4c5fd81faa9fe407c8a7fbd11b29351a", 4104, 4144, 2248, 2428, 44, 1176},
|
||||
//offsets for: /mysql/5.1.63/bin/mysqld (5.1.63)
|
||||
{"5.1.63","576124febe6310985e432f6346031ff4", 4104, 4144, 2248, 2428, 44, 1176},
|
||||
//offsets for: /mysqlrpm/5.5.8/usr/sbin/mysqld (5.5.8)
|
||||
{"5.5.8","3132e8c883f72caf4c8eddb24fd005b4", 3792, 3820, 2336, 2668, 44, 1640},
|
||||
{"5.5.8","ad8a16d9bbfb783dab53f38cef757900", 3792, 3820, 2336, 2668, 44, 1640},
|
||||
@@ -428,8 +473,19 @@ static const ThdOffsets thd_offsets_arr[] =
|
||||
//offsets for: /mysql/5.5.19/bin/mysqld (5.5.19)
|
||||
{"5.5.19","b407d678b9b855bfd29ba3c9f014d4b0", 3808, 3836, 2360, 2692, 44, 1640},
|
||||
//offsets for: /mysql/5.5.20/bin/mysqld (5.5.20)
|
||||
{"5.5.20","cb9b6887ea525fe9965121d357163fe4", 3808, 3836, 2360, 2692, 44, 1640}
|
||||
|
||||
{"5.5.20","cb9b6887ea525fe9965121d357163fe4", 3808, 3836, 2360, 2692, 44, 1640},
|
||||
//offsets for: mysql/5.5.21/bin/mysqld (5.5.21)
|
||||
{"5.5.21","a0762cee3ad5d4e77480956144900213", 3808, 3836, 2360, 2692, 44, 1640},
|
||||
//offsets for: /mysql/5.5.22/bin/mysqld (5.5.22)
|
||||
{"5.5.22","f635047c7ddf74dcac98612a65e40fe1", 3808, 3836, 2360, 2692, 44, 1640},
|
||||
//offsets for: /mysql-5.5_5.5.22-0ubuntu1_i386/bin/mysqld (5.5.22-0ubuntu1)
|
||||
{"5.5.22-0ubuntu1","9cc7d4582b1fae0ebf43dbe5ffb56008", 3784, 3812, 2336, 2668, 44, 1640},
|
||||
//offsets for: /mysql/5.5.23/bin/mysqld (5.5.23)
|
||||
{"5.5.23","8f51987d3f0d0dc044adcf42937050f6", 3808, 3836, 2360, 2692, 44, 1644},
|
||||
//offsets for: /mysql/5.5.24/bin/mysqld (5.5.24)
|
||||
{"5.5.24","a3916dca234905bd49b3fefe5d6ad738", 3808, 3836, 2360, 2692, 44, 1644},
|
||||
//offsets for: /mysql/5.5.25/bin/mysqld (5.5.25)
|
||||
{"5.5.25","f16c3fa53f77e5f25fd25694b5a27c48", 3812, 3840, 2364, 2696, 44, 1644}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -445,39 +501,48 @@ static Audit_json_formatter json_formatter;
|
||||
|
||||
//flags to hold if audit handlers are enabled
|
||||
static my_bool json_file_handler_enable = FALSE;
|
||||
static my_bool json_file_handler_flush = FALSE;
|
||||
static my_bool json_socket_handler_enable = FALSE;
|
||||
static my_bool uninstall_plugin_enable = FALSE;
|
||||
static my_bool validate_checksum_enable = FALSE;
|
||||
static char * offsets_string = NULL;
|
||||
static char * checksum_string = NULL;
|
||||
static int delay_ms_val =0;
|
||||
static char *delay_cmds_string = NULL;
|
||||
static char *record_cmds_string = NULL;
|
||||
static char *record_objs_string = NULL;
|
||||
|
||||
static char delay_cmds_array [SQLCOM_END + 2][MAX_COMMAND_CHAR_NUMBERS];
|
||||
|
||||
static char delay_cmds_array [SQLCOM_END + 2][MAX_COMMAND_CHAR_NUMBERS] = {0};
|
||||
static char record_cmds_array [SQLCOM_END + 2][MAX_COMMAND_CHAR_NUMBERS] = {0};
|
||||
static char record_objs_array [MAX_NUM_OBJECT_ELEM + 2][MAX_OBJECT_CHAR_NUMBERS] = {0};
|
||||
static int num_delay_cmds = 0;
|
||||
static int num_record_cmds = 0;
|
||||
static int num_record_objs = 0;
|
||||
static SHOW_VAR com_status_vars_array [MAX_COM_STATUS_VARS_RECORDS] = {0};
|
||||
/**
|
||||
* The trampoline function we use. Define it via a macro which simply fills it with nops.
|
||||
*/
|
||||
static int trampoline_mysql_execute_command(THD *thd)
|
||||
__attribute__ ((noinline)) static int trampoline_mysql_execute_command(THD *thd)
|
||||
{
|
||||
TRAMPOLINE_NOP_DEF;
|
||||
return 0; //dummy return as this does a jump.
|
||||
}
|
||||
static unsigned int trampoline_mysql_execute_size =0;
|
||||
|
||||
static void trampoline_log_slow_statement(THD *thd)
|
||||
__attribute__ ((noinline)) static void trampoline_log_slow_statement(THD *thd)
|
||||
{
|
||||
TRAMPOLINE_NOP_DEF
|
||||
}
|
||||
static unsigned int trampoline_log_slow_statement_size =0;
|
||||
|
||||
static int trampoline_check_user(THD *thd, enum enum_server_command command, const char *passwd, uint passwd_len, const char *db, bool check_count)
|
||||
__attribute__ ((noinline)) static int trampoline_check_user(THD *thd, enum enum_server_command command, const char *passwd, uint passwd_len, const char *db, bool check_count)
|
||||
{
|
||||
TRAMPOLINE_NOP_DEF;
|
||||
return 0; //dummy return as this does a jump.
|
||||
}
|
||||
static unsigned int trampoline_check_user_size =0;
|
||||
|
||||
bool trampoline_acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len){
|
||||
__attribute__ ((noinline)) static bool trampoline_acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len){
|
||||
TRAMPOLINE_NOP_DEF;
|
||||
return 0; //dummy return as this does a jump.
|
||||
}
|
||||
@@ -503,9 +568,63 @@ THDPRINTED * GetThdPrintedList (THD *thd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int check_array(const char *cmds[],const char *array, int length) {
|
||||
for (int k=0; array[k * length] !='\0';k++) {
|
||||
for (int q = 0; cmds[q] != NULL; q++) {
|
||||
const char *cmd = cmds[q];
|
||||
int j = 0;
|
||||
while (array[k * length + j] != '\0' && cmd[j] != '\0'
|
||||
&& array[k * length + j] == tolower(cmd[j])) {
|
||||
j++;
|
||||
}
|
||||
if (array[k * length + j] == '\0' && j != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static void audit(ThdSesData *pThdData)
|
||||
{
|
||||
THDPRINTED *pThdPrintedList = GetThdPrintedList (pThdData->getTHD());
|
||||
if (num_record_cmds > 0) {
|
||||
const char * cmd = pThdData->getCmdName();
|
||||
const char *cmds[2];
|
||||
cmds[0] = cmd;
|
||||
cmds[1] = NULL;
|
||||
if (!check_array(cmds, (char *) record_cmds_array, MAX_COMMAND_CHAR_NUMBERS)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (num_record_objs > 0) {
|
||||
LEX *pLex = Audit_formatter::thd_lex(pThdData->getTHD());
|
||||
TABLE_LIST * table = pLex->query_tables;
|
||||
int matched = 0;
|
||||
while (table && !matched) {
|
||||
char *name = table->get_table_name();
|
||||
char *db = table->get_db_name();
|
||||
char db_obj[MAX_OBJECT_CHAR_NUMBERS];
|
||||
char wildcard_obj[MAX_OBJECT_CHAR_NUMBERS];
|
||||
char db_wildcard[MAX_OBJECT_CHAR_NUMBERS];
|
||||
strcpy(db_obj, db);
|
||||
strcat(db_obj, ".");
|
||||
strcat(db_obj, name);
|
||||
strcpy(wildcard_obj, "*.");
|
||||
strcat(wildcard_obj, name);
|
||||
strcpy(db_wildcard, db);
|
||||
strcat(db_wildcard, ".*");
|
||||
const char *objects[4];
|
||||
objects[0] = db_obj;
|
||||
objects[1] = wildcard_obj;
|
||||
objects[2] = db_wildcard;
|
||||
objects[3] = NULL;
|
||||
matched = check_array(objects, (char *) record_objs_array, MAX_OBJECT_CHAR_NUMBERS);
|
||||
table = table->next_global;
|
||||
}
|
||||
if (!matched) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (pThdPrintedList && pThdPrintedList->cur_index < MAX_NUM_QUEUE_ELEM)
|
||||
{
|
||||
if (pThdPrintedList->is_thd_printed_queue[pThdPrintedList->cur_index] == 0)
|
||||
@@ -525,34 +644,27 @@ static void audit(ThdSesData *pThdData)
|
||||
if (delay_ms_val > 0)
|
||||
{
|
||||
const char * cmd = pThdData->getCmdName();
|
||||
for (int k=0; delay_cmds_array[k][0] !='\0';k++)
|
||||
{
|
||||
int j=0;
|
||||
for (;delay_cmds_array[k][j] !='\0'
|
||||
&& cmd[j] !='\0'
|
||||
&& delay_cmds_array[k][j] == tolower (cmd[j]);j++)
|
||||
{
|
||||
|
||||
}
|
||||
if (delay_cmds_array[k][j] == '\0' && j !=0)
|
||||
const char *cmds[2];
|
||||
cmds[0] = cmd;
|
||||
cmds[1] = NULL;
|
||||
int delay = check_array(cmds, (char *) delay_cmds_array, MAX_COMMAND_CHAR_NUMBERS);
|
||||
if (delay)
|
||||
{
|
||||
//Audit_file_handler::print_sleep(thd,delay_ms_val);
|
||||
my_sleep (delay_ms_val *1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int trampoline_send_result_to_client(Query_cache *pthis, THD *thd, char *sql, uint query_length)
|
||||
__attribute__ ((noinline)) static int trampoline_send_result_to_client(Query_cache *pthis, THD *thd, char *sql, uint query_length)
|
||||
{
|
||||
TRAMPOLINE_NOP_DEF;
|
||||
return 0 ; //dummy return as this does a jump.
|
||||
}
|
||||
|
||||
#if MYSQL_VERSION_ID > 50505
|
||||
bool trampoline_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
|
||||
__attribute__ ((noinline)) static bool trampoline_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
|
||||
Prelocking_strategy *prelocking_strategy)
|
||||
{
|
||||
TRAMPOLINE_NOP_DEF;
|
||||
@@ -560,7 +672,7 @@ bool trampoline_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint fl
|
||||
return true ; //dummy return as this does a jump.
|
||||
}
|
||||
#else
|
||||
static int trampoline_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
||||
__attribute__ ((noinline)) static int trampoline_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
||||
{
|
||||
TRAMPOLINE_NOP_DEF;
|
||||
TRAMPOLINE_NOP_DEF;
|
||||
@@ -586,7 +698,7 @@ NULL, NULL,0,0,
|
||||
return (QueryTableInf*) THDVAR(thd, query_cache_table_list);
|
||||
}
|
||||
|
||||
static bool trampoline_check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, uint number, bool no_errors)
|
||||
__attribute__ ((noinline)) static bool trampoline_check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, uint number, bool no_errors)
|
||||
{
|
||||
TRAMPOLINE_NOP_DEF
|
||||
return true;
|
||||
@@ -927,6 +1039,31 @@ static bool parse_thd_offsets_string (char *poffsets_string)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool validate_offsets(const ThdOffsets * offset)
|
||||
{
|
||||
//check that offsets are actually correct. We use a buff of memory as a dummy THD (32K is high enough)
|
||||
char buf[32*1024] = {0};
|
||||
THD * thd = (THD *)buf;
|
||||
//sanity check that offsets match
|
||||
//we can also consider using secutiry context function to do some sanity checks
|
||||
// char buffer[2048];
|
||||
// thd_security_context(thd, buffer, 2048, 2000);
|
||||
// fprintf(log_file, "info from security context: %s\n", buffer);
|
||||
|
||||
//we set the thread id to a value using the offset and then check that the value matches what thd_get_thread_id returns
|
||||
const my_thread_id test_val = 123456;
|
||||
(*(my_thread_id *) (((char *) thd)+ offset->thread_id)) = test_val;
|
||||
my_thread_id res= thd_get_thread_id(thd);
|
||||
bool retval = res == test_val;
|
||||
if (!retval)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s Offsets version: %s match thread validation check fails with value: %lu. Skipping offest.",
|
||||
log_prefix, offset->version, res);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the offsets needs to extract data from THD.
|
||||
*
|
||||
@@ -935,22 +1072,73 @@ static bool parse_thd_offsets_string (char *poffsets_string)
|
||||
static int setup_offsets()
|
||||
{
|
||||
DBUG_ENTER("setup_offsets");
|
||||
sql_print_information ("%s setup_offsets offsets_string %s",log_prefix, offsets_string);
|
||||
sql_print_information ("%s setup_offsets audit_offsets: %s",log_prefix, offsets_string);
|
||||
|
||||
unsigned char digest[16] = {0};
|
||||
char digest_str [128] = {0};
|
||||
const ThdOffsets * offset;
|
||||
|
||||
//if present in my.cnf
|
||||
//[mysqld]
|
||||
//audit_validate_checksum=1
|
||||
// or if
|
||||
//audit_checksum=0f4d7e3b17eb36f17aafe4360993a769
|
||||
//need to calculate digest
|
||||
if (validate_checksum_enable || (checksum_string != NULL && strlen(checksum_string) > 0))
|
||||
{
|
||||
//setup digest_str to contain the md5sum in hex
|
||||
sql_print_information(
|
||||
"%s Validate checksum enabled. Mysqld %s ",
|
||||
log_prefix, my_progname);
|
||||
my_MD5Context context;
|
||||
my_MD5Init(&context);
|
||||
unsigned char * file_buff;
|
||||
MY_STAT stat_arg;
|
||||
File fd;
|
||||
if (my_stat(my_progname, &stat_arg, MYF(MY_WME)))
|
||||
{
|
||||
if ((fd = my_open(my_progname, O_RDONLY,
|
||||
MYF(MY_WME))) > 0)
|
||||
{
|
||||
file_buff = (unsigned char*) my_malloc(
|
||||
(uint) stat_arg.st_size, MYF (MY_WME));
|
||||
if (read(fd, (char*) file_buff,
|
||||
(uint) stat_arg.st_size) >= 0L)
|
||||
{
|
||||
my_MD5Update(&context, file_buff,
|
||||
stat_arg.st_size);
|
||||
my_MD5Final(digest, &context);
|
||||
}
|
||||
(void) my_close(fd, MYF(0));
|
||||
#if MYSQL_VERSION_ID > 50505
|
||||
my_free(file_buff);
|
||||
#else
|
||||
my_free(file_buff, MYF(0));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < 16; j++)
|
||||
{
|
||||
sprintf(&(digest_str[j * 2]), "%02x", digest[j]);
|
||||
}
|
||||
}
|
||||
|
||||
//if present the offset_string specified in my.cnf
|
||||
//[mysqld]
|
||||
//audit_offsets=6200, 6264, 3672, 3944, 88, 2048
|
||||
|
||||
if (offsets_string !=NULL)
|
||||
{
|
||||
|
||||
char buf[32*1024] = {0};
|
||||
THD * thd = (THD *)buf;
|
||||
const my_thread_id test_val = 123456;
|
||||
|
||||
if (offsets_string != NULL)
|
||||
{
|
||||
if (checksum_string != NULL && strlen(checksum_string) > 0)
|
||||
{
|
||||
if (strncasecmp(checksum_string, digest_str, 32))
|
||||
{
|
||||
sql_print_information(
|
||||
"%s checksum check failed for %s, but found %s",
|
||||
log_prefix, checksum_string, digest_str);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
if (parse_thd_offsets_string (offsets_string))
|
||||
{
|
||||
sql_print_information ("%s setup_offsets Audit_formatter::thd_offsets values: %d %d %d %d %d %d ", log_prefix,
|
||||
@@ -961,60 +1149,26 @@ static int setup_offsets()
|
||||
Audit_formatter::thd_offsets.lex,
|
||||
Audit_formatter::thd_offsets.lex_comment);
|
||||
|
||||
(*(my_thread_id *) (((char *) thd)+ Audit_formatter::thd_offsets.thread_id)) = test_val;
|
||||
my_thread_id res= thd_get_thread_id(thd);
|
||||
if (res != test_val)
|
||||
{
|
||||
|
||||
sql_print_error("%s thread id check fails with value: %lu. Skipping offest.", log_prefix, res);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (!validate_offsets(&Audit_formatter::thd_offsets))
|
||||
{
|
||||
sql_print_error("%s Offsets set didn't pass validation. audit_offsets: %s .", log_prefix, offsets_string);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_print_error("%s Audit offsets parser error. Skipping offest.", log_prefix);
|
||||
sql_print_error("%s Failed parsing audit_offsets: %s", log_prefix, offsets_string);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
sql_print_information ("%s Validation passed. Using offsets from audit_offsets: %s",log_prefix, offsets_string);
|
||||
DBUG_RETURN(0);
|
||||
//exit from function
|
||||
}
|
||||
|
||||
size_t arr_size = (sizeof(thd_offsets_arr) / sizeof(thd_offsets_arr[0]));
|
||||
//iterate and search for the first offset which matches the version
|
||||
|
||||
//if present in my.cnf
|
||||
//[mysqld]
|
||||
//audit_validate_checksum=1
|
||||
//plugin-load=AUDIT=libaudit_plugin.so
|
||||
if (validate_checksum_enable)
|
||||
{
|
||||
sql_print_information ("%s Audit validate checksum enabled. Mysqld %s ",log_prefix, my_progname);
|
||||
my_MD5Context context;
|
||||
my_MD5Init (&context);
|
||||
unsigned char * file_buff;
|
||||
MY_STAT stat_arg;
|
||||
File fd;
|
||||
if (my_stat(my_progname,&stat_arg,MYF(MY_WME)))
|
||||
{
|
||||
if ((fd = my_open(my_progname,O_RDONLY, MYF(MY_WME))) > 0)
|
||||
{
|
||||
file_buff = (unsigned char*) my_malloc ((uint) stat_arg.st_size, MYF (MY_WME));
|
||||
if (read(fd,(char*) file_buff,(uint) stat_arg.st_size) >= 0L)
|
||||
{
|
||||
my_MD5Update (&context, file_buff, stat_arg.st_size);
|
||||
my_MD5Final (digest, &context);
|
||||
}
|
||||
(void) my_close(fd,MYF(0));
|
||||
free (file_buff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
bool bCheckSumValidation = false;
|
||||
for(int i=0; i < arr_size; i++)
|
||||
{
|
||||
|
||||
offset = thd_offsets_arr + i;
|
||||
//if present in my.cnf
|
||||
//[mysqld]
|
||||
@@ -1022,23 +1176,8 @@ static int setup_offsets()
|
||||
//plugin-load=AUDIT=libaudit_plugin.so
|
||||
if (validate_checksum_enable && strlen (offset->md5digest) >0)
|
||||
{
|
||||
memset (digest_str,0,sizeof (digest_str));
|
||||
bCheckSumValidation = true;
|
||||
int kd=0;
|
||||
for (int j=0;j<16;j++)
|
||||
{
|
||||
unsigned char Dig=0;
|
||||
char DigStr[3]={0};
|
||||
DigStr[0]= offset->md5digest[kd++];
|
||||
DigStr[1]= offset->md5digest[kd++];
|
||||
sscanf (DigStr,"%x",&Dig);
|
||||
sprintf (digest_str,"%s %2x",digest_str,digest[j]);
|
||||
if (Dig != digest[j])
|
||||
{
|
||||
bCheckSumValidation = false;
|
||||
}
|
||||
}
|
||||
if (bCheckSumValidation)
|
||||
if (!strncasecmp(digest_str, offset->md5digest, 32))
|
||||
{
|
||||
sql_print_information ("%s Checksum is %s verified", log_prefix, digest_str);
|
||||
sql_print_information("%s Using offsets from offset version: %s", log_prefix, offset->version);
|
||||
@@ -1046,7 +1185,6 @@ static int setup_offsets()
|
||||
DBUG_RETURN(0);
|
||||
//return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//if present in my.cnf
|
||||
@@ -1054,35 +1192,36 @@ static int setup_offsets()
|
||||
//audit_validate_checksum=0
|
||||
//plugin-load=AUDIT=libaudit_plugin.so
|
||||
if(!validate_checksum_enable && (strstr(server_version, offset->version)))
|
||||
{
|
||||
//check that offsets are actually correct. We use a buff of memory as a dummy THD (32K is high enough)
|
||||
char buf[32*1024] = {0};
|
||||
THD * thd = (THD *)buf;
|
||||
//sanity check that offsets match
|
||||
//we can also consider using secutiry context function to do some sanity checks
|
||||
// char buffer[2048];
|
||||
// thd_security_context(thd, buffer, 2048, 2000);
|
||||
// fprintf(log_file, "info from security context: %s\n", buffer);
|
||||
//we set the thread id to a value using the offset and then check that the value matches what thd_get_thread_id returns
|
||||
|
||||
unsigned long inst_thread_id = Audit_formatter::thd_inst_thread_id(thd);
|
||||
const my_thread_id test_val = 123456;
|
||||
(*(my_thread_id *) (((char *) thd)+ offset->thread_id)) = test_val;
|
||||
my_thread_id res= thd_get_thread_id(thd);
|
||||
if (res != test_val)
|
||||
{
|
||||
if (validate_offsets(offset))
|
||||
{
|
||||
sql_print_error(
|
||||
"%s Offsets version: %s match server version: %s but thread id check fails with value: %lu. Skipping offest.",
|
||||
log_prefix, offset->version, server_version, res);
|
||||
}
|
||||
sql_print_information("%s Using offsets from offset version: %s, digest: %s", log_prefix, offset->version, offset->md5digest);
|
||||
Audit_formatter::thd_offsets = *offset;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_print_information("%s Using offsets from offset version: %s", log_prefix, offset->version);
|
||||
Audit_formatter::thd_offsets = *offset;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
//try doing 24 byte decrement on THD offsets. Seen that on Ubuntu/Debian this is valid.
|
||||
OFFSET dec = 24;
|
||||
ThdOffsets decoffsets = *offset;
|
||||
decoffsets.query_id -= dec;
|
||||
decoffsets.thread_id -= dec;
|
||||
decoffsets.main_security_ctx -= dec;
|
||||
decoffsets.command -= dec;
|
||||
if (validate_offsets(&decoffsets))
|
||||
{
|
||||
Audit_formatter::thd_offsets = decoffsets;
|
||||
sql_print_information("%s Using decrement (%d) offsets from offset version: %s, digest: %s values: %d %d %d %d %d %d", log_prefix, dec, offset->version, offset->md5digest,
|
||||
Audit_formatter::thd_offsets.query_id,
|
||||
Audit_formatter::thd_offsets.thread_id,
|
||||
Audit_formatter::thd_offsets.main_security_ctx,
|
||||
Audit_formatter::thd_offsets.command,
|
||||
Audit_formatter::thd_offsets.lex,
|
||||
Audit_formatter::thd_offsets.lex_comment);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1090,6 +1229,116 @@ static int setup_offsets()
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
const char * retrieve_command (THD * thd)
|
||||
{
|
||||
const char *cmd = NULL;
|
||||
|
||||
int command = Audit_formatter::thd_inst_command(thd);
|
||||
if (command < 0 || command > COM_END)
|
||||
{
|
||||
command = COM_END;
|
||||
}
|
||||
const int sql_command = thd_sql_command(thd);
|
||||
if (sql_command >=0 && sql_command <= (MAX_COM_STATUS_VARS_RECORDS -1) )
|
||||
{
|
||||
cmd = com_status_vars_array[sql_command + 1].name;
|
||||
}
|
||||
if(!cmd)
|
||||
{
|
||||
cmd = command_name[command].str;
|
||||
}
|
||||
Security_context * sctx = Audit_formatter::thd_inst_main_security_ctx(thd);
|
||||
if (strcmp (cmd, "Connect") ==0 && (sctx->priv_user == NULL || *sctx->priv_user == 0x0))
|
||||
{
|
||||
cmd = "Failed Login";
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static int set_com_status_vars_array ()
|
||||
{
|
||||
DBUG_ENTER("set_com_status_vars_array");
|
||||
SHOW_VAR *com_status_vars;
|
||||
int sv_idx =0;
|
||||
while (strcmp (status_vars[sv_idx].name,"Com") !=0 && status_vars[sv_idx].name != NullS)
|
||||
{
|
||||
sv_idx ++;
|
||||
}
|
||||
if (strcmp (status_vars[sv_idx].name,"Com")==0)
|
||||
{
|
||||
int status_vars_index =0;
|
||||
com_status_vars = (SHOW_VAR*)status_vars[sv_idx].value;
|
||||
size_t initial_offset = (size_t) com_status_vars[0].value;
|
||||
while (com_status_vars[status_vars_index].name != NullS)
|
||||
{
|
||||
int sql_command_idx = (com_status_vars[status_vars_index].value - (char*) (initial_offset)) / sizeof (ulong);
|
||||
if (sql_command_idx >=0 && sql_command_idx < MAX_COM_STATUS_VARS_RECORDS)
|
||||
{
|
||||
com_status_vars_array [sql_command_idx].name = com_status_vars[status_vars_index].name;
|
||||
com_status_vars_array [sql_command_idx].type = com_status_vars[status_vars_index].type;
|
||||
com_status_vars_array [sql_command_idx].value = com_status_vars[status_vars_index].value;
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_print_error("%s Failed sql_command_idx [%d] is out of bounds. Plugin Init failed.",
|
||||
log_prefix, sql_command_idx);
|
||||
DBUG_RETURN (1);
|
||||
}
|
||||
status_vars_index ++;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_print_error("%s Failed looking up 'Com' entry in status_vars. Plugin Init failed.",
|
||||
log_prefix);
|
||||
DBUG_RETURN (1);
|
||||
}
|
||||
DBUG_RETURN (0);
|
||||
}
|
||||
static int string_to_array(const void *save, void *array,
|
||||
int rows, int length)
|
||||
{
|
||||
const char* save_string;
|
||||
save_string = *static_cast<const char* const *> (save);
|
||||
char* string_array;
|
||||
string_array = (char *) array;
|
||||
int r = 0;
|
||||
if (save_string != NULL)
|
||||
{
|
||||
int p = 0;
|
||||
for (int i = 0; save_string[i] != '\0'; i++)
|
||||
{
|
||||
if (save_string[i] == ' ' || save_string[i] == '\t'
|
||||
|| save_string[i] == ',')
|
||||
{
|
||||
if (p > 0)
|
||||
{
|
||||
string_array[r * length + p] = '\0';
|
||||
p = 0;
|
||||
r++;
|
||||
if (r == (rows - 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string_array[r * length + p] = tolower(save_string[i]);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if (p > 0)
|
||||
{
|
||||
string_array[r * length + p] = '\0';
|
||||
r++;
|
||||
}
|
||||
string_array[r * length + 0] = '\0';
|
||||
}
|
||||
return r;
|
||||
}
|
||||
/*
|
||||
Initialize the daemon plugin installation.
|
||||
|
||||
@@ -1105,17 +1354,36 @@ static int audit_plugin_init(void *p)
|
||||
{
|
||||
|
||||
DBUG_ENTER("audit_plugin_init");
|
||||
|
||||
#ifdef __x86_64__
|
||||
const char * arch = "64bit";
|
||||
#else
|
||||
const char * arch = "32bit";
|
||||
#endif
|
||||
|
||||
sql_print_information(
|
||||
"%s starting up. Version: %s, Revision: %s. AUDIT plugin interface version: %d. MySQL Server version: %s.",
|
||||
"%s starting up. Version: %s , Revision: %s (%s). AUDIT plugin interface version: %d. MySQL Server version: %s.",
|
||||
log_prefix, MYSQL_AUDIT_PLUGIN_VERSION,
|
||||
MYSQL_AUDIT_PLUGIN_REVISION, audit_plugin.interface_version >> 8,
|
||||
MYSQL_AUDIT_PLUGIN_REVISION, arch, audit_plugin.interface_version >> 8,
|
||||
server_version);
|
||||
//setup our offsets.
|
||||
if(setup_offsets() != 0)
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (delay_cmds_string != NULL) {
|
||||
num_delay_cmds = string_to_array(&delay_cmds_string, delay_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS);
|
||||
sql_print_information("%s Set num_delay_cmds: %d", log_prefix, num_delay_cmds);
|
||||
}
|
||||
if (record_cmds_string != NULL) {
|
||||
num_record_cmds = string_to_array(&record_cmds_string, record_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS);
|
||||
sql_print_information("%s Set num_record_cmds: %d", log_prefix, num_record_cmds);
|
||||
}
|
||||
if (record_objs_string != NULL) {
|
||||
num_record_objs = string_to_array(&record_objs_string, record_objs_array, MAX_NUM_OBJECT_ELEM + 2, MAX_OBJECT_CHAR_NUMBERS);
|
||||
sql_print_information("%s Set num_record_objs: %d", log_prefix, num_record_objs);
|
||||
}
|
||||
|
||||
//setup audit handlers (initially disabled)
|
||||
int res = json_file_handler.init(&json_formatter);
|
||||
if (res != 0)
|
||||
@@ -1136,9 +1404,9 @@ static int audit_plugin_init(void *p)
|
||||
//enable according to what we have in *file_handler_enable (this is set accordingly by sysvar functionality)
|
||||
json_file_handler.set_enable(json_file_handler_enable);
|
||||
json_socket_handler.set_enable(json_socket_handler_enable);
|
||||
Audit_handler::m_audit_handler_list[Audit_handler::BSON_FILE_HANDLER]
|
||||
Audit_handler::m_audit_handler_list[Audit_handler::JSON_FILE_HANDLER]
|
||||
= &json_file_handler;
|
||||
Audit_handler::m_audit_handler_list[Audit_handler::BSON_SOCKET_HANDLER]
|
||||
Audit_handler::m_audit_handler_list[Audit_handler::JSON_SOCKET_HANDLER]
|
||||
= &json_socket_handler;
|
||||
|
||||
//hot patch functions
|
||||
@@ -1254,7 +1522,7 @@ static int audit_plugin_init(void *p)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
sql_print_information(
|
||||
"%s hot patch open_tables address %p. Trampoline size: %ud.",
|
||||
"%s hot patch open_tables address %p. Trampoline size: %u.",
|
||||
log_prefix, *(bool (*)(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
|
||||
Prelocking_strategy *prelocking_strategy)) &open_tables,
|
||||
trampoline_open_tables_size);
|
||||
@@ -1276,7 +1544,11 @@ static int audit_plugin_init(void *p)
|
||||
log_prefix, *(bool (*)(THD *thd, TABLE_LIST **start, uint *counter, uint flags)) &open_tables,
|
||||
trampoline_open_tables_size);
|
||||
#endif
|
||||
|
||||
if (set_com_status_vars_array () !=0)
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
sql_print_information("%s Init completed successfully.", log_prefix);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@@ -1294,8 +1566,9 @@ static int audit_plugin_init(void *p)
|
||||
*/
|
||||
|
||||
static int audit_plugin_deinit(void *p)
|
||||
{
|
||||
{
|
||||
DBUG_ENTER("audit_plugin_deinit");
|
||||
sql_print_information("%s deinit", log_prefix);
|
||||
remove_hot_functions();
|
||||
//disable handlers
|
||||
DBUG_RETURN(0);
|
||||
@@ -1328,6 +1601,20 @@ static void json_log_file_enable(THD *thd, struct st_mysql_sys_var *var,
|
||||
}
|
||||
}
|
||||
|
||||
static void json_log_file_flush(THD *thd, struct st_mysql_sys_var *var,
|
||||
void *tgt, const void *save)
|
||||
{
|
||||
//always set to false. as we just flush if set to true and leave at 0
|
||||
json_file_handler_flush = FALSE;
|
||||
my_bool val = *(my_bool *) save ? TRUE : FALSE;
|
||||
if(val && json_file_handler.is_init())
|
||||
{
|
||||
json_file_handler.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void json_log_socket_enable(THD *thd, struct st_mysql_sys_var *var,
|
||||
void *tgt, const void *save)
|
||||
@@ -1339,56 +1626,28 @@ static void json_log_socket_enable(THD *thd, struct st_mysql_sys_var *var,
|
||||
}
|
||||
}
|
||||
|
||||
static void delay_cmds_string_handler (THD *thd, struct st_mysql_sys_var *var,
|
||||
void *tgt, const void *save)
|
||||
static void delay_cmds_string_update(THD *thd,
|
||||
struct st_mysql_sys_var *var, void *tgt,
|
||||
const void *save)
|
||||
{
|
||||
num_delay_cmds = string_to_array(save, delay_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS);
|
||||
sql_print_information("%s Set num_delay_cmds: %d", log_prefix, num_delay_cmds);
|
||||
}
|
||||
|
||||
char *old= *(char **) tgt;
|
||||
*(char **)tgt= my_strdup(*(char **) save, MYF(0));
|
||||
#if MYSQL_VERSION_ID > 50505
|
||||
my_free(old);
|
||||
#else
|
||||
my_free(old, MYF(0));
|
||||
#endif
|
||||
static void record_cmds_string_update(THD *thd,
|
||||
struct st_mysql_sys_var *var, void *tgt,
|
||||
const void *save)
|
||||
{
|
||||
num_record_cmds = string_to_array(save, record_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS);
|
||||
sql_print_information("%s Set num_record_cmds: %d", log_prefix, num_record_cmds);
|
||||
}
|
||||
|
||||
const char* save_string;
|
||||
save_string = *static_cast<const char*const*>(save);
|
||||
|
||||
int k =0;
|
||||
if (save_string !=NULL)
|
||||
{
|
||||
|
||||
int j =0;
|
||||
for (int i=0; save_string[i] !='\0'; i++,j++)
|
||||
{
|
||||
while (save_string[i] ==' ' || save_string[i] == '\t' || save_string[i] == ',' )
|
||||
{
|
||||
if (save_string[i] == ',')
|
||||
{
|
||||
if (j+1 < MAX_COMMAND_CHAR_NUMBERS)
|
||||
{
|
||||
delay_cmds_array[k][j] = '\0';
|
||||
}
|
||||
k++;
|
||||
j=0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (k < SQLCOM_END && j < MAX_COMMAND_CHAR_NUMBERS)
|
||||
{
|
||||
delay_cmds_array[k][j] = tolower (save_string[i]);
|
||||
}
|
||||
}
|
||||
if (k < SQLCOM_END && j < MAX_COMMAND_CHAR_NUMBERS)
|
||||
{
|
||||
delay_cmds_array[k][j] = '\0';
|
||||
}
|
||||
|
||||
}
|
||||
if (k < SQLCOM_END)
|
||||
{
|
||||
delay_cmds_array[k+1][0]='\0';
|
||||
}
|
||||
static void record_objs_string_update(THD *thd,
|
||||
struct st_mysql_sys_var *var, void *tgt,
|
||||
const void *save)
|
||||
{
|
||||
num_record_objs = string_to_array(save, record_objs_array, MAX_NUM_OBJECT_ELEM + 2, MAX_OBJECT_CHAR_NUMBERS);
|
||||
sql_print_information("%s Set num_record_objs: %d", log_prefix, num_record_objs);
|
||||
}
|
||||
|
||||
//setup sysvars which update directly the relevant plugins
|
||||
@@ -1405,8 +1664,12 @@ static MYSQL_SYSVAR_UINT(json_file_sync, json_file_handler.m_sync_period,
|
||||
NULL, NULL, 0, 0, UINT_MAX32, 0);
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(json_file, json_file_handler_enable,
|
||||
PLUGIN_VAR_OPCMDARG,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT plugin json log file Enable|Disable", NULL, json_log_file_enable, 0);
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(json_file_flush, json_file_handler_flush,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_NOCMDOPT,
|
||||
"AUDIT plugin json log file flush. Set to ON to perform a flush of the log.", NULL, json_log_file_flush, 0);
|
||||
|
||||
|
||||
static MYSQL_SYSVAR_STR(json_socket_name, json_socket_handler.m_sockname,
|
||||
@@ -1419,6 +1682,10 @@ static MYSQL_SYSVAR_STR(offsets, offsets_string,
|
||||
"AUDIT plugin offsets. Comma separated list of offsets to use for extracting data",
|
||||
NULL, NULL, NULL);
|
||||
|
||||
static MYSQL_SYSVAR_STR(checksum, checksum_string,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC,
|
||||
"AUDIT plugin checksum. Checksum for mysqld corresponding to offsets",
|
||||
NULL, NULL, "");
|
||||
static MYSQL_SYSVAR_BOOL(uninstall_plugin, uninstall_plugin_enable,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
|
||||
"AUDIT uninstall plugin Enable|Disable. Default disabled. If disabled attempts to uninstall the AUDIT plugin via the sql UNINSTALL command will fail.", NULL, NULL, 0);
|
||||
@@ -1429,7 +1696,7 @@ static MYSQL_SYSVAR_BOOL(validate_checksum, validate_checksum_enable,
|
||||
"AUDIT plugin binary checksum validation Enable|Disable", NULL, NULL, 1);
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(json_socket, json_socket_handler_enable,
|
||||
PLUGIN_VAR_OPCMDARG,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT plugin json log unix socket Enable|Disable", NULL, json_log_socket_enable, 0);
|
||||
|
||||
static MYSQL_SYSVAR_INT(delay_ms, delay_ms_val,
|
||||
@@ -1438,9 +1705,17 @@ static MYSQL_SYSVAR_INT(delay_ms, delay_ms_val,
|
||||
NULL, NULL, 0, 0, INT_MAX32, 0);
|
||||
|
||||
static MYSQL_SYSVAR_STR(delay_cmds, delay_cmds_string,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
|
||||
"AUDIT plugin delay commands to match against comma separated. If empty then delay is disabled.",
|
||||
NULL, delay_cmds_string_handler, NULL);
|
||||
NULL, delay_cmds_string_update, NULL);
|
||||
static MYSQL_SYSVAR_STR(record_cmds, record_cmds_string,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
|
||||
"AUDIT plugin commands to record, comma separated",
|
||||
NULL, record_cmds_string_update, NULL);
|
||||
static MYSQL_SYSVAR_STR(record_objs, record_objs_string,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
|
||||
"AUDIT plugin objects to record, comma separated",
|
||||
NULL, record_objs_string_update, NULL);
|
||||
|
||||
/*
|
||||
* Plugin system vars
|
||||
@@ -1450,6 +1725,7 @@ static struct st_mysql_sys_var* audit_system_variables[] =
|
||||
MYSQL_SYSVAR(json_log_file),
|
||||
MYSQL_SYSVAR(json_file_sync),
|
||||
MYSQL_SYSVAR(json_file),
|
||||
MYSQL_SYSVAR(json_file_flush),
|
||||
MYSQL_SYSVAR(uninstall_plugin),
|
||||
MYSQL_SYSVAR(validate_checksum),
|
||||
MYSQL_SYSVAR(json_socket_name),
|
||||
@@ -1459,6 +1735,9 @@ static struct st_mysql_sys_var* audit_system_variables[] =
|
||||
MYSQL_SYSVAR(is_thd_printed_list),
|
||||
MYSQL_SYSVAR(delay_ms),
|
||||
MYSQL_SYSVAR(delay_cmds),
|
||||
MYSQL_SYSVAR(record_cmds),
|
||||
MYSQL_SYSVAR(record_objs),
|
||||
MYSQL_SYSVAR(checksum),
|
||||
NULL };
|
||||
|
||||
//declare our plugin
|
||||
@@ -1485,7 +1764,7 @@ mysql_declare_plugin_end;
|
||||
* We set here the audit plugin version to the same as the first built in plugin.
|
||||
* This is so we can have a single lib for all versions (needed in 5.1)
|
||||
*/
|
||||
void __attribute__ ((constructor)) audit_plugin_so_init(void)
|
||||
extern "C" void __attribute__ ((constructor)) audit_plugin_so_init(void)
|
||||
{
|
||||
if (mysqld_builtins && mysqld_builtins[0])
|
||||
{
|
||||
@@ -1503,7 +1782,7 @@ void __attribute__ ((constructor)) audit_plugin_so_init(void)
|
||||
}
|
||||
#else
|
||||
extern struct st_mysql_plugin *mysql_mandatory_plugins[];
|
||||
void __attribute__ ((constructor)) audit_plugin_so_init(void)
|
||||
extern "C" void __attribute__ ((constructor)) audit_plugin_so_init(void)
|
||||
{
|
||||
|
||||
|
||||
|
||||
@@ -12,11 +12,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
#define unprotect(addr,len) (mprotect(addr,len,PROT_READ|PROT_WRITE|PROT_EXEC))
|
||||
#define protect(addr,len) (mprotect(addr,len,PROT_READ|PROT_EXEC))
|
||||
#define GETPAGESIZE() sysconf (_SC_PAGE_SIZE)
|
||||
|
||||
#define unprotect(addr,len) (mprotect(addr,len,PROT_READ|PROT_WRITE|PROT_EXEC))
|
||||
#define protect(addr,len) (mprotect(addr,len,PROT_READ|PROT_EXEC))
|
||||
#define GETPAGESIZE() sysconf (_SC_PAGE_SIZE)
|
||||
@@ -68,15 +63,6 @@ static void WriteJump(void *pAddress, ULONG_PTR JumpTo)
|
||||
*pCur++ = 0xE9; // jmp +imm32
|
||||
*((ULONG_PTR *)pCur) = JumpTo - (ULONG_PTR)pbJmpSrc;
|
||||
|
||||
/* old jump indirect requires 10 bytes (TOO big)
|
||||
*pCur = 0xff; // jmp [addr]
|
||||
*(++pCur) = 0x25;
|
||||
pCur++;
|
||||
*((DWORD *) pCur) = (DWORD)(((ULONG_PTR) pCur) + sizeof (DWORD));
|
||||
pCur += sizeof (DWORD);
|
||||
*((ULONG_PTR *)pCur) = JumpTo;
|
||||
*/
|
||||
|
||||
#else
|
||||
|
||||
*pCur = 0xff; // jmp [rip+addr]
|
||||
@@ -182,54 +168,7 @@ int hot_patch_function (void* targetFunction, void* newFunction, void * trampoli
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
/* OLD unused code
|
||||
int res = unprotect((void *)trampolinePage,PAGE_SIZE);
|
||||
if(res != 0)
|
||||
{
|
||||
sql_print_error("%s error un protecting trampoline page: 0x%x errno: %s. Aborting.",log_prefix, trampolinePage, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
//copy original code we are going to write over
|
||||
memcpy( trampolineFunction, targetFunction, TRAMPOLINE_COPY_LENGTH) ;
|
||||
//copy the jmp back to original code
|
||||
memset( (void *)((DATATYPE_ADDRESS)trampolineFunction + TRAMPOLINE_COPY_LENGTH), JMP_OPCODE, OPCODE_LENGTH ) ;
|
||||
//calculate where we want to jump back. The jump is relative.
|
||||
//We are jumping from: trampolineFunction + TRAMPOLINE_COPY_LENGTH + MIN_REQUIRED_FOR_DETOUR
|
||||
//to: targetFunction + TRAMPOLINE_COPY_LENGTH
|
||||
//the diff is: targetFunction + TRAMPOLINE_COPY_LENGTH - (trampolineFunction + TRAMPOLINE_COPY_LENGTH + MIN_REQUIRED_FOR_DETOUR)
|
||||
//TRAMPOLINE_COPY_LENGTH can be removed from both sides to get:
|
||||
DATATYPE_ADDRESS jumpBackAddress = (DATATYPE_ADDRESS)targetFunction - ((DATATYPE_ADDRESS)trampolineFunction + MIN_REQUIRED_FOR_DETOUR);
|
||||
//copy the location to the trampolineFunction
|
||||
memcpy( (void *)((DATATYPE_ADDRESS) trampolineFunction + TRAMPOLINE_COPY_LENGTH + OPCODE_LENGTH), &jumpBackAddress, ADDRESS_LENGTH) ;
|
||||
//protect the page
|
||||
protect((void *)trampolinePage,PAGE_SIZE);
|
||||
|
||||
//now modify the code of the target function
|
||||
DATATYPE_ADDRESS targetPage = get_page_address(targetFunction);
|
||||
cond_info_print(info_print, "%s targetPage: 0x%x targetFunction: 0x%x",log_prefix, targetPage, targetFunction);
|
||||
|
||||
res = unprotect((void *)targetPage,PAGE_SIZE);
|
||||
if(res == 0)
|
||||
{
|
||||
cond_info_print(info_print, "%s unprotect res: %d",log_prefix, res);
|
||||
cond_info_print(info_print, "%s setting jump code: 0x%x length: %d at: 0x%x", log_prefix, JMP_OPCODE, OPCODE_LENGTH, targetFunction);
|
||||
memset(targetFunction, JMP_OPCODE, OPCODE_LENGTH) ;
|
||||
//calculate where we want to jump to. Jump is relative (see above jump calcluation)
|
||||
DATATYPE_ADDRESS jumpAddress = (DATATYPE_ADDRESS)newFunction - ((DATATYPE_ADDRESS)targetFunction + MIN_REQUIRED_FOR_DETOUR);
|
||||
DATATYPE_ADDRESS targetFuncJumpAddress = (DATATYPE_ADDRESS)targetFunction + OPCODE_LENGTH;
|
||||
cond_info_print(info_print, "%s setting jump address: 0x%x length: %d at: 0x%x", log_prefix, jumpAddress, ADDRESS_LENGTH, targetFuncJumpAddress);
|
||||
memcpy((void *)targetFuncJumpAddress, &jumpAddress, ADDRESS_LENGTH) ;
|
||||
res = protect((void *)targetPage,PAGE_SIZE);
|
||||
cond_info_print(info_print, "%s protect res: %d",log_prefix, res);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_print_error("%s error un protecting target function page: 0x%x errno: %s. Aborted.", log_prefix, targetPage, strerror(errno));
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -243,26 +182,15 @@ int hot_patch_function (void* targetFunction, void* newFunction, void * trampoli
|
||||
*/
|
||||
void remove_hot_patch_function (void* targetFunction, void * trampolineFunction, unsigned int trampolinesize, bool info_print, const char * log_prefix)
|
||||
{
|
||||
if(trampolinesize == 0)
|
||||
{
|
||||
//nothing todo. As hot patch was not set.
|
||||
return;
|
||||
}
|
||||
cond_info_print(info_print, "%s removing hot patching function: 0x%x",log_prefix, targetFunction);
|
||||
DATATYPE_ADDRESS targetPage = get_page_address(targetFunction);
|
||||
cond_info_print(info_print, "%s targetPage: 0x%x targetFunction: 0x%x",log_prefix, targetPage, targetFunction);
|
||||
|
||||
UnhookFunction ((ULONG_PTR) targetFunction, (ULONG_PTR)trampolineFunction,trampolinesize);
|
||||
return;
|
||||
|
||||
/** OLD unused code
|
||||
int res = unprotect((void *)targetPage,PAGE_SIZE);
|
||||
if(res == 0)
|
||||
{
|
||||
cond_info_print(info_print, "%s unprotect res: %d", log_prefix, res);
|
||||
cond_info_print(info_print, "%s copying org code from trampoline function: 0x%x length: %d to: 0x%x", log_prefix, trampolineFunction, TRAMPOLINE_COPY_LENGTH, targetFunction);
|
||||
memcpy(targetFunction, trampolineFunction, TRAMPOLINE_COPY_LENGTH) ;
|
||||
res = protect((void *)targetPage,PAGE_SIZE);
|
||||
cond_info_print(info_print, "%s protect res: %d",log_prefix, res);
|
||||
}
|
||||
else
|
||||
{
|
||||
cond_info_print(info_print, "%s ERROR un protecting page: 0x%x errno: %d", log_prefix, targetPage, errno);
|
||||
}
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user