small fixes for command name loading

new readme with ref to github wiki
improve performance of command lookup.
Fix cmd type and object type in cached queries.
Support for MySQL 5.5.21 offsets
pull/8/merge v1.0.1
Guy Lichtman 2012-04-09 16:24:30 +03:00
parent 4d1f1a1ffb
commit 026fdbf505
7 changed files with 181 additions and 178 deletions

View File

@ -1,104 +1,52 @@
Audit Plugin
MySQL 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).
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 stand alone audit solution or configured to feed data to external monitoring tools.
==== INSTALLATION =====
Installation and Configuration
------------------------------
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).
Please check out our wiki on github for detailed installation and configuration instructions:
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';
https://github.com/mcafee/mysql-audit/wiki
===== CONFIGURATION =====
Reporting Bugs
------------------------------
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 report bugs to: https://github.com/mcafee/mysql-audit/issues
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.
To print MySQL Server version: log into MySQL and execute the command:
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'
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 =====
License
-------------------------------
Copyright (C) 2012 McAfee, Inc.
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
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.

View File

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

View File

@ -33,6 +33,7 @@ typedef struct _THDPRINTED {
const char * retrieve_command (THD * thd);
typedef size_t OFFSET;
#define MAX_COM_STATUS_VARS_RECORDS 512
/**
* The struct usd to hold offsets. We should have one per version.
@ -158,7 +159,7 @@ public:
return thd->query;
#endif
}
//virtual char * retrieve_command (THD * thd);
};

View File

@ -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
View 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: *;
};

View 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()
{
@ -363,6 +317,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 +351,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 +370,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 +402,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 +418,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 +433,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;

View File

@ -132,7 +132,8 @@ 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},
//DISTRIBUTION: tar.gz
//offsets for: /mysql/5.1.30/bin/mysqld (5.1.30)
@ -228,9 +229,9 @@ 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}
};
@ -332,7 +333,8 @@ 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},
//DISTRIBUTION: tar.gz
//offsets for: mysql/5.1.30/bin/mysqld (5.1.30)
@ -428,8 +430,9 @@ 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}
};
#endif
@ -453,7 +456,7 @@ static int delay_ms_val =0;
static char *delay_cmds_string = NULL;
static char delay_cmds_array [SQLCOM_END + 2][MAX_COMMAND_CHAR_NUMBERS];
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.
*/
@ -477,7 +480,7 @@ static int trampoline_check_user(THD *thd, enum enum_server_command command, con
}
static unsigned int trampoline_check_user_size =0;
bool trampoline_acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len){
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.
}
@ -552,7 +555,7 @@ static int trampoline_send_result_to_client(Query_cache *pthis, THD *thd, char
}
#if MYSQL_VERSION_ID > 50505
bool trampoline_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
static bool trampoline_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
Prelocking_strategy *prelocking_strategy)
{
TRAMPOLINE_NOP_DEF;
@ -1090,6 +1093,74 @@ 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);
}
/*
Initialize the daemon plugin installation.
@ -1116,6 +1187,7 @@ static int audit_plugin_init(void *p)
{
DBUG_RETURN(1);
}
//setup audit handlers (initially disabled)
int res = json_file_handler.init(&json_formatter);
if (res != 0)
@ -1276,7 +1348,10 @@ 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);
}
DBUG_RETURN(0);
}
@ -1485,7 +1560,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 +1578,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)
{