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 found_rows;
OFFSET sent_row_count; OFFSET sent_row_count;
OFFSET row_count_func; OFFSET row_count_func;
OFFSET stmt_da;
OFFSET da_status;
OFFSET da_sql_errno;
} ThdOffsets; } ThdOffsets;
/* /*
@ -145,6 +148,9 @@ public:
const char *getOsUser() const; const char *getOsUser() const;
const int getPort() const { return m_port; } const int getPort() const { return m_port; }
const StatementSource getStatementSource() const { return m_source; } 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. * Start fetching objects. Return true if there are objects available.
*/ */
@ -178,6 +184,9 @@ private:
int m_port; // TCP port of remote side int m_port; // TCP port of remote side
uint m_errorCode;
bool m_setErrorCode;
protected: protected:
ThdSesData(const ThdSesData&); ThdSesData(const ThdSesData&);
ThdSesData &operator =(const ThdSesData&); ThdSesData &operator =(const ThdSesData&);
@ -391,23 +400,19 @@ public:
static inline const char * pfs_connect_attrs(void * pfs) 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 //no offsets - return null
return NULL; return NULL;
} }
const char **pfs_pointer = (const char **) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs); 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; return *pfs_pointer;
} }
static inline uint pfs_connect_attrs_length(void * pfs) 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 //no offsets - return 0
return 0; return 0;
@ -417,7 +422,7 @@ public:
static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs) 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 //no offsets - return null
return NULL; return NULL;
@ -518,6 +523,47 @@ static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
return *rows; 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 #if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
static inline Sql_cmd_uninstall_plugin* lex_sql_cmd(LEX *lex) 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_base.h>
#include <sql/sql_table.h> #include <sql/sql_table.h>
#include <sql/sql_view.h> #include <sql/sql_view.h>
#include <sql/sql_error.h>
// TODO: use mysql mutex instead of pthread // TODO: use mysql mutex instead of pthread
/* /*

View File

@ -110,6 +110,26 @@ else
LEX_SQL='printf ", 0, 0"' LEX_SQL='printf ", 0, 0"'
fi 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 cat <<EOF > offsets.gdb
set logging on set logging on
set width 0 set width 0
@ -136,6 +156,9 @@ $LEX_SQL
$FOUND_ROWS $FOUND_ROWS
$SENT_ROW_COUNT $SENT_ROW_COUNT
$ROW_COUNT_FUNC $ROW_COUNT_FUNC
$STMT_DA
$DA_STATUS
$DA_SQL_ERRNO
printf "}" printf "}"
EOF EOF

View File

@ -945,6 +945,12 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
yajl_add_uint64(gen, "rows", rows); 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); yajl_add_string_val(gen, "cmd", cmd);
// get objects // get objects
@ -1074,7 +1080,7 @@ ThdSesData::ThdSesData(THD *pTHD, StatementSource source)
: m_pThd (pTHD), m_CmdName(NULL), m_UserName(NULL), : m_pThd (pTHD), m_CmdName(NULL), m_UserName(NULL),
m_objIterType(OBJ_NONE), m_tables(NULL), m_firstTable(true), m_objIterType(OBJ_NONE), m_tables(NULL), m_firstTable(true),
m_tableInf(NULL), m_index(0), m_isSqlCmd(false), 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_CmdName = retrieve_command (m_pThd, m_isSqlCmd);
m_UserName = retrieve_user (m_pThd); 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() bool ThdSesData::startGetObjects()
{ {
// reset vars as this may be called multiple times // 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; 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++) for (int k = 0; array[k * length] !='\0';k++)
{ {
const char *elem = array + (k * length);
for (int q = 0; cmds[q] != NULL; q++) for (int q = 0; cmds[q] != NULL; q++)
{ {
const char *cmd = cmds[q]; const char *cmd = cmds[q];
int j = 0; if (strcasecmp(cmd, elem) == 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 1;
} }
@ -665,8 +670,9 @@ static int audit_send_result_to_client(Query_cache *pthis, THD *thd, const LEX_
#endif #endif
if (res) if (res)
{ {
ThdSesData thd_data(thd, ThdSesData::SOURCE_QUERY_CACHE); ThdSesData thdData(thd, ThdSesData::SOURCE_QUERY_CACHE);
audit(&thd_data); thdData.storeErrorCode();
audit(&thdData);
} }
THDVAR(thd, query_cache_table_list) = 0; THDVAR(thd, query_cache_table_list) = 0;
return res; 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_thread_id(thd)
|| Audit_formatter::thd_inst_query_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); audit(&thd_data);
} }
return res; return res;
@ -712,10 +719,11 @@ static void audit_post_execute(THD * thd)
// query events are audited by mysql execute command // query events are audited by mysql execute command
if (Audit_formatter::thd_inst_command(thd) != COM_QUERY) if (Audit_formatter::thd_inst_command(thd) != COM_QUERY)
{ {
ThdSesData ThdData(thd); ThdSesData thdData(thd);
if (strcasestr(ThdData.getCmdName(), "show_fields") == NULL) 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: case ER_ACCOUNT_HAS_BEEN_LOCKED:
#endif #endif
ThdData.setCmdName("Failed Login"); ThdData.setCmdName("Failed Login");
ThdData.setErrorCode(event_general->general_error_code);
audit(&ThdData); audit(&ThdData);
break; break;
default: default:
@ -939,9 +948,11 @@ int is_remove_patches(ThdSesData *pThdData)
#endif #endif
if (strncasecmp(Lex_comment.str, PLUGIN_NAME, strlen(PLUGIN_NAME)) == 0) if (strncasecmp(Lex_comment.str, PLUGIN_NAME, strlen(PLUGIN_NAME)) == 0)
{ {
char msgBuffer[200];
if (! uninstall_plugin_enable) 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; return 2;
} }
@ -951,7 +962,8 @@ int is_remove_patches(ThdSesData *pThdData)
if (! called_once) if (! called_once)
{ {
called_once = true; 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 2;
} }
return 1; return 1;
@ -989,10 +1001,10 @@ static int audit_mysql_execute_command(THD *thd)
} }
} }
ThdSesData thd_data(thd); ThdSesData thdData(thd);
const char *cmd = thd_data.getCmdName(); const char *cmd = thdData.getCmdName();
do_delay(& thd_data); do_delay(& thdData);
if (before_after_mode == AUDIT_BEFORE || before_after_mode == AUDIT_BOTH) 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, "truncate") != NULL ||
strcasestr(cmd, "rename") != NULL) strcasestr(cmd, "rename") != NULL)
{ {
audit(&thd_data); audit(&thdData);
} }
} }
@ -1017,7 +1029,7 @@ static int audit_mysql_execute_command(THD *thd)
} }
else else
{ {
switch (is_remove_patches(&thd_data)) switch (is_remove_patches(&thdData))
{ {
case 1: case 1:
// hot patch function were removed and we call the real execute (restored) // 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) if (before_after_mode == AUDIT_AFTER || before_after_mode == AUDIT_BOTH)
{ {
audit(&thd_data); audit(&thdData);
} }
if (pThdPrintedList && pThdPrintedList->cur_index > 0) 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) bool check_count)
{ {
int res = trampoline_check_user(thd, command, passwd, passwd_len, db, check_count); int res = trampoline_check_user(thd, command, passwd, passwd_len, db, check_count);
ThdSesData ThdData(thd); ThdSesData thdData(thd);
thdData.storeErrorCode();
audit(&ThdData); audit(&thdData);
return (res); 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) 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); bool res = trampoline_acl_authenticate(thd, connect_errors, com_change_user_pkt_len);
ThdSesData ThdData(thd); ThdSesData thdData(thd);
thdData.storeErrorCode();
audit(&ThdData); audit(&thdData);
return (res); 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) if ((fd = my_open(file_name, O_RDONLY, MYF(MY_WME))) < 0)
{ {
sql_print_error("%s Failed file open: [%s], errno: %d.", sql_print_error("%s Failed file open: [%s], errno: %d. Retrying with /proc/%d/exe.",
log_prefix, file_name, errno); log_prefix, file_name, errno, getpid());
return false;
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; my_MD5Context context;
@ -1348,7 +1369,7 @@ static int setup_offsets()
if (parse_thd_offsets_string(offsets_string)) 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.query_id,
Audit_formatter::thd_offsets.thread_id, Audit_formatter::thd_offsets.thread_id,
Audit_formatter::thd_offsets.main_security_ctx, 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.uninstall_cmd_comment,
Audit_formatter::thd_offsets.found_rows, Audit_formatter::thd_offsets.found_rows,
Audit_formatter::thd_offsets.sent_row_count, 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)) if (! validate_offsets(&Audit_formatter::thd_offsets))
@ -1485,11 +1509,23 @@ static int setup_offsets()
{ {
decoffsets.row_count_func -= dec; 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)) if (validate_offsets(&decoffsets))
{ {
Audit_formatter::thd_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, log_prefix, dec, offset->version, offset->md5digest,
Audit_formatter::thd_offsets.query_id, Audit_formatter::thd_offsets.query_id,
Audit_formatter::thd_offsets.thread_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.uninstall_cmd_comment,
Audit_formatter::thd_offsets.found_rows, Audit_formatter::thd_offsets.found_rows,
Audit_formatter::thd_offsets.sent_row_count, 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); DBUG_RETURN(0);
@ -1529,7 +1568,7 @@ static int setup_offsets()
if (validate_offsets(&incoffsets)) if (validate_offsets(&incoffsets))
{ {
Audit_formatter::thd_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, log_prefix, inc, offset->version, offset->md5digest,
Audit_formatter::thd_offsets.query_id, Audit_formatter::thd_offsets.query_id,
Audit_formatter::thd_offsets.thread_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.uninstall_cmd_comment,
Audit_formatter::thd_offsets.found_rows, Audit_formatter::thd_offsets.found_rows,
Audit_formatter::thd_offsets.sent_row_count, 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); DBUG_RETURN(0);
} }
@ -1976,7 +2018,7 @@ static int audit_plugin_init(void *p)
interface_ver = interface_ver >> 8; interface_ver = interface_ver >> 8;
#endif #endif
sql_print_information( 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, log_prefix, MYSQL_AUDIT_PLUGIN_VERSION,
MYSQL_AUDIT_PLUGIN_REVISION, arch, interface_ver, interface_ver, MYSQL_AUDIT_PLUGIN_REVISION, arch, interface_ver, interface_ver,
server_version); server_version);