mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-260 auditing table accesses
This commit is contained in:
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#define MYSQL_AUDIT_CLASS_MASK_SIZE 1
|
#define MYSQL_AUDIT_CLASS_MASK_SIZE 1
|
||||||
|
|
||||||
#define MYSQL_AUDIT_INTERFACE_VERSION 0x0300
|
#define MYSQL_AUDIT_INTERFACE_VERSION 0x0301
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
@ -97,6 +97,50 @@ struct mysql_event_connection
|
|||||||
unsigned int database_length;
|
unsigned int database_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
AUDIT CLASS : TABLE
|
||||||
|
|
||||||
|
LOCK occurs when a connection "locks" (this does not necessarily mean a table
|
||||||
|
lock and also happens for row-locking engines) the table at the beginning of
|
||||||
|
a statement. This event is generated at the beginning of every statement for
|
||||||
|
every affected table, unless there's a LOCK TABLES statement in effect (in
|
||||||
|
which case it is generated once for LOCK TABLES and then is suppressed until
|
||||||
|
the tables are unlocked).
|
||||||
|
|
||||||
|
CREATE/DROP/RENAME occur when a table is created, dropped, or renamed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MYSQL_AUDIT_TABLE_CLASS 15
|
||||||
|
#define MYSQL_AUDIT_TABLE_CLASSMASK (1 << MYSQL_AUDIT_TABLE_CLASS)
|
||||||
|
#define MYSQL_AUDIT_TABLE_LOCK 0
|
||||||
|
#define MYSQL_AUDIT_TABLE_CREATE 1
|
||||||
|
#define MYSQL_AUDIT_TABLE_DROP 2
|
||||||
|
#define MYSQL_AUDIT_TABLE_RENAME 3
|
||||||
|
#define MYSQL_AUDIT_TABLE_ALTER 4
|
||||||
|
|
||||||
|
struct mysql_event_table
|
||||||
|
{
|
||||||
|
unsigned int event_subclass;
|
||||||
|
unsigned long thread_id;
|
||||||
|
const char *user;
|
||||||
|
const char *priv_user;
|
||||||
|
const char *priv_host;
|
||||||
|
const char *external_user;
|
||||||
|
const char *proxy_user;
|
||||||
|
const char *host;
|
||||||
|
const char *ip;
|
||||||
|
const char *database;
|
||||||
|
unsigned int database_length;
|
||||||
|
const char *table;
|
||||||
|
unsigned int table_length;
|
||||||
|
/* for MYSQL_AUDIT_TABLE_LOCK, true if read-only, false if read/write */
|
||||||
|
int read_only;
|
||||||
|
/* for MYSQL_AUDIT_TABLE_RENAME */
|
||||||
|
const char *new_database;
|
||||||
|
unsigned int new_database_length;
|
||||||
|
const char *new_table;
|
||||||
|
unsigned int new_table_length;
|
||||||
|
};
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Here we define the descriptor structure, that is referred from
|
Here we define the descriptor structure, that is referred from
|
||||||
|
@ -279,6 +279,27 @@ struct mysql_event_connection
|
|||||||
const char *database;
|
const char *database;
|
||||||
unsigned int database_length;
|
unsigned int database_length;
|
||||||
};
|
};
|
||||||
|
struct mysql_event_table
|
||||||
|
{
|
||||||
|
unsigned int event_subclass;
|
||||||
|
unsigned long thread_id;
|
||||||
|
const char *user;
|
||||||
|
const char *priv_user;
|
||||||
|
const char *priv_host;
|
||||||
|
const char *external_user;
|
||||||
|
const char *proxy_user;
|
||||||
|
const char *host;
|
||||||
|
const char *ip;
|
||||||
|
const char *database;
|
||||||
|
unsigned int database_length;
|
||||||
|
const char *table;
|
||||||
|
unsigned int table_length;
|
||||||
|
int read_only;
|
||||||
|
const char *new_database;
|
||||||
|
unsigned int new_database_length;
|
||||||
|
const char *new_table;
|
||||||
|
unsigned int new_table_length;
|
||||||
|
};
|
||||||
struct st_mysql_audit
|
struct st_mysql_audit
|
||||||
{
|
{
|
||||||
int interface_version;
|
int interface_version;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
set @old_global_general_log=@@global.general_log;
|
set @old_global_general_log=@@global.general_log;
|
||||||
set global general_log=OFF;
|
set global general_log=OFF;
|
||||||
|
grant select on *.* to testuser@localhost;
|
||||||
install plugin audit_null soname 'adt_null';
|
install plugin audit_null soname 'adt_null';
|
||||||
select 1;
|
select 1;
|
||||||
1
|
1
|
||||||
@ -18,12 +19,82 @@ concat("test1", x)
|
|||||||
test1-12
|
test1-12
|
||||||
show status like 'audit_null%';
|
show status like 'audit_null%';
|
||||||
Variable_name Value
|
Variable_name Value
|
||||||
Audit_null_called 19
|
Audit_null_called 21
|
||||||
Audit_null_general_error 1
|
Audit_null_general_error 1
|
||||||
Audit_null_general_log 7
|
Audit_null_general_log 7
|
||||||
Audit_null_general_result 5
|
Audit_null_general_result 5
|
||||||
|
create table t1 (a int);
|
||||||
|
insert t1 values (1), (2);
|
||||||
|
select * from t1;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
rename table t1 to t2;
|
||||||
|
alter table t2 add column b int;
|
||||||
|
create definer=testuser@localhost view v1 as select t2.a+1, t2_copy.a+2 from t2, t2 as t2_copy;
|
||||||
|
select * from v1;
|
||||||
|
t2.a+1 t2_copy.a+2
|
||||||
|
2 3
|
||||||
|
3 3
|
||||||
|
2 4
|
||||||
|
3 4
|
||||||
|
drop view v1;
|
||||||
|
create temporary table t2 (a date);
|
||||||
|
insert t2 values ('2020-10-09');
|
||||||
|
select * from t2;
|
||||||
|
a
|
||||||
|
2020-10-09
|
||||||
|
drop table t2;
|
||||||
|
explain select distinct * from t2;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using temporary
|
||||||
|
select distinct * from t2;
|
||||||
|
a b
|
||||||
|
1 NULL
|
||||||
|
2 NULL
|
||||||
|
drop table t2;
|
||||||
uninstall plugin audit_null;
|
uninstall plugin audit_null;
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1620 Plugin is busy and will be uninstalled on shutdown
|
Warning 1620 Plugin is busy and will be uninstalled on shutdown
|
||||||
drop procedure au1;
|
drop procedure au1;
|
||||||
|
drop user testuser@localhost;
|
||||||
set global general_log=@old_global_general_log;
|
set global general_log=@old_global_general_log;
|
||||||
|
root[root] @ localhost [] >> select 1
|
||||||
|
root[root] @ localhost [] >> select foobar
|
||||||
|
root[root] @ localhost [] >> show status like 'audit_null%'
|
||||||
|
root[root] @ localhost [] >> create procedure au1(x char(16)) select concat("test1", x)
|
||||||
|
root[root] @ localhost [] mysql.proc : write
|
||||||
|
root[root] @ localhost [] >> call au1("-12")
|
||||||
|
root[root] @ localhost [] mysql.proc : read
|
||||||
|
root[root] @ localhost [] >> select concat("test1", NAME_CONST('x',_latin1'-12' COLLATE 'latin1_swedish_ci'))
|
||||||
|
root[root] @ localhost [] >> show status like 'audit_null%'
|
||||||
|
root[root] @ localhost [] >> create table t1 (a int)
|
||||||
|
root[root] @ localhost [] test.t1 : create
|
||||||
|
root[root] @ localhost [] >> insert t1 values (1), (2)
|
||||||
|
root[root] @ localhost [] test.t1 : write
|
||||||
|
root[root] @ localhost [] >> select * from t1
|
||||||
|
root[root] @ localhost [] test.t1 : read
|
||||||
|
root[root] @ localhost [] >> rename table t1 to t2
|
||||||
|
root[root] @ localhost [] test.t1 : rename to test.t2
|
||||||
|
root[root] @ localhost [] >> alter table t2 add column b int
|
||||||
|
root[root] @ localhost [] test.t2 : alter
|
||||||
|
root[root] @ localhost [] test.t2 : read
|
||||||
|
root[root] @ localhost [] >> create definer=testuser@localhost view v1 as select t2.a+1, t2_copy.a+2 from t2, t2 as t2_copy
|
||||||
|
root[root] @ localhost [] test.t2 : read
|
||||||
|
root[root] @ localhost [] test.t2 : read
|
||||||
|
root[root] @ localhost [] >> select * from v1
|
||||||
|
root[root] @ localhost [] test.t2 : read
|
||||||
|
root[root] @ localhost [] test.t2 : read
|
||||||
|
root[root] @ localhost [] >> drop view v1
|
||||||
|
root[root] @ localhost [] >> create temporary table t2 (a date)
|
||||||
|
root[root] @ localhost [] >> insert t2 values ('2020-10-09')
|
||||||
|
root[root] @ localhost [] >> select * from t2
|
||||||
|
root[root] @ localhost [] >> drop table t2
|
||||||
|
root[root] @ localhost [] >> explain select distinct * from t2
|
||||||
|
root[root] @ localhost [] test.t2 : read
|
||||||
|
root[root] @ localhost [] >> select distinct * from t2
|
||||||
|
root[root] @ localhost [] test.t2 : read
|
||||||
|
root[root] @ localhost [] >> drop table t2
|
||||||
|
root[root] @ localhost [] test.t2 : drop
|
||||||
|
root[root] @ localhost [] >> uninstall plugin audit_null
|
||||||
|
root[root] @ localhost [] mysql.plugin : write
|
||||||
|
@ -8,6 +8,8 @@ if (!$ADT_NULL_SO) {
|
|||||||
set @old_global_general_log=@@global.general_log;
|
set @old_global_general_log=@@global.general_log;
|
||||||
set global general_log=OFF;
|
set global general_log=OFF;
|
||||||
|
|
||||||
|
grant select on *.* to testuser@localhost;
|
||||||
|
|
||||||
--disable_ps_protocol
|
--disable_ps_protocol
|
||||||
install plugin audit_null soname 'adt_null';
|
install plugin audit_null soname 'adt_null';
|
||||||
|
|
||||||
@ -22,9 +24,36 @@ call au1("-12");
|
|||||||
|
|
||||||
show status like 'audit_null%';
|
show status like 'audit_null%';
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
insert t1 values (1), (2);
|
||||||
|
select * from t1;
|
||||||
|
rename table t1 to t2;
|
||||||
|
alter table t2 add column b int;
|
||||||
|
|
||||||
|
create definer=testuser@localhost view v1 as select t2.a+1, t2_copy.a+2 from t2, t2 as t2_copy;
|
||||||
|
select * from v1;
|
||||||
|
drop view v1;
|
||||||
|
|
||||||
|
# temp table generates no audit events
|
||||||
|
create temporary table t2 (a date);
|
||||||
|
insert t2 values ('2020-10-09');
|
||||||
|
select * from t2;
|
||||||
|
drop table t2;
|
||||||
|
|
||||||
|
# internal temp table generates no audit events
|
||||||
|
explain select distinct * from t2;
|
||||||
|
select distinct * from t2;
|
||||||
|
|
||||||
|
drop table t2;
|
||||||
|
|
||||||
uninstall plugin audit_null;
|
uninstall plugin audit_null;
|
||||||
--enable_ps_protocol
|
--enable_ps_protocol
|
||||||
|
|
||||||
drop procedure au1;
|
drop procedure au1;
|
||||||
|
drop user testuser@localhost;
|
||||||
set global general_log=@old_global_general_log;
|
set global general_log=@old_global_general_log;
|
||||||
|
|
||||||
|
let $MYSQLD_DATADIR= `SELECT @@datadir`;
|
||||||
|
--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ /#sql2-[-0-9a-f_]*/#sql2-temporary/
|
||||||
|
cat_file $MYSQLD_DATADIR/audit_null_tables.log;
|
||||||
|
|
||||||
|
@ -22,11 +22,12 @@
|
|||||||
#define __attribute__(A)
|
#define __attribute__(A)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static volatile int number_of_calls; /* for SHOW STATUS, see below */
|
static volatile int ncalls; /* for SHOW STATUS, see below */
|
||||||
static volatile int number_of_calls_general_log;
|
static volatile int ncalls_general_log;
|
||||||
static volatile int number_of_calls_general_error;
|
static volatile int ncalls_general_error;
|
||||||
static volatile int number_of_calls_general_result;
|
static volatile int ncalls_general_result;
|
||||||
|
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialize the plugin at server start or plugin installation.
|
Initialize the plugin at server start or plugin installation.
|
||||||
@ -44,11 +45,16 @@ static volatile int number_of_calls_general_result;
|
|||||||
|
|
||||||
static int audit_null_plugin_init(void *arg __attribute__((unused)))
|
static int audit_null_plugin_init(void *arg __attribute__((unused)))
|
||||||
{
|
{
|
||||||
number_of_calls= 0;
|
ncalls= 0;
|
||||||
number_of_calls_general_log= 0;
|
ncalls_general_log= 0;
|
||||||
number_of_calls_general_error= 0;
|
ncalls_general_error= 0;
|
||||||
number_of_calls_general_result= 0;
|
ncalls_general_result= 0;
|
||||||
return(0);
|
|
||||||
|
f = fopen("audit_null_tables.log", "w");
|
||||||
|
if (!f)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -67,7 +73,8 @@ static int audit_null_plugin_init(void *arg __attribute__((unused)))
|
|||||||
|
|
||||||
static int audit_null_plugin_deinit(void *arg __attribute__((unused)))
|
static int audit_null_plugin_deinit(void *arg __attribute__((unused)))
|
||||||
{
|
{
|
||||||
return(0);
|
fclose(f);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -86,7 +93,7 @@ static void audit_null_notify(MYSQL_THD thd __attribute__((unused)),
|
|||||||
const void *event)
|
const void *event)
|
||||||
{
|
{
|
||||||
/* prone to races, oh well */
|
/* prone to races, oh well */
|
||||||
number_of_calls++;
|
ncalls++;
|
||||||
if (event_class == MYSQL_AUDIT_GENERAL_CLASS)
|
if (event_class == MYSQL_AUDIT_GENERAL_CLASS)
|
||||||
{
|
{
|
||||||
const struct mysql_event_general *event_general=
|
const struct mysql_event_general *event_general=
|
||||||
@ -94,18 +101,56 @@ static void audit_null_notify(MYSQL_THD thd __attribute__((unused)),
|
|||||||
switch (event_general->event_subclass)
|
switch (event_general->event_subclass)
|
||||||
{
|
{
|
||||||
case MYSQL_AUDIT_GENERAL_LOG:
|
case MYSQL_AUDIT_GENERAL_LOG:
|
||||||
number_of_calls_general_log++;
|
ncalls_general_log++;
|
||||||
|
fprintf(f, "%s\t>> %s\n", event_general->general_user,
|
||||||
|
event_general->general_query);
|
||||||
break;
|
break;
|
||||||
case MYSQL_AUDIT_GENERAL_ERROR:
|
case MYSQL_AUDIT_GENERAL_ERROR:
|
||||||
number_of_calls_general_error++;
|
ncalls_general_error++;
|
||||||
break;
|
break;
|
||||||
case MYSQL_AUDIT_GENERAL_RESULT:
|
case MYSQL_AUDIT_GENERAL_RESULT:
|
||||||
number_of_calls_general_result++;
|
ncalls_general_result++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
if (event_class == MYSQL_AUDIT_TABLE_CLASS)
|
||||||
|
{
|
||||||
|
const struct mysql_event_table *event_table=
|
||||||
|
(const struct mysql_event_table *) event;
|
||||||
|
const char *ip= event_table->ip ? event_table->ip : "";
|
||||||
|
const char *op= 0;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
switch (event_table->event_subclass)
|
||||||
|
{
|
||||||
|
case MYSQL_AUDIT_TABLE_LOCK:
|
||||||
|
op= event_table->read_only ? "read" : "write";
|
||||||
|
break;
|
||||||
|
case MYSQL_AUDIT_TABLE_CREATE:
|
||||||
|
op= "create";
|
||||||
|
break;
|
||||||
|
case MYSQL_AUDIT_TABLE_DROP:
|
||||||
|
op= "drop";
|
||||||
|
break;
|
||||||
|
case MYSQL_AUDIT_TABLE_ALTER:
|
||||||
|
op= "alter";
|
||||||
|
break;
|
||||||
|
case MYSQL_AUDIT_TABLE_RENAME:
|
||||||
|
snprintf(buf, sizeof(buf), "rename to %s.%s",
|
||||||
|
event_table->new_database, event_table->new_table);
|
||||||
|
buf[sizeof(buf)-1]= 0;
|
||||||
|
op= buf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(f, "%s[%s] @ %s [%s]\t%s.%s : %s\n",
|
||||||
|
event_table->priv_user, event_table->user,
|
||||||
|
event_table->host, ip,
|
||||||
|
event_table->database, event_table->table, op);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -115,10 +160,8 @@ static void audit_null_notify(MYSQL_THD thd __attribute__((unused)),
|
|||||||
|
|
||||||
static struct st_mysql_audit audit_null_descriptor=
|
static struct st_mysql_audit audit_null_descriptor=
|
||||||
{
|
{
|
||||||
MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */
|
MYSQL_AUDIT_INTERFACE_VERSION, NULL, audit_null_notify,
|
||||||
NULL, /* release_thd function */
|
{ MYSQL_AUDIT_GENERAL_CLASSMASK | MYSQL_AUDIT_TABLE_CLASSMASK }
|
||||||
audit_null_notify, /* notify function */
|
|
||||||
{ (unsigned long) MYSQL_AUDIT_GENERAL_CLASSMASK } /* class mask */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -127,12 +170,10 @@ static struct st_mysql_audit audit_null_descriptor=
|
|||||||
|
|
||||||
static struct st_mysql_show_var simple_status[]=
|
static struct st_mysql_show_var simple_status[]=
|
||||||
{
|
{
|
||||||
{ "Audit_null_called", (char *) &number_of_calls, SHOW_INT },
|
{ "Audit_null_called", (char *) &ncalls, SHOW_INT },
|
||||||
{ "Audit_null_general_log", (char *) &number_of_calls_general_log, SHOW_INT },
|
{ "Audit_null_general_log", (char *) &ncalls_general_log, SHOW_INT },
|
||||||
{ "Audit_null_general_error", (char *) &number_of_calls_general_error,
|
{ "Audit_null_general_error", (char *) &ncalls_general_error, SHOW_INT },
|
||||||
SHOW_INT },
|
{ "Audit_null_general_result", (char *) &ncalls_general_result, SHOW_INT },
|
||||||
{ "Audit_null_general_result", (char *) &number_of_calls_general_result,
|
|
||||||
SHOW_INT },
|
|
||||||
{ 0, 0, 0}
|
{ 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "myisam.h"
|
#include "myisam.h"
|
||||||
#include "probes_mysql.h"
|
#include "probes_mysql.h"
|
||||||
#include "debug_sync.h" // DEBUG_SYNC
|
#include "debug_sync.h" // DEBUG_SYNC
|
||||||
|
#include "sql_audit.h"
|
||||||
|
|
||||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
#include "ha_partition.h"
|
#include "ha_partition.h"
|
||||||
@ -3689,7 +3690,6 @@ int
|
|||||||
handler::ha_delete_table(const char *name)
|
handler::ha_delete_table(const char *name)
|
||||||
{
|
{
|
||||||
mark_trx_read_write();
|
mark_trx_read_write();
|
||||||
|
|
||||||
return delete_table(name);
|
return delete_table(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3722,8 +3722,11 @@ int
|
|||||||
handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info)
|
handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info)
|
||||||
{
|
{
|
||||||
mark_trx_read_write();
|
mark_trx_read_write();
|
||||||
|
int error= create(name, form, info);
|
||||||
return create(name, form, info);
|
if (!error &&
|
||||||
|
!(info->options & (HA_LEX_CREATE_TMP_TABLE | HA_CREATE_TMP_ALTER)))
|
||||||
|
mysql_audit_create_table(form);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -5099,7 +5102,11 @@ int handler::ha_external_lock(THD *thd, int lock_type)
|
|||||||
int error= external_lock(thd, lock_type);
|
int error= external_lock(thd, lock_type);
|
||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
|
{
|
||||||
cached_table_flags= table_flags();
|
cached_table_flags= table_flags();
|
||||||
|
if (table_share->tmp_table == NO_TMP_TABLE)
|
||||||
|
mysql_audit_external_lock(thd, table_share, lock_type);
|
||||||
|
}
|
||||||
|
|
||||||
if (MYSQL_HANDLER_RDLOCK_DONE_ENABLED() ||
|
if (MYSQL_HANDLER_RDLOCK_DONE_ENABLED() ||
|
||||||
MYSQL_HANDLER_WRLOCK_DONE_ENABLED() ||
|
MYSQL_HANDLER_WRLOCK_DONE_ENABLED() ||
|
||||||
|
@ -318,6 +318,7 @@
|
|||||||
#define HA_LEX_CREATE_TMP_TABLE 1
|
#define HA_LEX_CREATE_TMP_TABLE 1
|
||||||
#define HA_LEX_CREATE_IF_NOT_EXISTS 2
|
#define HA_LEX_CREATE_IF_NOT_EXISTS 2
|
||||||
#define HA_LEX_CREATE_TABLE_LIKE 4
|
#define HA_LEX_CREATE_TABLE_LIKE 4
|
||||||
|
#define HA_CREATE_TMP_ALTER 8
|
||||||
#define HA_MAX_REC_LENGTH 65535
|
#define HA_MAX_REC_LENGTH 65535
|
||||||
|
|
||||||
/* Table caching type */
|
/* Table caching type */
|
||||||
|
@ -31,8 +31,7 @@ unsigned long mysql_global_audit_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
|
|||||||
|
|
||||||
static mysql_mutex_t LOCK_audit_mask;
|
static mysql_mutex_t LOCK_audit_mask;
|
||||||
|
|
||||||
static void event_class_dispatch(THD *thd, unsigned int event_class,
|
static void event_class_dispatch(THD *, unsigned int, const void *);
|
||||||
const void *event);
|
|
||||||
|
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
@ -111,9 +110,36 @@ static void connection_class_handler(THD *thd, uint event_subclass, va_list ap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void table_class_handler(THD *thd, uint event_subclass, va_list ap)
|
||||||
|
{
|
||||||
|
mysql_event_table event;
|
||||||
|
event.event_subclass= event_subclass;
|
||||||
|
event.read_only= va_arg(ap, int);
|
||||||
|
event.thread_id= va_arg(ap, unsigned long);
|
||||||
|
event.user= va_arg(ap, const char *);
|
||||||
|
event.priv_user= va_arg(ap, const char *);
|
||||||
|
event.priv_host= va_arg(ap, const char *);
|
||||||
|
event.external_user= va_arg(ap, const char *);
|
||||||
|
event.proxy_user= va_arg(ap, const char *);
|
||||||
|
event.host= va_arg(ap, const char *);
|
||||||
|
event.ip= va_arg(ap, const char *);
|
||||||
|
event.database= va_arg(ap, const char *);
|
||||||
|
event.database_length= va_arg(ap, unsigned int);
|
||||||
|
event.table= va_arg(ap, const char *);
|
||||||
|
event.table_length= va_arg(ap, unsigned int);
|
||||||
|
event.new_database= va_arg(ap, const char *);
|
||||||
|
event.new_database_length= va_arg(ap, unsigned int);
|
||||||
|
event.new_table= va_arg(ap, const char *);
|
||||||
|
event.new_table_length= va_arg(ap, unsigned int);
|
||||||
|
event_class_dispatch(thd, MYSQL_AUDIT_TABLE_CLASS, &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static audit_handler_t audit_handlers[] =
|
static audit_handler_t audit_handlers[] =
|
||||||
{
|
{
|
||||||
general_class_handler, connection_class_handler
|
general_class_handler, connection_class_handler,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0, /* placeholders */
|
||||||
|
table_class_handler
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint audit_handlers_count=
|
static const uint audit_handlers_count=
|
||||||
|
@ -43,17 +43,23 @@ static inline bool mysql_audit_general_enabled()
|
|||||||
return mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK;
|
return mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool mysql_audit_table_enabled()
|
||||||
|
{
|
||||||
|
return mysql_global_audit_mask[0] & MYSQL_AUDIT_TABLE_CLASSMASK;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static inline void mysql_audit_notify(THD *thd, uint event_class,
|
static inline void mysql_audit_notify(THD *thd, uint event_class,
|
||||||
uint event_subtype, ...) { }
|
uint event_subtype, ...) { }
|
||||||
#define mysql_audit_general_enabled() 0
|
#define mysql_audit_general_enabled() 0
|
||||||
|
#define mysql_audit_table_enabled() 0
|
||||||
#endif
|
#endif
|
||||||
extern void mysql_audit_release(THD *thd);
|
extern void mysql_audit_release(THD *thd);
|
||||||
|
|
||||||
#define MAX_USER_HOST_SIZE 512
|
#define MAX_USER_HOST_SIZE 512
|
||||||
static inline uint make_user_name(THD *thd, char *buf)
|
static inline uint make_user_name(THD *thd, char *buf)
|
||||||
{
|
{
|
||||||
Security_context *sctx= thd->security_ctx;
|
const Security_context *sctx= thd->security_ctx;
|
||||||
return strxnmov(buf, MAX_USER_HOST_SIZE,
|
return strxnmov(buf, MAX_USER_HOST_SIZE,
|
||||||
sctx->priv_user[0] ? sctx->priv_user : "", "[",
|
sctx->priv_user[0] ? sctx->priv_user : "", "[",
|
||||||
sctx->user ? sctx->user : "", "] @ ",
|
sctx->user ? sctx->user : "", "] @ ",
|
||||||
@ -174,4 +180,87 @@ void mysql_audit_general(THD *thd, uint event_subtype,
|
|||||||
(thd)->security_ctx->ip ? strlen((thd)->security_ctx->ip) : 0,\
|
(thd)->security_ctx->ip ? strlen((thd)->security_ctx->ip) : 0,\
|
||||||
(thd)->db, (thd)->db ? strlen((thd)->db) : 0)
|
(thd)->db, (thd)->db ? strlen((thd)->db) : 0)
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void mysql_audit_external_lock(THD *thd, TABLE_SHARE *share, int lock)
|
||||||
|
{
|
||||||
|
if (lock != F_UNLCK && mysql_audit_table_enabled())
|
||||||
|
{
|
||||||
|
const Security_context *sctx= thd->security_ctx;
|
||||||
|
mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_LOCK,
|
||||||
|
(int)(lock == F_RDLCK), (ulong)thd->thread_id,
|
||||||
|
sctx->user, sctx->priv_user, sctx->priv_host,
|
||||||
|
sctx->external_user, sctx->proxy_user, sctx->host,
|
||||||
|
sctx->ip, share->db.str, (uint)share->db.length,
|
||||||
|
share->table_name.str, (uint)share->table_name.length,
|
||||||
|
0,0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void mysql_audit_create_table(TABLE *table)
|
||||||
|
{
|
||||||
|
if (mysql_audit_table_enabled())
|
||||||
|
{
|
||||||
|
THD *thd= table->in_use;
|
||||||
|
const TABLE_SHARE *share= table->s;
|
||||||
|
const Security_context *sctx= thd->security_ctx;
|
||||||
|
mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_CREATE,
|
||||||
|
0, (ulong)thd->thread_id,
|
||||||
|
sctx->user, sctx->priv_user, sctx->priv_host,
|
||||||
|
sctx->external_user, sctx->proxy_user, sctx->host,
|
||||||
|
sctx->ip, share->db.str, (uint)share->db.length,
|
||||||
|
share->table_name.str, (uint)share->table_name.length,
|
||||||
|
0,0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void mysql_audit_drop_table(THD *thd, TABLE_LIST *table)
|
||||||
|
{
|
||||||
|
if (mysql_audit_table_enabled())
|
||||||
|
{
|
||||||
|
const Security_context *sctx= thd->security_ctx;
|
||||||
|
mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_DROP,
|
||||||
|
0, (ulong)thd->thread_id,
|
||||||
|
sctx->user, sctx->priv_user, sctx->priv_host,
|
||||||
|
sctx->external_user, sctx->proxy_user, sctx->host,
|
||||||
|
sctx->ip, table->db, (uint)table->db_length,
|
||||||
|
table->table_name, (uint)table->table_name_length,
|
||||||
|
0,0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void mysql_audit_rename_table(THD *thd, const char *old_db, const char *old_tb,
|
||||||
|
const char *new_db, const char *new_tb)
|
||||||
|
{
|
||||||
|
if (mysql_audit_table_enabled())
|
||||||
|
{
|
||||||
|
const Security_context *sctx= thd->security_ctx;
|
||||||
|
mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_RENAME,
|
||||||
|
0, (ulong)thd->thread_id,
|
||||||
|
sctx->user, sctx->priv_user, sctx->priv_host,
|
||||||
|
sctx->external_user, sctx->proxy_user, sctx->host,
|
||||||
|
sctx->ip,
|
||||||
|
old_db, (uint)strlen(old_db), old_tb, (uint)strlen(old_tb),
|
||||||
|
new_db, (uint)strlen(new_db), new_tb, (uint)strlen(new_tb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void mysql_audit_alter_table(THD *thd, TABLE_LIST *table)
|
||||||
|
{
|
||||||
|
if (mysql_audit_table_enabled())
|
||||||
|
{
|
||||||
|
const Security_context *sctx= thd->security_ctx;
|
||||||
|
mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_ALTER,
|
||||||
|
0, (ulong)thd->thread_id,
|
||||||
|
sctx->user, sctx->priv_user, sctx->priv_host,
|
||||||
|
sctx->external_user, sctx->proxy_user, sctx->host,
|
||||||
|
sctx->ip, table->db, (uint)table->db_length,
|
||||||
|
table->table_name, (uint)table->table_name_length,
|
||||||
|
0,0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SQL_AUDIT_INCLUDED */
|
#endif /* SQL_AUDIT_INCLUDED */
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include "sql_show.h"
|
#include "sql_show.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "datadict.h" // dd_frm_type()
|
#include "datadict.h" // dd_frm_type()
|
||||||
|
#include "sql_audit.h"
|
||||||
|
|
||||||
#ifdef __WIN__
|
#ifdef __WIN__
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
@ -2344,6 +2345,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||||||
wrong_tables.append(',');
|
wrong_tables.append(',');
|
||||||
wrong_tables.append(String(table->table_name,system_charset_info));
|
wrong_tables.append(String(table->table_name,system_charset_info));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mysql_audit_drop_table(thd, table);
|
||||||
|
}
|
||||||
DBUG_PRINT("table", ("table: 0x%lx s: 0x%lx", (long) table->table,
|
DBUG_PRINT("table", ("table: 0x%lx s: 0x%lx", (long) table->table,
|
||||||
table->table ? (long) table->table->s : (long) -1));
|
table->table ? (long) table->table->s : (long) -1));
|
||||||
|
|
||||||
@ -4728,6 +4733,8 @@ mysql_rename_table(handlerton *base, const char *old_db,
|
|||||||
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
|
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
|
||||||
else if (error)
|
else if (error)
|
||||||
my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
|
my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
|
||||||
|
else if (!(flags & FN_IS_TMP))
|
||||||
|
mysql_audit_rename_table(thd, old_db, old_name, new_db, new_name);
|
||||||
DBUG_RETURN(error != 0);
|
DBUG_RETURN(error != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6054,6 +6061,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||||||
|
|
||||||
mysql_ha_rm_tables(thd, table_list);
|
mysql_ha_rm_tables(thd, table_list);
|
||||||
|
|
||||||
|
mysql_audit_alter_table(thd, table_list);
|
||||||
|
|
||||||
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
|
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
|
||||||
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
|
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
|
||||||
/* Conditionally writes to binlog. */
|
/* Conditionally writes to binlog. */
|
||||||
@ -6716,6 +6725,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||||||
HA_OPTION_PACK_RECORD));
|
HA_OPTION_PACK_RECORD));
|
||||||
}
|
}
|
||||||
tmp_disable_binlog(thd);
|
tmp_disable_binlog(thd);
|
||||||
|
create_info->options|=HA_CREATE_TMP_ALTER;
|
||||||
error= mysql_create_table_no_lock(thd, new_db, tmp_name,
|
error= mysql_create_table_no_lock(thd, new_db, tmp_name,
|
||||||
create_info,
|
create_info,
|
||||||
alter_info,
|
alter_info,
|
||||||
|
Reference in New Issue
Block a user