diff options
Diffstat (limited to 'plugin')
-rw-r--r-- | plugin/server_audit/server_audit.c | 151 |
1 files changed, 115 insertions, 36 deletions
diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 96b1f6a09e9..84626c02f8c 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Alexey Botchkov and SkySQL Ab +/* Copyright (C) 2013, 2015, Alexey Botchkov and SkySQL Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,8 +14,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define PLUGIN_VERSION 0x102 -#define PLUGIN_STR_VERSION "1.2.0" +#define PLUGIN_VERSION 0x103 +#define PLUGIN_STR_VERSION "1.3.0" #include <my_config.h> #include <stdio.h> @@ -195,6 +195,9 @@ static char logging; static int internal_stop_logging= 0; static char incl_user_buffer[1024]; static char excl_user_buffer[1024]; +static char *big_buffer= NULL; +static size_t big_buffer_alloced= 0; +static unsigned int query_log_limit= 0; static char servhost[256]; static size_t servhost_len; @@ -237,14 +240,15 @@ static MYSQL_SYSVAR_STR(excl_users, excl_users, PLUGIN_VAR_RQCMDARG, /* bits in the event filter. */ #define EVENT_CONNECT 1 #define EVENT_QUERY_ALL 2 -#define EVENT_QUERY 26 +#define EVENT_QUERY 58 #define EVENT_TABLE 4 #define EVENT_QUERY_DDL 8 #define EVENT_QUERY_DML 16 +#define EVENT_QUERY_DCL 32 static const char *event_names[]= { - "CONNECT", "QUERY", "TABLE", "QUERY_DDL", "QUERY_DML", + "CONNECT", "QUERY", "TABLE", "QUERY_DDL", "QUERY_DML", "QUERY_DCL", NULL }; static TYPELIB events_typelib= @@ -289,6 +293,9 @@ static MYSQL_SYSVAR_STR(syslog_ident, syslog_ident, PLUGIN_VAR_RQCMDARG, static MYSQL_SYSVAR_STR(syslog_info, syslog_info, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, "The <info> string to be added to the SYSLOG record.", NULL, NULL, ""); +static MYSQL_SYSVAR_UINT(query_log_limit, query_log_limit, + PLUGIN_VAR_OPCMDARG, "Limit on the length of the query string in a record.", + NULL, NULL, 1024, 0, 0x7FFFFFFF, 1); static const char *syslog_facility_names[]= { @@ -368,6 +375,7 @@ static struct st_mysql_sys_var* vars[] = { MYSQL_SYSVAR(syslog_ident), MYSQL_SYSVAR(syslog_facility), MYSQL_SYSVAR(syslog_priority), + MYSQL_SYSVAR(query_log_limit), NULL }; @@ -392,9 +400,11 @@ static struct st_mysql_show_var audit_status[]= static PSI_mutex_key key_LOCK_operations; static PSI_mutex_info mutex_key_list[]= {{ &key_LOCK_operations, "SERVER_AUDIT_plugin::lock_operations", +{{ &key_LOCK_bigbuffer, "SERVER_AUDIT_plugin::lock_bigbuffer", PSI_FLAG_GLOBAL}}; #endif static mysql_mutex_t lock_operations; +static mysql_mutex_t lock_bigbuffer; /* The Percona server and partly MySQL don't support */ /* launching client errors in the 'update_variable' methods. */ @@ -627,6 +637,18 @@ struct sa_keyword dml_keywords[]= }; +struct sa_keyword dcl_keywords[]= +{ + {6, "CREATE", &user_word, SQLCOM_DCL}, + {4, "DROP", &user_word, SQLCOM_DCL}, + {6, "RENAME", &user_word, SQLCOM_DCL}, + {5, "GRANT", 0, SQLCOM_DCL}, + {6, "REVOKE", 0, SQLCOM_DCL}, + {3, "SET", &password_word, SQLCOM_DCL}, + {0, NULL, 0, SQLCOM_DDL} +}; + + struct sa_keyword passwd_keywords[]= { {3, "SET", &password_word, SQLCOM_SET_OPTION}, @@ -887,6 +909,7 @@ static struct connection_info * #define SAFE_STRLEN(s) (s ? strlen(s) : 0) +static char empty_str[1]= { 0 }; static int is_space(char c) @@ -1093,11 +1116,15 @@ static size_t escape_string(const char *str, unsigned int len, break; if (*str == '\'') { + if (result+1 >= res_end) + break; *(result++)= '\\'; *(result++)= '\''; } else if (*str == '\\') { + if (result+1 >= res_end) + break; *(result++)= '\\'; *(result++)= '\\'; } @@ -1182,11 +1209,15 @@ no_password: break; if (*str == '\'') { + if (result+1 >= res_end) + break; *(result++)= '\\'; *(result++)= '\''; } else if (*str == '\\') { + if (result+1 >= res_end) + break; *(result++)= '\\'; *(result++)= '\\'; } @@ -1316,12 +1347,16 @@ static int log_statement_ex(const struct connection_info *cn, const char *query, unsigned int query_len, int error_code, const char *type) { - size_t csize, esc_q_len; - char message[1024]; - char uh_buffer[768]; + size_t csize; + char message_loc[1024]; + char *message= message_loc; + size_t message_size= sizeof(message_loc); + char *uh_buffer; + size_t uh_buffer_size; const char *db; unsigned int db_length; long long query_id; + int result; if ((db= cn->db)) db_length= cn->db_length; @@ -1334,14 +1369,6 @@ static int log_statement_ex(const struct connection_info *cn, if (!(query_id= cn->query_id)) query_id= query_counter++; - csize= log_header(message, sizeof(message)-1, &ev_time, - servhost, servhost_len, - cn->user, cn->user_length,cn->host, cn->host_length, - cn->ip, cn->ip_length, thd_id, query_id, type); - - csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, - ",%.*s", db_length, db); - if (query == 0) { /* Can happen after the error in mysqld_prepare_stmt() */ @@ -1383,45 +1410,89 @@ static int log_statement_ex(const struct connection_info *cn, if (filter_query_type(query, dml_keywords)) goto do_log_query; } + if (events & EVENT_QUERY_DCL) + { + if (filter_query_type(query, dcl_keywords)) + goto do_log_query; + } return 0; do_log_query: query= orig_query; } + csize= log_header(message, message_size-1, &ev_time, + servhost, servhost_len, + cn->user, cn->user_length,cn->host, cn->host_length, + cn->ip, cn->ip_length, thd_id, query_id, type); + + csize+= my_snprintf(message+csize, message_size - 1 - csize, + ",%.*s,\'", db_length, db); + + if (query_log_limit > 0 && query_len > query_log_limit) + query_len= query_log_limit; + + if (query_len > (message_size - csize)/2) + { + flogger_mutex_lock(&lock_bigbuffer); + if (big_buffer_alloced < (query_len * 2 + csize)) + { + big_buffer_alloced= (query_len * 2 + csize + 4095) & ~4095L; + big_buffer= realloc(big_buffer, big_buffer_alloced); + if (big_buffer == NULL) + { + big_buffer_alloced= 0; + return 0; + } + } + + memcpy(big_buffer, message, csize); + message= big_buffer; + message_size= big_buffer_alloced; + } + + uh_buffer= message + csize; + uh_buffer_size= message_size - csize; + if (query_log_limit > 0 && uh_buffer_size > query_log_limit+2) + uh_buffer_size= query_log_limit+2; + 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), + csize+= escape_string_hide_passwords(query, query_len, + uh_buffer, uh_buffer_size, "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), + csize+= escape_string_hide_passwords(query, query_len, + uh_buffer, uh_buffer_size, "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), + csize+= escape_string_hide_passwords(query, query_len, + uh_buffer, uh_buffer_size, "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), + csize+= escape_string_hide_passwords(query, query_len, + uh_buffer, uh_buffer_size, "=", 1, NULL, 0, 1); break; default: - esc_q_len= escape_string(query, query_len, - uh_buffer, sizeof(uh_buffer)); + csize+= escape_string(query, query_len, + uh_buffer, uh_buffer_size); break; } - csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, - ",\'%.*s\',%d", esc_q_len, uh_buffer, error_code); + csize+= my_snprintf(message+csize, message_size - 1 - csize, + "\',%d", error_code); message[csize]= '\n'; - return write_log(message, csize + 1); + result= write_log(message, csize + 1); + if (message == big_buffer) + flogger_mutex_unlock(&lock_bigbuffer); + + return result; } @@ -1989,6 +2060,7 @@ static int server_audit_init(void *p __attribute__((unused))) PSI_server->register_mutex("server_audit", mutex_key_list, 1); #endif flogger_mutex_init(key_LOCK_operations, &lock_operations, MY_MUTEX_INIT_FAST); + flogger_mutex_init(key_LOCK_operations, &lock_bigbuffer, MY_MUTEX_INIT_FAST); my_hash_clear(&incl_user_hash); my_hash_clear(&excl_user_hash); @@ -2065,7 +2137,10 @@ static int server_audit_deinit(void *p __attribute__((unused))) logger_close(logfile); else if (output_type == OUTPUT_SYSLOG) closelog(); + + (void) free(big_buffer); flogger_mutex_destroy(&lock_operations); + flogger_mutex_destroy(&lock_bigbuffer); error_header(); fprintf(stderr, "STOPPED\n"); @@ -2166,10 +2241,12 @@ static void update_file_path(MYSQL_THD thd, struct st_mysql_sys_var *var __attribute__((unused)), void *var_ptr __attribute__((unused)), const void *save) { + char *new_name= (*(char **) save) ? *(char **) save : empty_str; + flogger_mutex_lock(&lock_operations); internal_stop_logging= 1; error_header(); - fprintf(stderr, "Log file name was changed to '%s'.\n", *(const char **) save); + fprintf(stderr, "Log file name was changed to '%s'.\n", new_name); if (logging) log_current_query(thd); @@ -2178,7 +2255,7 @@ static void update_file_path(MYSQL_THD thd, { char *sav_path= file_path; - file_path= *(char **) save; + file_path= new_name; internal_stop_logging= 1; stop_logging(); if (start_logging()) @@ -2198,7 +2275,7 @@ static void update_file_path(MYSQL_THD thd, internal_stop_logging= 0; } - strncpy(path_buffer, *(const char **) save, sizeof(path_buffer)); + strncpy(path_buffer, new_name, sizeof(path_buffer)); file_path= path_buffer; exit_func: internal_stop_logging= 0; @@ -2245,9 +2322,10 @@ static void update_incl_users(MYSQL_THD thd, struct st_mysql_sys_var *var __attribute__((unused)), void *var_ptr __attribute__((unused)), const void *save) { + char *new_users= (*(char **) save) ? *(char **) save : empty_str; flogger_mutex_lock(&lock_operations); mark_always_logged(thd); - strncpy(incl_user_buffer, *(const char **) save, sizeof(incl_user_buffer)); + strncpy(incl_user_buffer, new_users, sizeof(incl_user_buffer)); incl_users= incl_user_buffer; user_hash_fill(&incl_user_hash, incl_users, &excl_user_hash, 1); error_header(); @@ -2260,9 +2338,10 @@ static void update_excl_users(MYSQL_THD thd __attribute__((unused)), struct st_mysql_sys_var *var __attribute__((unused)), void *var_ptr __attribute__((unused)), const void *save) { + char *new_users= (*(char **) save) ? *(char **) save : empty_str; flogger_mutex_lock(&lock_operations); mark_always_logged(thd); - strncpy(excl_user_buffer, *(const char **) save, sizeof(excl_user_buffer)); + strncpy(excl_user_buffer, new_users, sizeof(excl_user_buffer)); excl_users= excl_user_buffer; user_hash_fill(&excl_user_hash, excl_users, &incl_user_hash, 0); error_header(); @@ -2387,8 +2466,8 @@ static void update_syslog_ident(MYSQL_THD thd __attribute__((unused)), struct st_mysql_sys_var *var __attribute__((unused)), void *var_ptr __attribute__((unused)), const void *save) { - strncpy(syslog_ident_buffer, *(const char **) save, - sizeof(syslog_ident_buffer)); + char *new_ident= (*(char **) save) ? *(char **) save : empty_str; + strncpy(syslog_ident_buffer, new_ident, sizeof(syslog_ident_buffer)); syslog_ident= syslog_ident_buffer; error_header(); fprintf(stderr, "SYSYLOG ident was changed to '%s'\n", syslog_ident); |