diff --git a/include/audit_handler.h b/include/audit_handler.h index 65ee0fd..7da9ec8 100644 --- a/include/audit_handler.h +++ b/include/audit_handler.h @@ -35,6 +35,9 @@ 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. */ diff --git a/src/audit_handler.cc b/src/audit_handler.cc index 06df311..1ae1ccb 100644 --- a/src/audit_handler.cc +++ b/src/audit_handler.cc @@ -29,259 +29,259 @@ * Will write into buff the date prefix for txt formatter. Return the number of bytes written * (not including null terminate). */ - static int log_date_prefix(char * buff, size_t buff_size) - { - struct tm tm_tmp; - time_t result= time(NULL); - localtime_r(&result, &tm_tmp); - //my_snprintf is limited regarding formatting but sufficient for this - return my_snprintf(buff, buff_size, "%02d%02d%02d %2d:%02d:%02d: ", - tm_tmp.tm_year % 100, - tm_tmp.tm_mon+1, - tm_tmp.tm_mday, - tm_tmp.tm_hour, - tm_tmp.tm_min, - tm_tmp.tm_sec); - } +static int log_date_prefix(char * buff, size_t buff_size) +{ + struct tm tm_tmp; + time_t result= time(NULL); + localtime_r(&result, &tm_tmp); + //my_snprintf is limited regarding formatting but sufficient for this + return my_snprintf(buff, buff_size, "%02d%02d%02d %2d:%02d:%02d: ", + tm_tmp.tm_year % 100, + tm_tmp.tm_mon+1, + tm_tmp.tm_mday, + tm_tmp.tm_hour, + tm_tmp.tm_min, + tm_tmp.tm_sec); +} - //utility macro to log also with a date as a prefix -#define log_with_date(f, ...) do{\ - struct tm tm_tmp;\ - time_t result= time(NULL);\ - localtime_r(&result, &tm_tmp);\ - fprintf(f, "%02d%02d%02d %2d:%02d:%02d: ",\ - tm_tmp.tm_year % 100,\ - tm_tmp.tm_mon+1,\ - tm_tmp.tm_mday,\ - tm_tmp.tm_hour,\ - tm_tmp.tm_min,\ - tm_tmp.tm_sec);\ - fprintf(f, __VA_ARGS__);\ - }while(0) +//utility macro to log also with a date as a prefix +#define log_with_date(f, ...) do{ \ + struct tm tm_tmp; \ + time_t result= time(NULL); \ + localtime_r(&result, &tm_tmp); \ + fprintf(f, "%02d%02d%02d %2d:%02d:%02d: ", \ + tm_tmp.tm_year % 100, \ + tm_tmp.tm_mon+1, \ + tm_tmp.tm_mday, \ + tm_tmp.tm_hour, \ + tm_tmp.tm_min, \ + tm_tmp.tm_sec); \ + fprintf(f, __VA_ARGS__); \ + }while(0) - //initialize static stuff - ThdOffsets Audit_formatter::thd_offsets = { 0 }; - Audit_handler * Audit_handler::m_audit_handler_list[Audit_handler::MAX_AUDIT_HANDLERS_NUM]; - const char * Audit_json_formatter::DEF_MSG_DELIMITER = "\\n"; +//initialize static stuff +ThdOffsets Audit_formatter::thd_offsets = { 0 }; +Audit_handler * Audit_handler::m_audit_handler_list[Audit_handler::MAX_AUDIT_HANDLERS_NUM]; +const char * Audit_json_formatter::DEF_MSG_DELIMITER = "\\n"; #define C_STRING_WITH_LEN(X) ((char *) (X)), ((size_t) (sizeof(X) - 1)) - const char * Audit_formatter::retrive_object_type (TABLE_LIST *pObj) - { - if (pObj->view) - { - return "VIEW"; - } - return "TABLE"; - } +const char * Audit_formatter::retrive_object_type (TABLE_LIST *pObj) +{ + if (pObj->view) + { + return "VIEW"; + } + return "TABLE"; +} - void Audit_handler::stop_all() - { - for (int i = 0; i < MAX_AUDIT_HANDLERS_NUM; ++i) - { - if (m_audit_handler_list[i] != NULL) - { - m_audit_handler_list[i]->set_enable(false); - } - } - } +void Audit_handler::stop_all() +{ + for (int i = 0; i < MAX_AUDIT_HANDLERS_NUM; ++i) + { + if (m_audit_handler_list[i] != NULL) + { + m_audit_handler_list[i]->set_enable(false); + } + } +} - void Audit_handler::log_audit_all(ThdSesData *pThdData) - { - for (int i = 0; i < MAX_AUDIT_HANDLERS_NUM; ++i) - { - if (m_audit_handler_list[i] != NULL) - { - m_audit_handler_list[i]->log_audit(pThdData); - } - } - } +void Audit_handler::log_audit_all(ThdSesData *pThdData) +{ + for (int i = 0; i < MAX_AUDIT_HANDLERS_NUM; ++i) + { + if (m_audit_handler_list[i] != NULL) + { + m_audit_handler_list[i]->log_audit(pThdData); + } + } +} - void Audit_handler::set_enable(bool val) - { - lock_exclusive(); - if (m_enabled == val) //we are already enabled simply return - { - unlock(); - return; - } - m_enabled = val; - if (m_enabled) - { - //call the startup of the handler - handler_start(); - } - else - { - //call the cleanup of the handler - handler_stop(); - } - unlock(); - } +void Audit_handler::set_enable(bool val) +{ + lock_exclusive(); + if (m_enabled == val) //we are already enabled simply return + { + unlock(); + return; + } + m_enabled = val; + if (m_enabled) + { + //call the startup of the handler + handler_start(); + } + else + { + //call the cleanup of the handler + handler_stop(); + } + unlock(); +} - void Audit_handler::log_audit(ThdSesData *pThdData) - { - lock_shared(); - if (!m_enabled) - { - unlock(); - return; - } - //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); - unsigned long inst_thread_id = Audit_formatter::thd_inst_thread_id(pThdData->getTHD()); - unsigned long plug_thread_id = thd_get_thread_id(pThdData->getTHD()); - if (inst_thread_id != plug_thread_id) - { - if (m_print_offset_err) - { - m_print_offset_err = false; - sql_print_error( - "%s Thread id from thd_get_thread_id doesn't match calculated value from offset %lu <> %lu. Aborting!", - AUDIT_LOG_PREFIX, inst_thread_id, plug_thread_id); +void Audit_handler::log_audit(ThdSesData *pThdData) +{ + lock_shared(); + if (!m_enabled) + { + unlock(); + return; + } + //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); + unsigned long inst_thread_id = Audit_formatter::thd_inst_thread_id(pThdData->getTHD()); + unsigned long plug_thread_id = thd_get_thread_id(pThdData->getTHD()); + if (inst_thread_id != plug_thread_id) + { + if (m_print_offset_err) + { + m_print_offset_err = false; + sql_print_error( + "%s Thread id from thd_get_thread_id doesn't match calculated value from offset %lu <> %lu. Aborting!", + AUDIT_LOG_PREFIX, inst_thread_id, plug_thread_id); } } - else + else {//offsets are good - m_print_offset_err = true; //mark to print offset err to log incase we encounter in the future - handler_log_audit(pThdData); + m_print_offset_err = true; //mark to print offset err to log incase we encounter in the future + handler_log_audit(pThdData); } - unlock(); + unlock(); } ssize_t Audit_file_handler::write(const char * data, size_t size) { - return my_fwrite(m_log_file, (uchar *) data, size, MYF(0)); + return my_fwrite(m_log_file, (uchar *) data, size, MYF(0)); } void Audit_file_handler::handler_start() { - pthread_mutex_lock(&LOCK_io); - char format_name[FN_REFLEN]; - fn_format(format_name, m_filename, "", "", MY_UNPACK_FILENAME); - m_log_file = my_fopen(format_name, O_RDWR | O_APPEND, MYF(0)); - if (!m_log_file) + pthread_mutex_lock(&LOCK_io); + char format_name[FN_REFLEN]; + fn_format(format_name, m_filename, "", "", MY_UNPACK_FILENAME); + m_log_file = my_fopen(format_name, O_RDWR | O_APPEND, MYF(0)); + if (!m_log_file) { - sql_print_error( - "%s unable to create %s: %s. audit file handler disabled!!", - AUDIT_LOG_PREFIX, m_filename, strerror(errno)); - m_enabled = false; + sql_print_error( + "%s unable to create %s: %s. audit file handler disabled!!", + AUDIT_LOG_PREFIX, m_filename, strerror(errno)); + m_enabled = false; } - else + else { - ssize_t res = m_formatter->start_msg_format(this); - /* - sanity check of writing to the log. If we fail. We will print an erorr and disable this handler. - */ - if (res < 0 || fflush(m_log_file) != 0) + ssize_t res = m_formatter->start_msg_format(this); + /* + sanity check of writing to the log. If we fail. We will print an erorr and disable this handler. + */ + if (res < 0 || fflush(m_log_file) != 0) { - sql_print_error( - "%s unable to write to %s: %s. Disabling audit handler.", - AUDIT_LOG_PREFIX, m_log_file, strerror(errno)); - close_file(); - m_enabled = false; + sql_print_error( + "%s unable to write to %s: %s. Disabling audit handler.", + AUDIT_LOG_PREFIX, m_log_file, strerror(errno)); + close_file(); + m_enabled = false; } } - pthread_mutex_unlock(&LOCK_io); + pthread_mutex_unlock(&LOCK_io); } void Audit_file_handler::handler_stop() { - pthread_mutex_lock(&LOCK_io); - m_formatter->stop_msg_format(this); - close_file(); - pthread_mutex_unlock(&LOCK_io); + pthread_mutex_lock(&LOCK_io); + m_formatter->stop_msg_format(this); + close_file(); + pthread_mutex_unlock(&LOCK_io); } void Audit_file_handler::handler_log_audit(ThdSesData *pThdData) { - pthread_mutex_lock(&LOCK_io); - m_formatter->event_format(pThdData, this); - if (++m_sync_counter >= m_sync_period && m_sync_period) + pthread_mutex_lock(&LOCK_io); + m_formatter->event_format(pThdData, this); + if (++m_sync_counter >= m_sync_period && m_sync_period) { - m_sync_counter = 0; - //Note fflush() only flushes the user space buffers provided by the C library. - //To ensure that the data is physically stored on disk the kernel buffers must be flushed too, - //e.g. with sync(2) or fsync(2). - fflush(m_log_file); - int fd = fileno(m_log_file); - my_sync(fd, MYF(MY_WME)); + m_sync_counter = 0; + //Note fflush() only flushes the user space buffers provided by the C library. + //To ensure that the data is physically stored on disk the kernel buffers must be flushed too, + //e.g. with sync(2) or fsync(2). + fflush(m_log_file); + int fd = fileno(m_log_file); + my_sync(fd, MYF(MY_WME)); } - pthread_mutex_unlock(&LOCK_io); + pthread_mutex_unlock(&LOCK_io); } /////////////////// Audit_socket_handler ////////////////////////////////// ssize_t Audit_socket_handler::write(const char * data, size_t size) { - return vio_write(m_vio, (const uchar *) data, size); + return vio_write(m_vio, (const uchar *) data, size); } void Audit_socket_handler::handler_start() { - pthread_mutex_lock(&LOCK_io); - //open the socket - int sock = socket(AF_UNIX,SOCK_STREAM,0); - if (sock < 0) - { - sql_print_error( - "%s unable to create socket: %s. audit socket handler disabled!!", - AUDIT_LOG_PREFIX, strerror(errno)); - m_enabled = false; - pthread_mutex_unlock(&LOCK_io); - return; - } - - //connect the socket - m_vio= vio_new(sock, VIO_TYPE_SOCKET, VIO_LOCALHOST); - struct sockaddr_un UNIXaddr; - UNIXaddr.sun_family = AF_UNIX; - strmake(UNIXaddr.sun_path, m_sockname, sizeof(UNIXaddr.sun_path)-1); - if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr), - m_connect_timeout)) + pthread_mutex_lock(&LOCK_io); + //open the socket + int sock = socket(AF_UNIX,SOCK_STREAM,0); + if (sock < 0) { sql_print_error( - "%s unable to connect to socket: %s. err: %s. audit socket handler disabled!!", - AUDIT_LOG_PREFIX, m_sockname, strerror(errno)); + "%s unable to create socket: %s. audit socket handler disabled!!", + AUDIT_LOG_PREFIX, strerror(errno)); + m_enabled = false; + pthread_mutex_unlock(&LOCK_io); + return; + } + + //connect the socket + m_vio= vio_new(sock, VIO_TYPE_SOCKET, VIO_LOCALHOST); + struct sockaddr_un UNIXaddr; + UNIXaddr.sun_family = AF_UNIX; + strmake(UNIXaddr.sun_path, m_sockname, sizeof(UNIXaddr.sun_path)-1); + if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr), + m_connect_timeout)) + { + sql_print_error( + "%s unable to connect to socket: %s. err: %s. audit socket handler disabled!!", + AUDIT_LOG_PREFIX, m_sockname, strerror(errno)); close_vio(); m_enabled = false; pthread_mutex_unlock(&LOCK_io); return; } - ssize_t res = m_formatter->start_msg_format(this); - /* - sanity check of writing to the log. If we fail. We will print an erorr and disable this handler. - */ - if (res < 0) + ssize_t res = m_formatter->start_msg_format(this); + /* + sanity check of writing to the log. If we fail. We will print an erorr and disable this handler. + */ + if (res < 0) { - sql_print_error( - "%s unable to write to %s: %s. Disabling audit handler.", - AUDIT_LOG_PREFIX, m_sockname, strerror(errno)); - close_vio(); - m_enabled = false; + sql_print_error( + "%s unable to write to %s: %s. Disabling audit handler.", + AUDIT_LOG_PREFIX, m_sockname, strerror(errno)); + close_vio(); + m_enabled = false; } - pthread_mutex_unlock(&LOCK_io); + pthread_mutex_unlock(&LOCK_io); } void Audit_socket_handler::handler_stop() { - pthread_mutex_lock(&LOCK_io); - m_formatter->stop_msg_format(this); - close_vio(); - pthread_mutex_unlock(&LOCK_io); + pthread_mutex_lock(&LOCK_io); + m_formatter->stop_msg_format(this); + close_vio(); + pthread_mutex_unlock(&LOCK_io); } void Audit_socket_handler::handler_log_audit(ThdSesData *pThdData) { - pthread_mutex_lock(&LOCK_io); - m_formatter->event_format(pThdData, this); - pthread_mutex_unlock(&LOCK_io); + pthread_mutex_lock(&LOCK_io); + m_formatter->event_format(pThdData, this); + pthread_mutex_unlock(&LOCK_io); } //////////////////////// Audit Socket handler end /////////////////////////////////////////// @@ -291,40 +291,40 @@ void Audit_socket_handler::handler_log_audit(ThdSesData *pThdData) static inline yajl_gen_status yajl_add_string(yajl_gen hand, const char * str) { - return yajl_gen_string(hand, (const unsigned char*)str, strlen(str)); + return yajl_gen_string(hand, (const unsigned char*)str, strlen(str)); } static inline void yajl_add_string_val(yajl_gen hand, const char * name, const char* val) { - if(0 == val) - { - return; //we don't add NULL values to json - } - yajl_add_string(hand, name); - yajl_add_string(hand, val); + if(0 == val) + { + return; //we don't add NULL values to json + } + yajl_add_string(hand, name); + yajl_add_string(hand, val); } static inline void yajl_add_string_val(yajl_gen hand, const char * name, const char* val, size_t val_len) { - yajl_add_string(hand, name); - yajl_gen_string(hand, (const unsigned char*)val, val_len); + yajl_add_string(hand, name); + yajl_gen_string(hand, (const unsigned char*)val, val_len); } static inline void yajl_add_uint64(yajl_gen gen, const char * name, uint64 num) { - const size_t max_int64_str_len = 21; - char buf[max_int64_str_len]; - snprintf(buf, max_int64_str_len, "%llu", num); - yajl_add_string_val(gen, name, buf); + const size_t max_int64_str_len = 21; + char buf[max_int64_str_len]; + 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, "db", db); + if (name) { - yajl_add_string_val(gen, "name", name); + yajl_add_string_val(gen, "name", name); } - yajl_add_string_val(gen, "obj_type",ptype); + yajl_add_string_val(gen, "obj_type",ptype); } //void Audit_file_handler::print_sleep (THD *thd, int delay_ms) @@ -334,152 +334,151 @@ static inline void yajl_add_obj( yajl_gen gen, const char *db,const char* ptype // yajl_gen gen = yajl_gen_alloc(&config, NULL); // yajl_gen_array_open(gen); // yajl_gen_map_open(gen); -// yajl_add_string_val(gen, "msg-type", "activity"); +// yajl_add_string_val(gen, "msg-type", "activity"); // uint64 ts = my_getsystime() / (10000); // yajl_add_uint64(gen, "date", ts); -// yajl_add_uint64(gen, "thread-id", thdid); -// yajl_add_uint64(gen, "audit is going to sleep for ", delay_ms); -// yajl_gen_map_close(gen); -// yajl_gen_array_close(gen); +// yajl_add_uint64(gen, "thread-id", thdid); +// yajl_add_uint64(gen, "audit is going to sleep for ", delay_ms); +// yajl_gen_map_close(gen); +// yajl_gen_array_close(gen); // fflush(m_log_file); // int fd = fileno(m_log_file); -// my_sync(fd, MYF(MY_WME)); +// my_sync(fd, MYF(MY_WME)); // //} ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * writer) { - 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()); + 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()); - Security_context * sctx = thd_inst_main_security_ctx(pThdData->getTHD()); + Security_context * sctx = thd_inst_main_security_ctx(pThdData->getTHD()); - //initialize yajl - yajl_gen gen = yajl_gen_alloc(&config, NULL); - yajl_gen_map_open(gen); - yajl_add_string_val(gen, "msg-type", "activity"); - //TODO: get the start date from THD (but it is not in millis. Need to think about how we handle this) - //for now simply use the current time. - //my_getsystime() time since epoc in 100 nanosec units. Need to devide by 1000*(1000/100) to reach millis - uint64 ts = my_getsystime() / (10000); - yajl_add_uint64(gen, "date", ts); - yajl_add_uint64(gen, "thread-id", thdid); - yajl_add_uint64(gen, "query-id", qid); - yajl_add_string_val(gen, "user", sctx->user); - 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); - 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) + //initialize yajl + yajl_gen gen = yajl_gen_alloc(&config, NULL); + yajl_gen_map_open(gen); + yajl_add_string_val(gen, "msg-type", "activity"); + //TODO: get the start date from THD (but it is not in millis. Need to think about how we handle this) + //for now simply use the current time. + //my_getsystime() time since epoc in 100 nanosec units. Need to devide by 1000*(1000/100) to reach millis + uint64 ts = my_getsystime() / (10000); + yajl_add_uint64(gen, "date", ts); + yajl_add_uint64(gen, "thread-id", thdid); + yajl_add_uint64(gen, "query-id", qid); + yajl_add_string_val(gen, "user", sctx->user); + 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); + 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;inum_of_elem && i < MAX_NUM_QUERY_TABLE_ELEM && pQuery_cache_table_list->num_of_elem >=0;i++) + yajl_add_string_val(gen, "cmd", "select"); + yajl_add_string(gen, "objects"); + yajl_gen_array_open(gen); + for (int i=0;inum_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_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); + yajl_gen_array_close(gen); } - else + else { - - yajl_add_string_val(gen, "cmd", cmd); + yajl_add_string_val(gen, "cmd", cmd); } - if (strcmp (cmd,"Init DB") ==0 || strcmp (cmd, "SHOW TABLES")== 0 || strcmp (cmd, "SHOW TABLE")==0) - { - if ((pThdData->getTHD())->db !=0) - { - yajl_add_string(gen, "objects"); - yajl_gen_array_open(gen); - yajl_add_obj (gen,(pThdData->getTHD())->db,"database", NULL); - yajl_gen_array_close(gen); - } - } - - - if (pLex && command != COM_QUIT && pLex->query_tables) + if (strcmp (cmd,"Init DB") ==0 || strcmp (cmd, "SHOW TABLES")== 0 || strcmp (cmd, "SHOW TABLE")==0) { - yajl_add_string(gen, "objects"); - yajl_gen_array_open(gen); - TABLE_LIST * table = pLex->query_tables; - bool isFirstElementInView = true; - - while (table) - { - yajl_gen_map_open(gen); - if (isFirstElementInView && strstr (cmd,"_view")!=NULL ) - { - yajl_add_obj (gen,table->get_db_name(), "view",table->get_table_name()); - isFirstElementInView = false; - } - else - { - 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; - } - yajl_gen_array_close(gen); + if ((pThdData->getTHD())->db !=0) + { + yajl_add_string(gen, "objects"); + yajl_gen_array_open(gen); + yajl_add_obj (gen,(pThdData->getTHD())->db,"database", NULL); + yajl_gen_array_close(gen); + } } - size_t qlen = 0; - - const char * query = thd_query(pThdData->getTHD(), &qlen); - if (query && qlen > 0) + if (pLex && command != COM_QUIT && pLex->query_tables) { - CHARSET_INFO *col_connection = Item::default_charset(); - if (strcmp (col_connection->csname,"utf8")!=0) { - String sQuery (query,col_connection) ; - pThdData->getTHD()->convert_string (&sQuery,col_connection,&my_charset_utf8_general_ci); - yajl_add_string_val(gen, "query", sQuery.c_ptr_safe(), sQuery.length()); - } - else - { - yajl_add_string_val(gen, "query",query, qlen); - } + yajl_add_string(gen, "objects"); + yajl_gen_array_open(gen); + TABLE_LIST * table = pLex->query_tables; + bool isFirstElementInView = true; + + while (table) + { + yajl_gen_map_open(gen); + if (isFirstElementInView && strstr (cmd,"_view")!=NULL ) + { + yajl_add_obj (gen,table->get_db_name(), "view",table->get_table_name()); + isFirstElementInView = false; + } + else + { + 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; + } + yajl_gen_array_close(gen); + } + + + size_t qlen = 0; + + const char * query = thd_query(pThdData->getTHD(), &qlen); + if (query && qlen > 0) + { + CHARSET_INFO *col_connection = Item::default_charset(); + if (strcmp (col_connection->csname,"utf8")!=0) { + String sQuery (query,col_connection) ; + pThdData->getTHD()->convert_string (&sQuery,col_connection,&my_charset_utf8_general_ci); + yajl_add_string_val(gen, "query", sQuery.c_ptr_safe(), sQuery.length()); + } + else + { + yajl_add_string_val(gen, "query",query, qlen); + } } - else + else { - if (cmd!=NULL && strlen (cmd)!=0) + if (cmd!=NULL && strlen (cmd)!=0) { - yajl_add_string_val(gen, "query",cmd, strlen (cmd)); + yajl_add_string_val(gen, "query",cmd, strlen (cmd)); } - else + else { - yajl_add_string_val(gen, "query","n/a", strlen ("n/a" )); + yajl_add_string_val(gen, "query","n/a", strlen ("n/a" )); } } - ssize_t res = -2; - yajl_gen_status stat = yajl_gen_map_close(gen); //close the object - if(stat == yajl_gen_status_ok) //all is good write the buffer out + ssize_t res = -2; + yajl_gen_status stat = yajl_gen_map_close(gen); //close the object + if(stat == yajl_gen_status_ok) //all is good write the buffer out { - const unsigned char * text = NULL; - unsigned int len = 0; - yajl_gen_get_buf(gen, &text, &len); - //print the json - res = writer->write((const char *)text, len); - if(res >= 0) + const unsigned char * text = NULL; + unsigned int len = 0; + yajl_gen_get_buf(gen, &text, &len); + //print the json + res = writer->write((const char *)text, len); + if(res >= 0) { - //TODO: use the msg_delimiter - res = writer->write("\n", 1); + //TODO: use the msg_delimiter + res = writer->write("\n", 1); } - //my_fwrite(log_file, (uchar *) b.data, json_size(&b), MYF(0)); + //my_fwrite(log_file, (uchar *) b.data, json_size(&b), MYF(0)); } - yajl_gen_free(gen); //free the generator - return res; + yajl_gen_free(gen); //free the generator + return res; } @@ -487,5 +486,5 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write ThdSesData::ThdSesData (THD *pTHD) : m_pThd (pTHD), m_CmdName(NULL) { - m_CmdName = retrieve_command (m_pThd); + m_CmdName = retrieve_command (m_pThd); } diff --git a/src/audit_plugin.cc b/src/audit_plugin.cc index 973f63d..1352db4 100644 --- a/src/audit_plugin.cc +++ b/src/audit_plugin.cc @@ -104,6 +104,8 @@ static const ThdOffsets thd_offsets_arr[] = {"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}, + //offsets for: + {"5.1.63","2a6d7c81179baf6bc6bbb807b8b54967", 6336, 6400, 3696, 3968, 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) @@ -454,8 +456,16 @@ static my_bool validate_checksum_enable = FALSE; static char * offsets_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 record_cmds_array [SQLCOM_END + 2][MAX_COMMAND_CHAR_NUMBERS]; +static char record_objs_array [MAX_NUM_OBJECT_ELEM + 2][MAX_OBJECT_CHAR_NUMBERS]; +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. @@ -506,9 +516,49 @@ THDPRINTED * GetThdPrintedList (THD *thd) return NULL; } +static int check_array(const char *cmd, char *array, int length) { + for (int k=0; array[k * length + 0] !='\0';k++) { + 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(); + if (!check_array(cmd, (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 obj[MAX_OBJECT_CHAR_NUMBERS]; + strcpy(obj, db); + strcat(obj, ":"); + strcat(obj, name); + matched = check_array(obj, (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) @@ -528,21 +578,11 @@ 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) - { - //Audit_file_handler::print_sleep(thd,delay_ms_val); - my_sleep (delay_ms_val *1000); - break; - } + int delay = check_array(cmd, (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); } } } @@ -887,47 +927,47 @@ static bool parse_thd_offsets_string (char *poffsets_string) { char offset_str [2048] = {0}; - char *poffset_str = offset_str; - strncpy (poffset_str,poffsets_string,2048); - char * comma_delimiter = strchr (poffset_str,','); - int i =0; - OFFSET *pOffset; - size_t len = strlen (poffset_str); - - for (int j=0;j= '0' && poffset_str[j] <='9') || poffset_str[j] == ' ' || poffset_str[j] == ',')) - return false; - } - while (comma_delimiter !=NULL) - { - *comma_delimiter = '\0'; - pOffset = (OFFSET*)&Audit_formatter::thd_offsets.query_id + i; - if ((size_t)pOffset- (size_t)&Audit_formatter::thd_offsets < sizeof (Audit_formatter::thd_offsets)) - { - sscanf (poffset_str, "%d", pOffset); - } - else - { - return false; - } - i++; - poffset_str = comma_delimiter + 1; - comma_delimiter = strchr (poffset_str,','); - } - if (poffset_str !=NULL) - { - pOffset = &Audit_formatter::thd_offsets.query_id + i; - if ((size_t)pOffset- (size_t)&Audit_formatter::thd_offsets < sizeof (Audit_formatter::thd_offsets)) - { - sscanf (poffset_str, "%d", pOffset); - } - else - { - return false; - } - } - return true; + char *poffset_str = offset_str; + strncpy (poffset_str,poffsets_string,2048); + char * comma_delimiter = strchr (poffset_str,','); + int i =0; + OFFSET *pOffset; + size_t len = strlen (poffset_str); + + for (int j=0;j= '0' && poffset_str[j] <='9') || poffset_str[j] == ' ' || poffset_str[j] == ',')) + return false; + } + while (comma_delimiter !=NULL) + { + *comma_delimiter = '\0'; + pOffset = (OFFSET*)&Audit_formatter::thd_offsets.query_id + i; + if ((size_t)pOffset- (size_t)&Audit_formatter::thd_offsets < sizeof (Audit_formatter::thd_offsets)) + { + sscanf (poffset_str, "%d", pOffset); + } + else + { + return false; + } + i++; + poffset_str = comma_delimiter + 1; + comma_delimiter = strchr (poffset_str,','); + } + if (poffset_str !=NULL) + { + pOffset = &Audit_formatter::thd_offsets.query_id + i; + if ((size_t)pOffset- (size_t)&Audit_formatter::thd_offsets < sizeof (Audit_formatter::thd_offsets)) + { + sscanf (poffset_str, "%d", pOffset); + } + else + { + return false; + } + } + return true; } /** @@ -1097,69 +1137,69 @@ static int setup_offsets() 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; - } + + 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); + 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. @@ -1414,8 +1454,9 @@ 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 int string_handler (THD *thd, struct st_mysql_sys_var *var, + void *tgt, const void *save, + char *string_array, int rows, int length) { char *old= *(char **) tgt; @@ -1429,41 +1470,60 @@ static void delay_cmds_string_handler (THD *thd, struct st_mysql_sys_var *var, const char* save_string; save_string = *static_cast(save); - int k =0; - if (save_string !=NULL) - { + int r =0; + if (save_string !=NULL) { + int p = 0; + for (int i = 0; save_string[i] != '\0'; i++) { + // consider space and tab and comma to be separators + // strings of multiple of them will be only a single separator + 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; + } + } + } + // otherwise copy the character over + else { + string_array[r * length + p] = tolower(save_string[i]); + p++; + } + } + // if we have copied chars to the current row, then terminate the string and + // go to the next row. + if (p > 0) { + string_array[r * length + p] = '\0'; + r++; + } + // now terminate the list + string_array[r * length + 0] = '\0'; + } - 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'; - } + return r; +} + +static void delay_cmds_string_handler (THD *thd, struct st_mysql_sys_var *var, + void *tgt, const void *save) +{ + num_delay_cmds = string_handler(thd, var, tgt, save, (char *) delay_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS); + sql_print_information("%s Set num_delay_cmds: %d", log_prefix, num_delay_cmds); +} + +static void record_cmds_string_handler (THD *thd, struct st_mysql_sys_var *var, + void *tgt, const void *save) +{ + num_record_cmds = string_handler(thd, var, tgt, save, (char *) record_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS); + sql_print_information("%s Set num_record_cmds: %d", log_prefix, num_record_cmds); +} + +static void record_objs_string_handler (THD *thd, struct st_mysql_sys_var *var, + void *tgt, const void *save) +{ + num_record_objs = string_handler(thd, var, tgt, save, (char *) 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 @@ -1517,6 +1577,16 @@ static MYSQL_SYSVAR_STR(delay_cmds, delay_cmds_string, "AUDIT plugin delay commands to match against comma separated. If empty then delay is disabled.", NULL, delay_cmds_string_handler, NULL); +static MYSQL_SYSVAR_STR(record_cmds, record_cmds_string, + PLUGIN_VAR_RQCMDARG, + "AUDIT plugin commands to record, comma separated", + NULL, record_cmds_string_handler, NULL); + +static MYSQL_SYSVAR_STR(record_objs, record_objs_string, + PLUGIN_VAR_RQCMDARG, + "AUDIT plugin objects to record, comma separated", + NULL, record_objs_string_handler, NULL); + /* * Plugin system vars */ @@ -1534,6 +1604,8 @@ 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), NULL }; //declare our plugin