Add offsets for MariaDB 10.0.32 and 10.1.26.

Fix Community Issues 171, 172, 173.
Add support for sending exit status of a command.
pull/179/head
Aharon Robbins 2017-08-31 11:16:19 +03:00
parent 969d0b481a
commit 40dc1e7ff7
6 changed files with 1273 additions and 1129 deletions

View File

@ -101,6 +101,9 @@ typedef struct ThdOffsets {
OFFSET found_rows;
OFFSET sent_row_count;
OFFSET row_count_func;
OFFSET stmt_da;
OFFSET da_status;
OFFSET da_sql_errno;
} ThdOffsets;
/*
@ -145,6 +148,9 @@ public:
const char *getOsUser() const;
const int getPort() const { return m_port; }
const StatementSource getStatementSource() const { return m_source; }
void storeErrorCode();
void setErrorCode(uint code) { m_errorCode = code; m_setErrorCode = true; }
bool getErrorCode(uint & code) const { code = m_errorCode; return m_setErrorCode; }
/**
* Start fetching objects. Return true if there are objects available.
*/
@ -178,6 +184,9 @@ private:
int m_port; // TCP port of remote side
uint m_errorCode;
bool m_setErrorCode;
protected:
ThdSesData(const ThdSesData&);
ThdSesData &operator =(const ThdSesData&);
@ -391,23 +400,19 @@ public:
static inline const char * pfs_connect_attrs(void * pfs)
{
if (! Audit_formatter::thd_offsets.pfs_connect_attrs)
if (! Audit_formatter::thd_offsets.pfs_connect_attrs || pfs == NULL)
{
//no offsets - return null
return NULL;
}
const char **pfs_pointer = (const char **) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs);
if (pfs_pointer == NULL)
{
return NULL;
}
return *pfs_pointer;
}
static inline uint pfs_connect_attrs_length(void * pfs)
{
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_length)
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_length || pfs == NULL)
{
//no offsets - return 0
return 0;
@ -417,7 +422,7 @@ public:
static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
{
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_cs)
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_cs || pfs == NULL)
{
//no offsets - return null
return NULL;
@ -518,6 +523,47 @@ static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
return *rows;
}
static inline bool thd_error_code(THD *thd, uint & code)
{
#if MYSQL_VERSION_ID >= 50534
if ( Audit_formatter::thd_offsets.stmt_da == 0 ||
Audit_formatter::thd_offsets.da_status == 0 ||
Audit_formatter::thd_offsets.da_sql_errno == 0 )
{
return false;
}
Diagnostics_area **stmt_da = ((Diagnostics_area **) (((unsigned char *) thd)
+ Audit_formatter::thd_offsets.stmt_da));
enum Diagnostics_area::enum_diagnostics_status *status =
((enum Diagnostics_area::enum_diagnostics_status *) (((unsigned char *) (*stmt_da))
+ Audit_formatter::thd_offsets.da_status));
uint *sql_errno = ((uint *) (((unsigned char *) (*stmt_da))
+ Audit_formatter::thd_offsets.da_sql_errno));
if (*status == Diagnostics_area::DA_OK ||
*status == Diagnostics_area::DA_EOF )
{
code = 0;
return true;
}
else if (*status == Diagnostics_area::DA_ERROR)
{
code = *sql_errno;
return true;
}
else // DA_EMPTY, DA_DISABLE
{
return false;
}
#else
return false;
#endif
}
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
static inline Sql_cmd_uninstall_plugin* lex_sql_cmd(LEX *lex)
{

View File

@ -44,6 +44,7 @@
#include <sql/sql_base.h>
#include <sql/sql_table.h>
#include <sql/sql_view.h>
#include <sql/sql_error.h>
// TODO: use mysql mutex instead of pthread
/*

View File

@ -110,6 +110,26 @@ else
LEX_SQL='printf ", 0, 0"'
fi
# Exit status info 5.5, 5.6, 5.7
DA_STATUS="print_offset Diagnostics_area m_status" # 5.5, 5.6, 5.7, mariadb 10.0, 10.1, 10.2
DA_SQL_ERRNO="print_offset Diagnostics_area m_sql_errno" # 5.5, 5.6, mariadb 10.0, 10.1, 10.2
STMT_DA="print_offset THD m_stmt_da" # 5.6, 5.7, mariadb 10.0, 10.1, 10.2
if echo $MYVER | grep -P '^(5\.7)' > /dev/null
then
DA_SQL_ERRNO="print_offset Diagnostics_area m_mysql_errno"
elif echo $MYVER | grep -P '^(5\.6|10\.)' > /dev/null
then
: place holder
elif echo $MYVER | grep -P '^(5\.5)' > /dev/null
then
STMT_DA="print_offset THD stmt_da"
else
STMT_DA='printf ", 0"'
DA_STATUS='printf ", 0"'
DA_SQL_ERRNO='printf ", 0"'
fi
cat <<EOF > offsets.gdb
set logging on
set width 0
@ -136,6 +156,9 @@ $LEX_SQL
$FOUND_ROWS
$SENT_ROW_COUNT
$ROW_COUNT_FUNC
$STMT_DA
$DA_STATUS
$DA_SQL_ERRNO
printf "}"
EOF

View File

@ -945,6 +945,12 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
yajl_add_uint64(gen, "rows", rows);
}
uint code;
if (pThdData->getErrorCode(code))
{
yajl_add_uint64(gen, "status", code); // 0 - success, otherwise reports specific errno
}
yajl_add_string_val(gen, "cmd", cmd);
// get objects
@ -1074,7 +1080,7 @@ ThdSesData::ThdSesData(THD *pTHD, StatementSource source)
: m_pThd (pTHD), m_CmdName(NULL), m_UserName(NULL),
m_objIterType(OBJ_NONE), m_tables(NULL), m_firstTable(true),
m_tableInf(NULL), m_index(0), m_isSqlCmd(false),
m_port(-1), m_source(source)
m_port(-1), m_source(source), m_errorCode(0), m_setErrorCode(false)
{
m_CmdName = retrieve_command (m_pThd, m_isSqlCmd);
m_UserName = retrieve_user (m_pThd);
@ -1087,6 +1093,15 @@ ThdSesData::ThdSesData(THD *pTHD, StatementSource source)
}
}
void ThdSesData::storeErrorCode()
{
uint code = 0;
if (Audit_formatter::thd_error_code(m_pThd, code))
{
setErrorCode(code);
}
}
bool ThdSesData::startGetObjects()
{
// reset vars as this may be called multiple times

File diff suppressed because it is too large Load Diff

View File

@ -397,20 +397,25 @@ PeerInfo *retrieve_peerinfo(THD *thd)
return NULL;
}
static int check_array(const char *cmds[],const char *array, int length)
// cmds[] is a list of "commands" (names, commands, whatever) to
// check against the list stored in `array'. Although declared
// here as simple `char *', the `array' is actually a two-dimensional
// array where each element is `length' bytes long. (An array of
// strings.)
//
// We loop over the array and for each element see if it's also
// in `cmds'. If so, we return 1, otherwise we return 0.
//
// This should really be of type bool and return true/false.
static int check_array(const char *cmds[], const char *array, int length)
{
for (int k = 0; array[k * length] !='\0';k++)
{
const char *elem = array + (k * length);
for (int q = 0; cmds[q] != NULL; q++)
{
const char *cmd = cmds[q];
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)
if (strcasecmp(cmd, elem) == 0)
{
return 1;
}
@ -665,8 +670,9 @@ static int audit_send_result_to_client(Query_cache *pthis, THD *thd, const LEX_
#endif
if (res)
{
ThdSesData thd_data(thd, ThdSesData::SOURCE_QUERY_CACHE);
audit(&thd_data);
ThdSesData thdData(thd, ThdSesData::SOURCE_QUERY_CACHE);
thdData.storeErrorCode();
audit(&thdData);
}
THDVAR(thd, query_cache_table_list) = 0;
return res;
@ -697,7 +703,8 @@ static int audit_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint f
&& (Audit_formatter::thd_inst_thread_id(thd)
|| Audit_formatter::thd_inst_query_id(thd)))
{
ThdSesData thd_data (thd);
ThdSesData thd_data(thd);
// This is before something is run, so no need to set exit status
audit(&thd_data);
}
return res;
@ -712,10 +719,11 @@ static void audit_post_execute(THD * thd)
// query events are audited by mysql execute command
if (Audit_formatter::thd_inst_command(thd) != COM_QUERY)
{
ThdSesData ThdData(thd);
if (strcasestr(ThdData.getCmdName(), "show_fields") == NULL)
ThdSesData thdData(thd);
if (strcasestr(thdData.getCmdName(), "show_fields") == NULL)
{
audit(&ThdData);
thdData.storeErrorCode();
audit(&thdData);
}
}
}
@ -779,6 +787,7 @@ static int audit_notify(THD *thd, mysql_event_class_t event_class,
case ER_ACCOUNT_HAS_BEEN_LOCKED:
#endif
ThdData.setCmdName("Failed Login");
ThdData.setErrorCode(event_general->general_error_code);
audit(&ThdData);
break;
default:
@ -939,9 +948,11 @@ int is_remove_patches(ThdSesData *pThdData)
#endif
if (strncasecmp(Lex_comment.str, PLUGIN_NAME, strlen(PLUGIN_NAME)) == 0)
{
char msgBuffer[200];
if (! uninstall_plugin_enable)
{
my_message(ER_NOT_ALLOWED_COMMAND, "Uninstall AUDIT plugin disabled", MYF(0));
sprintf(msgBuffer, "Uninstall %s plugin disabled", PLUGIN_NAME);
my_message(ER_NOT_ALLOWED_COMMAND, msgBuffer, MYF(0));
return 2;
}
@ -951,7 +962,8 @@ int is_remove_patches(ThdSesData *pThdData)
if (! called_once)
{
called_once = true;
my_message(WARN_PLUGIN_BUSY, "Uninstall AUDIT plugin must be called again to complete", MYF(0));
sprintf(msgBuffer, "Uninstall %s plugin must be called again to complete", PLUGIN_NAME);
my_message(WARN_PLUGIN_BUSY, msgBuffer, MYF(0));
return 2;
}
return 1;
@ -989,10 +1001,10 @@ static int audit_mysql_execute_command(THD *thd)
}
}
ThdSesData thd_data(thd);
const char *cmd = thd_data.getCmdName();
ThdSesData thdData(thd);
const char *cmd = thdData.getCmdName();
do_delay(& thd_data);
do_delay(& thdData);
if (before_after_mode == AUDIT_BEFORE || before_after_mode == AUDIT_BOTH)
{
@ -1002,7 +1014,7 @@ static int audit_mysql_execute_command(THD *thd)
strcasestr(cmd, "truncate") != NULL ||
strcasestr(cmd, "rename") != NULL)
{
audit(&thd_data);
audit(&thdData);
}
}
@ -1017,7 +1029,7 @@ static int audit_mysql_execute_command(THD *thd)
}
else
{
switch (is_remove_patches(&thd_data))
switch (is_remove_patches(&thdData))
{
case 1:
// hot patch function were removed and we call the real execute (restored)
@ -1037,10 +1049,11 @@ static int audit_mysql_execute_command(THD *thd)
}
}
thdData.storeErrorCode();
if (before_after_mode == AUDIT_AFTER || before_after_mode == AUDIT_BOTH)
{
audit(&thd_data);
audit(&thdData);
}
if (pThdPrintedList && pThdPrintedList->cur_index > 0)
@ -1070,9 +1083,9 @@ static int audit_check_user(THD *thd, enum enum_server_command command,
bool check_count)
{
int res = trampoline_check_user(thd, command, passwd, passwd_len, db, check_count);
ThdSesData ThdData(thd);
audit(&ThdData);
ThdSesData thdData(thd);
thdData.storeErrorCode();
audit(&thdData);
return (res);
}
@ -1082,9 +1095,9 @@ static int audit_check_user(THD *thd, enum enum_server_command command,
static bool audit_acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
{
bool res = trampoline_acl_authenticate(thd, connect_errors, com_change_user_pkt_len);
ThdSesData ThdData(thd);
audit(&ThdData);
ThdSesData thdData(thd);
thdData.storeErrorCode();
audit(&thdData);
return (res);
}
@ -1257,9 +1270,17 @@ static bool calc_file_md5(const char *file_name, char *digest_str)
if ((fd = my_open(file_name, O_RDONLY, MYF(MY_WME))) < 0)
{
sql_print_error("%s Failed file open: [%s], errno: %d.",
log_prefix, file_name, errno);
return false;
sql_print_error("%s Failed file open: [%s], errno: %d. Retrying with /proc/%d/exe.",
log_prefix, file_name, errno, getpid());
char pidFilename[100];
sprintf(pidFilename, "/proc/%d/exe", getpid());
if ((fd = my_open(pidFilename, O_RDONLY, MYF(MY_WME))) < 0)
{
sql_print_error("%s Failed file open: [%s], errno: %d.",
log_prefix, pidFilename, errno);
return false;
}
}
my_MD5Context context;
@ -1348,7 +1369,7 @@ static int setup_offsets()
if (parse_thd_offsets_string(offsets_string))
{
sql_print_information ("%s setup_offsets Audit_formatter::thd_offsets values: %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu", log_prefix,
sql_print_information ("%s setup_offsets Audit_formatter::thd_offsets values: %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu", log_prefix,
Audit_formatter::thd_offsets.query_id,
Audit_formatter::thd_offsets.thread_id,
Audit_formatter::thd_offsets.main_security_ctx,
@ -1370,7 +1391,10 @@ static int setup_offsets()
Audit_formatter::thd_offsets.uninstall_cmd_comment,
Audit_formatter::thd_offsets.found_rows,
Audit_formatter::thd_offsets.sent_row_count,
Audit_formatter::thd_offsets.row_count_func
Audit_formatter::thd_offsets.row_count_func,
Audit_formatter::thd_offsets.stmt_da,
Audit_formatter::thd_offsets.da_status,
Audit_formatter::thd_offsets.da_sql_errno
);
if (! validate_offsets(&Audit_formatter::thd_offsets))
@ -1485,11 +1509,23 @@ static int setup_offsets()
{
decoffsets.row_count_func -= dec;
}
if (decoffsets.stmt_da)
{
decoffsets.stmt_da -= dec;
}
if (decoffsets.da_status)
{
decoffsets.da_status -= dec;
}
if (decoffsets.da_sql_errno)
{
decoffsets.da_sql_errno -= dec;
}
if (validate_offsets(&decoffsets))
{
Audit_formatter::thd_offsets = decoffsets;
sql_print_information("%s Using decrement (%zu) offsets from offset version: %s (%s) values: %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu",
sql_print_information("%s Using decrement (%zu) offsets from offset version: %s (%s) values: %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu",
log_prefix, dec, offset->version, offset->md5digest,
Audit_formatter::thd_offsets.query_id,
Audit_formatter::thd_offsets.thread_id,
@ -1511,7 +1547,10 @@ static int setup_offsets()
Audit_formatter::thd_offsets.uninstall_cmd_comment,
Audit_formatter::thd_offsets.found_rows,
Audit_formatter::thd_offsets.sent_row_count,
Audit_formatter::thd_offsets.row_count_func
Audit_formatter::thd_offsets.row_count_func,
Audit_formatter::thd_offsets.stmt_da,
Audit_formatter::thd_offsets.da_status,
Audit_formatter::thd_offsets.da_sql_errno
);
DBUG_RETURN(0);
@ -1529,7 +1568,7 @@ static int setup_offsets()
if (validate_offsets(&incoffsets))
{
Audit_formatter::thd_offsets = incoffsets;
sql_print_information("%s Using increment (%zu) offsets from offset version: %s (%s) values: %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu",
sql_print_information("%s Using increment (%zu) offsets from offset version: %s (%s) values: %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu",
log_prefix, inc, offset->version, offset->md5digest,
Audit_formatter::thd_offsets.query_id,
Audit_formatter::thd_offsets.thread_id,
@ -1551,7 +1590,10 @@ static int setup_offsets()
Audit_formatter::thd_offsets.uninstall_cmd_comment,
Audit_formatter::thd_offsets.found_rows,
Audit_formatter::thd_offsets.sent_row_count,
Audit_formatter::thd_offsets.row_count_func
Audit_formatter::thd_offsets.row_count_func,
Audit_formatter::thd_offsets.stmt_da,
Audit_formatter::thd_offsets.da_status,
Audit_formatter::thd_offsets.da_sql_errno
);
DBUG_RETURN(0);
}
@ -1976,7 +2018,7 @@ static int audit_plugin_init(void *p)
interface_ver = interface_ver >> 8;
#endif
sql_print_information(
"%s starting up. Version: %s , Revision: %s (%s). AUDIT plugin interface version: %d (0x%x). MySQL Server version: %s.",
"%s starting up. Version: %s , Revision: %s (%s). MySQL AUDIT plugin interface version: %d (0x%x). MySQL Server version: %s.",
log_prefix, MYSQL_AUDIT_PLUGIN_VERSION,
MYSQL_AUDIT_PLUGIN_REVISION, arch, interface_ver, interface_ver,
server_version);