Commit 919f40e4 authored by Alexey Botchkov's avatar Alexey Botchkov

Audit plugin v1.2.0.

parent 0d73bc1c
...@@ -85,6 +85,66 @@ create table sa_t1(id int); ...@@ -85,6 +85,66 @@ create table sa_t1(id int);
insert into sa_t1 values (1), (2); insert into sa_t1 values (1), (2);
drop table sa_t1; drop table sa_t1;
drop database sa_db; drop database sa_db;
create database sa_db;
use sa_db;
CREATE USER u1 IDENTIFIED BY 'pwd-123';
GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321";
SET PASSWORD FOR u1 = PASSWORD('pwd 098');
CREATE USER u3 IDENTIFIED BY '';
drop user u1, u2, u3;
set global server_audit_events='query_ddl';
create table t1(id int);
insert into t1 values (1), (2);
select * from t1;
id
1
2
select 2;
2
2
(select 2);
2
2
/*! select 2*/;
2
2
/*comment*/ select 2;
2
2
drop table t1;
set global server_audit_events='query_ddl,query_dml';
create table t1(id int);
insert into t1 values (1), (2);
select * from t1;
id
1
2
select 2;
2
2
drop table t1;
set global server_audit_events='query_dml';
create table t1(id int);
insert into t1 values (1), (2);
select * from t1;
id
1
2
select 2;
2
2
(select 2);
2
2
/*! select 2*/;
2
2
/*comment*/ select 2;
2
2
drop table t1;
set global server_audit_events='';
drop database sa_db;
set global server_audit_file_path='.'; set global server_audit_file_path='.';
show status like 'server_audit_current_log'; show status like 'server_audit_current_log';
Variable_name Value Variable_name Value
...@@ -176,19 +236,65 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proc, ...@@ -176,19 +236,65 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proc,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,event, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,event,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop database sa_db',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop database sa_db',0
TIME,HOSTNAME,root,localhost,ID,0,DISCONNECT,sa_db,,0 TIME,HOSTNAME,root,localhost,ID,0,DISCONNECT,sa_db,,0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_file_path=\'.\'',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'create database sa_db',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_file_path=\'.\'',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'use sa_db',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'show status like \'server_audit_current_log\'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_file_path=\'\'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_file_path=\'\'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'show status like \'server_audit_current_log\'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_file_path=\' \'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_file_path=\' \'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'show status like \'server_audit_current_log\'',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u1 IDENTIFIED BY *****',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_file_path=\'nonexisting_dir/\'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_file_path=\'nonexisting_dir/\'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'SHOW WARNINGS',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'GRANT ALL ON sa_db TO u2 IDENTIFIED BY *****',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'show status like \'server_audit_current_log\'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'show variables like \'server_audit%\'',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'SET PASSWORD FOR u1 = PASSWORD(*****)',0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u3 IDENTIFIED BY *****',0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop user u1, u2, u3',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'create table t1(id int)',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop table t1',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'create table t1(id int)',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'insert into t1 values (1), (2)',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select * from t1',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select 2',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop table t1',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'insert into t1 values (1), (2)',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select * from t1',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select 2',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'(select 2)',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'/*! select 2*/',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'/*comment*/ select 2',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_events=\'\'',0
TIME,HOSTNAME,root,localhost,ID,ID,READ,mysql,proc,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proc,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,event,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop database sa_db',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\'.\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\'.\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'show status like \'server_audit_current_log\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\'\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\'\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'show status like \'server_audit_current_log\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\' \'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\' \'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'show status like \'server_audit_current_log\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\'nonexisting_dir/\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\'nonexisting_dir/\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'SHOW WARNINGS',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'show status like \'server_audit_current_log\'',0
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'show variables like \'server_audit%\'',0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,plugin, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,plugin,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'uninstall plugin server_audit',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'uninstall plugin server_audit',0
...@@ -15,6 +15,7 @@ connect (con1,localhost,root,,mysql); ...@@ -15,6 +15,7 @@ connect (con1,localhost,root,,mysql);
connection default; connection default;
disconnect con1; disconnect con1;
--sleep 2 --sleep 2
--sleep 2
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
connect (con1,localhost,no_such_user,,mysql); connect (con1,localhost,no_such_user,,mysql);
...@@ -45,6 +46,8 @@ set global server_audit_events=''; ...@@ -45,6 +46,8 @@ set global server_audit_events='';
create database sa_db; create database sa_db;
connect (con1,localhost,root,,test); connect (con1,localhost,root,,test);
connection con1; connection con1;
--sleep 2
--sleep 2
create table t1 (id2 int); create table t1 (id2 int);
insert into t1 values (1), (2); insert into t1 values (1), (2);
select * from t1; select * from t1;
...@@ -56,8 +59,43 @@ drop table sa_t1; ...@@ -56,8 +59,43 @@ drop table sa_t1;
drop database sa_db; drop database sa_db;
connection default; connection default;
disconnect con1; disconnect con1;
--sleep 2 --sleep 2
--sleep 2
create database sa_db;
use sa_db;
CREATE USER u1 IDENTIFIED BY 'pwd-123';
GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321";
SET PASSWORD FOR u1 = PASSWORD('pwd 098');
CREATE USER u3 IDENTIFIED BY '';
drop user u1, u2, u3;
set global server_audit_events='query_ddl';
create table t1(id int);
insert into t1 values (1), (2);
select * from t1;
select 2;
(select 2);
/*! select 2*/;
/*comment*/ select 2;
drop table t1;
set global server_audit_events='query_ddl,query_dml';
create table t1(id int);
insert into t1 values (1), (2);
select * from t1;
select 2;
drop table t1;
set global server_audit_events='query_dml';
create table t1(id int);
insert into t1 values (1), (2);
select * from t1;
select 2;
(select 2);
/*! select 2*/;
/*comment*/ select 2;
drop table t1;
set global server_audit_events='';
drop database sa_db;
set global server_audit_file_path='.'; set global server_audit_file_path='.';
--replace_regex /\.[\\\/]/HOME_DIR\// --replace_regex /\.[\\\/]/HOME_DIR\//
show status like 'server_audit_current_log'; show status like 'server_audit_current_log';
......
...@@ -14,11 +14,10 @@ ...@@ -14,11 +14,10 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define PLUGIN_VERSION 0x101 #define PLUGIN_VERSION 0x102
#define PLUGIN_STR_VERSION "1.1.7" #define PLUGIN_STR_VERSION "1.2.0"
#include <my_config.h> #include <my_config.h>
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#include <string.h> #include <string.h>
...@@ -142,6 +141,10 @@ static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)), ...@@ -142,6 +141,10 @@ static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)),
#define flogger_mutex_lock(A) pthread_mutex_lock(&(A)->m_mutex) #define flogger_mutex_lock(A) pthread_mutex_lock(&(A)->m_mutex)
#define flogger_mutex_unlock(A) pthread_mutex_unlock(&(A)->m_mutex) #define flogger_mutex_unlock(A) pthread_mutex_unlock(&(A)->m_mutex)
static char **int_mysql_data_home;
static char *default_home= (char *)".";
#define mysql_data_home (*int_mysql_data_home)
#include "../../mysys/file_logger.c" #include "../../mysys/file_logger.c"
#endif /*!MARIADB_ONLY*/ #endif /*!MARIADB_ONLY*/
...@@ -165,6 +168,7 @@ static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)), ...@@ -165,6 +168,7 @@ static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)),
extern char server_version[]; extern char server_version[];
static const char *serv_ver= NULL; static const char *serv_ver= NULL;
static int started_mysql= 0; static int started_mysql= 0;
static int started_mariadb= 0;
static int maria_above_5= 0; static int maria_above_5= 0;
static char *incl_users, *excl_users, static char *incl_users, *excl_users,
*file_path, *syslog_info; *file_path, *syslog_info;
...@@ -222,11 +226,15 @@ static MYSQL_SYSVAR_STR(excl_users, excl_users, PLUGIN_VAR_RQCMDARG, ...@@ -222,11 +226,15 @@ static MYSQL_SYSVAR_STR(excl_users, excl_users, PLUGIN_VAR_RQCMDARG,
NULL, update_excl_users, NULL); NULL, update_excl_users, NULL);
/* bits in the event filter. */ /* bits in the event filter. */
#define EVENT_CONNECT 1 #define EVENT_CONNECT 1
#define EVENT_QUERY 2 #define EVENT_QUERY_ALL 2
#define EVENT_QUERY 26
#define EVENT_TABLE 4 #define EVENT_TABLE 4
#define EVENT_QUERY_DDL 8
#define EVENT_QUERY_DML 16
static const char *event_names[]= static const char *event_names[]=
{ {
"CONNECT", "QUERY", "TABLE", "CONNECT", "QUERY", "TABLE", "QUERY_DDL", "QUERY_DML",
NULL NULL
}; };
static TYPELIB events_typelib= static TYPELIB events_typelib=
...@@ -234,7 +242,7 @@ static TYPELIB events_typelib= ...@@ -234,7 +242,7 @@ static TYPELIB events_typelib=
array_elements(event_names) - 1, "", event_names, NULL array_elements(event_names) - 1, "", event_names, NULL
}; };
static MYSQL_SYSVAR_SET(events, events, PLUGIN_VAR_RQCMDARG, static MYSQL_SYSVAR_SET(events, events, PLUGIN_VAR_RQCMDARG,
"Specifies the set of events to monitor. Can be CONNECT, QUERY, TABLE.", "Specifies the set of events to monitor. Can be CONNECT, QUERY, TABLE, QUERY_DDL, QUERY_DML.",
NULL, NULL, 0, &events_typelib); NULL, NULL, 0, &events_typelib);
#define OUTPUT_SYSLOG 0 #define OUTPUT_SYSLOG 0
#define OUTPUT_FILE 1 #define OUTPUT_FILE 1
...@@ -526,6 +534,103 @@ static int user_hash_fill(HASH *h, char *users, ...@@ -526,6 +534,103 @@ static int user_hash_fill(HASH *h, char *users,
} }
enum sa_keywords
{
SQLCOM_NOTHING=0,
SQLCOM_DDL,
SQLCOM_DML,
SQLCOM_GRANT,
SQLCOM_CREATE_USER,
SQLCOM_CHANGE_MASTER,
SQLCOM_CREATE_SERVER,
SQLCOM_SET_OPTION,
SQLCOM_ALTER_SERVER,
SQLCOM_TRUNCATE,
SQLCOM_QUERY_ADMIN,
SQLCOM_DCL,
};
struct sa_keyword
{
int length;
const char *wd;
struct sa_keyword *next;
enum sa_keywords type;
};
struct sa_keyword xml_word= {3, "XML", 0, SQLCOM_NOTHING};
struct sa_keyword user_word= {4, "USER", 0, SQLCOM_NOTHING};
struct sa_keyword data_word= {4, "DATA", 0, SQLCOM_NOTHING};
struct sa_keyword server_word= {6, "SERVER", 0, SQLCOM_NOTHING};
struct sa_keyword master_word= {6, "MASTER", 0, SQLCOM_NOTHING};
struct sa_keyword password_word= {8, "PASSWORD", 0, SQLCOM_NOTHING};
struct sa_keyword function_word= {8, "FUNCTION", 0, SQLCOM_NOTHING};
struct sa_keyword statement_word= {9, "STATEMENT", 0, SQLCOM_NOTHING};
struct sa_keyword procedure_word= {9, "PROCEDURE", 0, SQLCOM_NOTHING};
struct sa_keyword keywords_to_skip[]=
{
{3, "SET", &statement_word, SQLCOM_QUERY_ADMIN},
{0, NULL, 0, SQLCOM_DDL}
};
struct sa_keyword not_ddl_keywords[]=
{
{4, "DROP", &function_word, SQLCOM_QUERY_ADMIN},
{4, "DROP", &procedure_word, SQLCOM_QUERY_ADMIN},
{4, "DROP", &user_word, SQLCOM_DCL},
{6, "CREATE", &user_word, SQLCOM_DCL},
{6, "CREATE", &function_word, SQLCOM_QUERY_ADMIN},
{6, "CREATE", &procedure_word, SQLCOM_QUERY_ADMIN},
{6, "RENAME", &user_word, SQLCOM_DCL},
{0, NULL, 0, SQLCOM_DDL}
};
struct sa_keyword ddl_keywords[]=
{
{4, "DROP", 0, SQLCOM_DDL},
{5, "ALTER", 0, SQLCOM_DDL},
{6, "CREATE", 0, SQLCOM_DDL},
{6, "RENAME", 0, SQLCOM_DDL},
{8, "TRUNCATE", 0, SQLCOM_DDL},
{0, NULL, 0, SQLCOM_DDL}
};
struct sa_keyword dml_keywords[]=
{
{2, "DO", 0, SQLCOM_DML},
{4, "CALL", 0, SQLCOM_DML},
{4, "LOAD", &data_word, SQLCOM_DML},
{4, "LOAD", &xml_word, SQLCOM_DML},
{6, "DELETE", 0, SQLCOM_DML},
{6, "INSERT", 0, SQLCOM_DML},
{6, "SELECT", 0, SQLCOM_DML},
{6, "UPDATE", 0, SQLCOM_DML},
{7, "HANDLER", 0, SQLCOM_DML},
{7, "REPLACE", 0, SQLCOM_DML},
{0, NULL, 0, SQLCOM_DML}
};
struct sa_keyword passwd_keywords[]=
{
{3, "SET", &password_word, SQLCOM_SET_OPTION},
{5, "ALTER", &server_word, SQLCOM_ALTER_SERVER},
{5, "GRANT", 0, SQLCOM_GRANT},
{6, "CREATE", &user_word, SQLCOM_CREATE_USER},
{6, "CREATE", &server_word, SQLCOM_CREATE_SERVER},
{6, "CHANGE", &master_word, SQLCOM_CHANGE_MASTER},
{0, NULL, 0, SQLCOM_NOTHING}
};
#define MAX_KEYWORD 9
static void error_header() static void error_header()
{ {
struct tm tm_time; struct tm tm_time;
...@@ -563,6 +668,7 @@ struct connection_info ...@@ -563,6 +668,7 @@ struct connection_info
int log_always; int log_always;
}; };
static HASH connection_hash; static HASH connection_hash;
...@@ -773,6 +879,21 @@ static struct connection_info * ...@@ -773,6 +879,21 @@ static struct connection_info *
#define SAFE_STRLEN(s) (s ? strlen(s) : 0) #define SAFE_STRLEN(s) (s ? strlen(s) : 0)
static int is_space(char c)
{
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
}
#define SKIP_SPACES(str) \
do { \
while (is_space(*str)) \
++str; \
} while(0)
static struct connection_info * static struct connection_info *
add_connection_initdb(const struct mysql_event_general *event) add_connection_initdb(const struct mysql_event_general *event)
{ {
...@@ -980,6 +1101,98 @@ static size_t escape_string(const char *str, unsigned int len, ...@@ -980,6 +1101,98 @@ static size_t escape_string(const char *str, unsigned int len,
} }
static size_t escape_string_hide_passwords(const char *str, unsigned int len,
char *result, size_t result_len,
const char *word1, size_t word1_len,
const char *word2, size_t word2_len,
int next_text_string)
{
const char *res_start= result;
const char *res_end= result + result_len - 2;
size_t d_len;
char b_char;
while (len)
{
if (len > word1_len + 1 && strncasecmp(str, word1, word1_len) == 0)
{
const char *next_s= str + word1_len;
size_t c;
if (next_text_string)
{
while (*next_s && *next_s != '\'' && *next_s != '"')
++next_s;
}
else
{
if (word2)
{
SKIP_SPACES(next_s);
if (len < (next_s - str) + word2_len + 1 ||
strncasecmp(next_s, word2, word2_len) != 0)
goto no_password;
next_s+= word2_len;
}
while (*next_s && *next_s != '\'' && *next_s != '"')
++next_s;
}
d_len= next_s - str;
if (result + d_len + 5 > res_end)
break;
for (c=0; c<d_len; c++)
result[c]= is_space(str[c]) ? ' ' : str[c];
memmove(result + d_len, "*****", 5);
result+= d_len + 5;
b_char= *(next_s++);
while (*next_s)
{
if (*next_s == b_char)
{
++next_s;
break;
}
if (*next_s == '\\')
{
if (next_s[1])
next_s++;
}
next_s++;
}
len-= next_s - str;
str= next_s;
continue;
}
no_password:
if (result >= res_end)
break;
if (*str == '\'')
{
*(result++)= '\\';
*(result++)= '\'';
}
else if (*str == '\\')
{
*(result++)= '\\';
*(result++)= '\\';
}
else if (is_space(*str))
*(result++)= ' ';
else
*(result++)= *str;
str++;
len--;
}
*result= 0;
return result - res_start;
}
static int do_log_user(const char *name) static int do_log_user(const char *name)
{ {
size_t len; size_t len;
...@@ -998,6 +1211,96 @@ static int do_log_user(const char *name) ...@@ -998,6 +1211,96 @@ static int do_log_user(const char *name)
} }
static int get_next_word(const char *query, char *word)
{
int len= 0;
char c;
while ((c= query[len]))
{
if (c >= 'a' && c <= 'z')
word[len]= 'A' + (c-'a');
else if (c >= 'A' && c <= 'Z')
word[len]= c;
else
break;
if (len++ == MAX_KEYWORD)
return 0;
}
word[len]= 0;
return len;
}
static int filter_query_type(const char *query, struct sa_keyword *kwd)
{
int qwe_in_list;
char fword[MAX_KEYWORD + 1], nword[MAX_KEYWORD + 1];
int len, nlen= 0;
const struct sa_keyword *l_keywords;
while (*query && (is_space(*query) || *query == '(' || *query == '/'))
{
/* comment handling */
if (*query == '/' && query[1] == '*')
{
if (query[2] == '!')
{
query+= 3;
while (*query >= '0' && *query <= '9')
query++;
continue;
}
query+= 2;
while (*query)
{
if (*query=='*' && query[1] == '/')
{
query+= 2;
break;
}
query++;
}
continue;
}
query++;
}
qwe_in_list= 0;
if (!(len= get_next_word(query, fword)))
goto not_in_list;
query+= len+1;
l_keywords= kwd;
while (l_keywords->length)
{
if (l_keywords->length == len && strncmp(l_keywords->wd, fword, len) == 0)
{
if (l_keywords->next)
{
if (nlen == 0)
{
while (*query && is_space(*query))
query++;
nlen= get_next_word(query, nword);
}
if (l_keywords->next->length != nlen ||
strncmp(l_keywords->next->wd, nword, nlen) != 0)
goto do_loop;
}
qwe_in_list= l_keywords->type;
break;
};
do_loop:
l_keywords++;
}
not_in_list:
return qwe_in_list;
}
static int log_statement_ex(const struct connection_info *cn, static int log_statement_ex(const struct connection_info *cn,
time_t ev_time, unsigned long thd_id, time_t ev_time, unsigned long thd_id,
const char *query, unsigned int query_len, const char *query, unsigned int query_len,
...@@ -1034,10 +1337,77 @@ static int log_statement_ex(const struct connection_info *cn, ...@@ -1034,10 +1337,77 @@ static int log_statement_ex(const struct connection_info *cn,
/* Can happen after the error in mysqld_prepare_stmt() */ /* Can happen after the error in mysqld_prepare_stmt() */
query= cn->query; query= cn->query;
query_len= cn->query_length; query_len= cn->query_length;
if (query == 0 || query_len == 0)
return 0;
} }
if (query && !(events & EVENT_QUERY_ALL) &&
(events & EVENT_QUERY))
{
const char *orig_query= query;
if (filter_query_type(query, keywords_to_skip))
{
char fword[MAX_KEYWORD + 1];
int len;
do
{
len= get_next_word(query, fword);
query+= len ? len : 1;
if (len == 3 && strncmp(fword, "FOR", 3) == 0)
break;
} while (*query);
if (*query == 0)
return 0;
}
if (events & EVENT_QUERY_DDL)
{
if (!filter_query_type(query, not_ddl_keywords) &&
filter_query_type(query, ddl_keywords))
goto do_log_query;
}
if (events & EVENT_QUERY_DML)
{
if (filter_query_type(query, dml_keywords))
goto do_log_query;
}
return 0;
do_log_query:
query= orig_query;
}
switch (filter_query_type(query, passwd_keywords))
{
case SQLCOM_GRANT:
case SQLCOM_CREATE_USER:
esc_q_len= escape_string_hide_passwords(query, query_len,
uh_buffer, sizeof(uh_buffer),
"IDENTIFIED", 10, "BY", 2, 0);
break;
case SQLCOM_CHANGE_MASTER:
esc_q_len= escape_string_hide_passwords(query, query_len,
uh_buffer, sizeof(uh_buffer),
"MASTER_PASSWORD", 15, "=", 1, 0);
break;
case SQLCOM_CREATE_SERVER:
case SQLCOM_ALTER_SERVER:
esc_q_len= escape_string_hide_passwords(query, query_len,
uh_buffer, sizeof(uh_buffer),
"PASSWORD", 8, NULL, 0, 0);
break;
case SQLCOM_SET_OPTION:
esc_q_len= escape_string_hide_passwords(query, query_len,
uh_buffer, sizeof(uh_buffer),
"=", 1, NULL, 0, 1);
break;
default:
esc_q_len= escape_string(query, query_len, esc_q_len= escape_string(query, query_len,
uh_buffer, sizeof(uh_buffer)); uh_buffer, sizeof(uh_buffer));
break;
}
csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize,
",\'%.*s\',%d", esc_q_len, uh_buffer, error_code); ",\'%.*s\',%d", esc_q_len, uh_buffer, error_code);
message[csize]= '\n'; message[csize]= '\n';
...@@ -1386,6 +1756,105 @@ static void auditing(MYSQL_THD thd __attribute__((unused)), ...@@ -1386,6 +1756,105 @@ static void auditing(MYSQL_THD thd __attribute__((unused)),
} }
#ifdef DBUG_OFF
#ifdef __x86_64__
static const int cmd_off= 4200;
static const int db_off= 120;
static const int db_len_off= 128;
#else
static const int cmd_off= 2668;
static const int db_off= 60;
static const int db_len_off= 64;
#endif /*x86_64*/
#else
#ifdef __x86_64__
static const int cmd_off= 4432;
static const int db_off= 120;
static const int db_len_off= 128;
#else
static const int cmd_off= 2808;
static const int db_off= 64;
static const int db_len_off= 68;
#endif /*x86_64*/
#endif /*DBUG_OFF*/
struct mysql_event_general_v8
{
unsigned int event_class;
unsigned int event_subclass;
int general_error_code;
unsigned long general_thread_id;
const char *general_user;
unsigned int general_user_length;
const char *general_command;
unsigned int general_command_length;
const char *general_query;
unsigned int general_query_length;
struct charset_info_st *general_charset;
unsigned long long general_time;
unsigned long long general_rows;
};
static void auditing_v8(MYSQL_THD thd, struct mysql_event_general_v8 *ev_v8)
{
struct mysql_event_general event;
if (ev_v8->event_class != MYSQL_AUDIT_GENERAL_CLASS)
return;
event.event_subclass= ev_v8->event_subclass;
event.general_error_code= ev_v8->general_error_code;
event.general_thread_id= ev_v8->general_thread_id;
event.general_user= ev_v8->general_user;
event.general_user_length= ev_v8->general_user_length;
event.general_command= ev_v8->general_command;
event.general_command_length= ev_v8->general_command_length;
event.general_query= ev_v8->general_query;
event.general_query_length= ev_v8->general_query_length;
event.general_charset= ev_v8->general_charset;
event.general_time= ev_v8->general_time;
event.general_rows= ev_v8->general_rows;
event.database= 0;
event.database_length= 0;
if (event.general_query_length > 0)
{
event.event_subclass= MYSQL_AUDIT_GENERAL_STATUS;
event.general_command= "Query";
event.general_command_length= 5;
#ifdef __linux__
event.database= *(char **) (((char *) thd) + db_off);
event.database_length= *(size_t *) (((char *) thd) + db_len_off);
#endif /*__linux*/
}
#ifdef __linux__
else if (*((int *) (((char *)thd) + cmd_off)) == 2)
{
event.event_subclass= MYSQL_AUDIT_GENERAL_LOG;
event.general_command= "Init DB";
event.general_command_length= 7;
event.general_query= *(char **) (((char *) thd) + db_off);
event.general_query_length= *(size_t *) (((char *) thd) + db_len_off);
}
#endif /*__linux*/
auditing(thd, ev_v8->event_class, &event);
}
static void auditing_v13(MYSQL_THD thd, unsigned int *ev_v0)
{
struct mysql_event_general event= *(const struct mysql_event_general *) (ev_v0+1);
if (event.general_query_length > 0)
{
event.event_subclass= MYSQL_AUDIT_GENERAL_STATUS;
event.general_command= "Query";
event.general_command_length= 5;
}
auditing(thd, ev_v0[0], &event);
}
/* /*
As it's just too difficult to #include "sql_class.h", As it's just too difficult to #include "sql_class.h",
let's just copy the necessary part of the system_variables let's just copy the necessary part of the system_variables
...@@ -1461,15 +1930,19 @@ typedef struct loc_system_variables ...@@ -1461,15 +1930,19 @@ typedef struct loc_system_variables
ulong query_cache_type; ulong query_cache_type;
} LOC_SV; } LOC_SV;
static int server_audit_init(void *p __attribute__((unused))) static int server_audit_init(void *p __attribute__((unused)))
{ {
const void *my_hash_init_ptr; const void *my_hash_init_ptr;
if (!serv_ver)
{
#ifdef _WIN32 #ifdef _WIN32
serv_ver= (const char *) GetProcAddress(0, "server_version"); serv_ver= (const char *) GetProcAddress(0, "server_version");
#else #else
serv_ver= server_version; serv_ver= server_version;
#endif /*_WIN32*/ #endif /*_WIN32*/
}
my_hash_init_ptr= dlsym(RTLD_DEFAULT, "_my_hash_init"); my_hash_init_ptr= dlsym(RTLD_DEFAULT, "_my_hash_init");
if (!my_hash_init_ptr) if (!my_hash_init_ptr)
{ {
...@@ -1477,8 +1950,14 @@ static int server_audit_init(void *p __attribute__((unused))) ...@@ -1477,8 +1950,14 @@ static int server_audit_init(void *p __attribute__((unused)))
my_hash_init_ptr= dlsym(RTLD_DEFAULT, "my_hash_init2"); my_hash_init_ptr= dlsym(RTLD_DEFAULT, "my_hash_init2");
} }
if(!(int_mysql_data_home= dlsym(RTLD_DEFAULT, "mysql_data_home")))
{
if(!(int_mysql_data_home= dlsym(RTLD_DEFAULT, "?mysql_data_home@@3PADA")))
int_mysql_data_home= &default_home;
}
if (!serv_ver || !my_hash_init_ptr) if (!serv_ver || !my_hash_init_ptr)
return 0; return 1;
if (!started_mysql) if (!started_mysql)
{ {
...@@ -1489,7 +1968,6 @@ static int server_audit_init(void *p __attribute__((unused))) ...@@ -1489,7 +1968,6 @@ static int server_audit_init(void *p __attribute__((unused)))
} }
} }
if (gethostname(servhost, sizeof(servhost))) if (gethostname(servhost, sizeof(servhost)))
strcpy(servhost, "unknown"); strcpy(servhost, "unknown");
...@@ -1608,8 +2086,8 @@ mysql_declare_plugin(server_audit) ...@@ -1608,8 +2086,8 @@ mysql_declare_plugin(server_audit)
MYSQL_AUDIT_PLUGIN, MYSQL_AUDIT_PLUGIN,
&mysql_descriptor, &mysql_descriptor,
"SERVER_AUDIT", "SERVER_AUDIT",
" Alexey Botchkov (MariaDB)", " Alexey Botchkov (MariaDB Corporation)",
"Audit the server activity.", "Audit the server activity",
PLUGIN_LICENSE_GPL, PLUGIN_LICENSE_GPL,
server_audit_init_mysql, server_audit_init_mysql,
server_audit_deinit, server_audit_deinit,
...@@ -1636,8 +2114,8 @@ maria_declare_plugin(server_audit) ...@@ -1636,8 +2114,8 @@ maria_declare_plugin(server_audit)
MYSQL_AUDIT_PLUGIN, MYSQL_AUDIT_PLUGIN,
&maria_descriptor, &maria_descriptor,
"SERVER_AUDIT", "SERVER_AUDIT",
"Alexey Botchkov (MariaDB)", "Alexey Botchkov (MariaDB Corporation)",
"Audit the server activity.", "Audit the server activity",
PLUGIN_LICENSE_GPL, PLUGIN_LICENSE_GPL,
server_audit_init, server_audit_init,
server_audit_deinit, server_audit_deinit,
...@@ -1645,7 +2123,7 @@ maria_declare_plugin(server_audit) ...@@ -1645,7 +2123,7 @@ maria_declare_plugin(server_audit)
audit_status, audit_status,
vars, vars,
PLUGIN_STR_VERSION, PLUGIN_STR_VERSION,
MariaDB_PLUGIN_MATURITY_BETA MariaDB_PLUGIN_MATURITY_GAMMA
} }
maria_declare_plugin_end; maria_declare_plugin_end;
...@@ -1915,3 +2393,48 @@ static void update_syslog_ident(MYSQL_THD thd __attribute__((unused)), ...@@ -1915,3 +2393,48 @@ static void update_syslog_ident(MYSQL_THD thd __attribute__((unused)),
} }
#ifdef _WIN32
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason != DLL_PROCESS_ATTACH)
return 1;
serv_ver= (const char *) GetProcAddress(0, "server_version");
#else
void __attribute__ ((constructor)) audit_plugin_so_init(void)
{
serv_ver= server_version;
#endif /*_WIN32*/
if (!serv_ver)
goto exit;
started_mariadb= strstr(serv_ver, "MariaDB") != 0;
if (!started_mariadb)
{
if (serv_ver[0] == '5' && serv_ver[2] == '5')
{
int sc= serv_ver[4] - '0';
if (serv_ver[5] >= '0' && serv_ver[5] <= '9')
sc= sc * 10 + serv_ver[5] - '0';
if (sc <= 10)
{
mysql_descriptor.interface_version= 0x0200;
mysql_descriptor.event_notify= (void *) auditing_v8;
}
else if (sc < 14)
{
mysql_descriptor.interface_version= 0x0200;
mysql_descriptor.event_notify= (void *) auditing_v13;
}
}
}
exit:
#ifdef _WIN32
return 1;
#else
return;
#endif
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment