You've already forked mysql-audit
mirror of
https://github.com/trellix-enterprise/mysql-audit.git
synced 2025-12-17 18:24:02 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd9400da0e | ||
|
|
0ff56ddfb4 | ||
|
|
570bfb0de6 | ||
|
|
ba21262b81 | ||
|
|
4fbcae3a81 | ||
|
|
d83c36627c | ||
|
|
5e8055249e | ||
|
|
c33a99baa1 | ||
|
|
f29f9bb8ca | ||
|
|
53b1db74e3 |
@@ -48,10 +48,23 @@ typedef struct _THDPRINTED {
|
||||
char is_thd_printed_queue[MAX_NUM_QUEUE_ELEM];
|
||||
} THDPRINTED;
|
||||
|
||||
#define MAX_COMMAND_CHAR_NUMBERS 40
|
||||
struct PeerInfo {
|
||||
unsigned long pid;
|
||||
enum { MAX_APP_NAME_LEN = 128, MAX_USER_NAME_LEN = 128 };
|
||||
char appName[MAX_APP_NAME_LEN + 1];
|
||||
char osUser[MAX_USER_NAME_LEN + 1]; // allow lots, in case from LDAP or some such
|
||||
PeerInfo() : pid(0) {
|
||||
memset(appName, 0, sizeof appName);
|
||||
memset(osUser, 0, sizeof osUser);
|
||||
}
|
||||
};
|
||||
|
||||
PeerInfo *retrieve_peerinfo(THD *thd);
|
||||
|
||||
const char *retrieve_command(THD *thd, bool& is_sql_cmd);
|
||||
typedef size_t OFFSET;
|
||||
|
||||
#define MAX_COMMAND_CHAR_NUMBERS 40
|
||||
#define MAX_COM_STATUS_VARS_RECORDS 512
|
||||
|
||||
// mysql max identifier is 64 so 2*64 + . and null
|
||||
@@ -78,6 +91,16 @@ typedef struct ThdOffsets {
|
||||
OFFSET sec_ctx_priv_user;
|
||||
OFFSET db;
|
||||
OFFSET killed;
|
||||
OFFSET client_capabilities;
|
||||
OFFSET pfs_connect_attrs;
|
||||
OFFSET pfs_connect_attrs_length;
|
||||
OFFSET pfs_connect_attrs_cs;
|
||||
OFFSET net;
|
||||
OFFSET lex_m_sql_command;
|
||||
OFFSET uninstall_cmd_comment;
|
||||
OFFSET found_rows;
|
||||
OFFSET sent_row_count;
|
||||
OFFSET row_count_func;
|
||||
} ThdOffsets;
|
||||
|
||||
/*
|
||||
@@ -110,11 +133,18 @@ class ThdSesData {
|
||||
public:
|
||||
// enum indicating from where the object list came from
|
||||
enum ObjectIterType { OBJ_NONE, OBJ_DB, OBJ_QUERY_CACHE, OBJ_TABLE_LIST };
|
||||
ThdSesData(THD *pTHD);
|
||||
THD *getTHD() { return m_pThd;}
|
||||
const char *getCmdName() { return m_CmdName; }
|
||||
// enum indicating source of statement
|
||||
typedef enum { SOURCE_GENERAL, SOURCE_QUERY_CACHE } StatementSource;
|
||||
ThdSesData(THD *pTHD, StatementSource source = SOURCE_GENERAL);
|
||||
THD *getTHD() const { return m_pThd;}
|
||||
const char *getCmdName() const { return m_CmdName; }
|
||||
void setCmdName(const char *cmd) { m_CmdName = cmd; }
|
||||
const char *getUserName() { return m_UserName; }
|
||||
const unsigned long getPeerPid() const;
|
||||
const char *getAppName() const;
|
||||
const char *getOsUser() const;
|
||||
const int getPort() const { return m_port; }
|
||||
const StatementSource getStatementSource() const { return m_source; }
|
||||
/**
|
||||
* Start fetching objects. Return true if there are objects available.
|
||||
*/
|
||||
@@ -141,6 +171,13 @@ private:
|
||||
QueryTableInf *m_tableInf;
|
||||
int m_index;
|
||||
|
||||
// Statement source
|
||||
StatementSource m_source;
|
||||
|
||||
PeerInfo *m_peerInfo;
|
||||
|
||||
int m_port; // TCP port of remote side
|
||||
|
||||
protected:
|
||||
ThdSesData(const ThdSesData&);
|
||||
ThdSesData &operator =(const ThdSesData&);
|
||||
@@ -319,6 +356,194 @@ public:
|
||||
return *(LEX **) (((unsigned char *) thd) + Audit_formatter::thd_offsets.lex);
|
||||
}
|
||||
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
//in mysql 5.7 capabilities flag moved to protocol. We use the capabilities offset to point to m_protocol
|
||||
//and get from protocol the capabilities flag
|
||||
static inline ulong thd_client_capabilities(THD *thd)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.client_capabilities)
|
||||
{
|
||||
//no offsets - return 0
|
||||
return 0;
|
||||
}
|
||||
Protocol * prot = *(Protocol **) (((unsigned char *) thd) + Audit_formatter::thd_offsets.client_capabilities);
|
||||
if(!prot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return prot->get_client_capabilities();
|
||||
}
|
||||
#else
|
||||
static inline ulong thd_client_capabilities(THD *thd)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.client_capabilities)
|
||||
{
|
||||
//no offsets - return 0
|
||||
return 0;
|
||||
}
|
||||
return *(ulong *) (((unsigned char *) thd) + Audit_formatter::thd_offsets.client_capabilities);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline const char * pfs_connect_attrs(void * pfs)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.pfs_connect_attrs)
|
||||
{
|
||||
//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)
|
||||
{
|
||||
//no offsets - return 0
|
||||
return 0;
|
||||
}
|
||||
return *(uint *) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs_length);
|
||||
}
|
||||
|
||||
static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_cs)
|
||||
{
|
||||
//no offsets - return null
|
||||
return NULL;
|
||||
}
|
||||
#if (!defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50600) || (defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100010)
|
||||
/**
|
||||
* m_session_connect_attrs_cs changed to: m_session_connect_attrs_cs_number
|
||||
* in 5.6.15 and up, 5.7 and mariadb 10.0.11 and up, and 10.1.
|
||||
* see: storage/perfschema/table_session_connect.cc
|
||||
* and: storage/perfschema/pfs_instr.h
|
||||
*/
|
||||
static bool first = true;
|
||||
static int major, minor, patch;
|
||||
|
||||
if (first)
|
||||
{
|
||||
sscanf(server_version, "%d.%d.%d", & major, & minor, & patch);
|
||||
// sql_print_information("Audit_plugin: extracted version: %d.%d.%d",
|
||||
// major, minor, patch);
|
||||
}
|
||||
|
||||
if ( ( major == 5 && ( (minor == 6 && patch >= 15) || minor >= 7) ) // MySQL
|
||||
|| ( major == 10 && ( (minor == 0 && patch >= 11) || minor >= 1) ) ) // MariaDB
|
||||
{
|
||||
uint cs_number = *(uint *) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs_cs);
|
||||
if (!cs_number)
|
||||
{
|
||||
return NULL;
|
||||
|
||||
}
|
||||
return get_charset(cs_number, MYF(0));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return *(const CHARSET_INFO **) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs_cs);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int thd_client_fd(THD *thd)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.net)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
NET *net = ((NET *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.net));
|
||||
// get the socket for the peer
|
||||
int sock = -1;
|
||||
if (net->vio != NULL) // MySQL 5.7.17 - this can happen. :-(
|
||||
{
|
||||
#if MYSQL_VERSION_ID < 50600
|
||||
sock = net->vio->sd;
|
||||
#else
|
||||
sock = net->vio->mysql_socket.fd;
|
||||
#endif
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static inline int thd_client_port(THD *thd)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.net)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
NET *net = ((NET *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.net));
|
||||
|
||||
// get the port for the remote end
|
||||
int port = -1;
|
||||
|
||||
if (net->vio != NULL) // MySQL 5.7.17 - this can happen. :-(
|
||||
{
|
||||
struct sockaddr_in *in;
|
||||
|
||||
in = (struct sockaddr_in *) & net->vio->remote;
|
||||
port = in->sin_port;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
static inline ulonglong thd_found_rows(THD *thd)
|
||||
{
|
||||
if (Audit_formatter::thd_offsets.found_rows == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulonglong *rows = ((ulonglong *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.found_rows));
|
||||
|
||||
return *rows;
|
||||
}
|
||||
|
||||
static inline unsigned long thd_sent_row_count(THD *thd)
|
||||
{
|
||||
if (Audit_formatter::thd_offsets.sent_row_count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ha_rows *rows = ((ha_rows *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.sent_row_count));
|
||||
|
||||
return (unsigned long) *rows;
|
||||
}
|
||||
|
||||
static inline longlong thd_row_count_func(THD *thd)
|
||||
{
|
||||
if (Audit_formatter::thd_offsets.row_count_func == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
longlong *rows = ((longlong *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.row_count_func));
|
||||
|
||||
return *rows;
|
||||
}
|
||||
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
static inline Sql_cmd_uninstall_plugin* lex_sql_cmd(LEX *lex)
|
||||
{
|
||||
return *(Sql_cmd_uninstall_plugin **) (((unsigned char *) lex) + Audit_formatter::thd_offsets.lex_m_sql_command);
|
||||
}
|
||||
#endif
|
||||
|
||||
// we don't use get_db_name() as when we call it view may be not null
|
||||
// and it may return an invalid value for view_db
|
||||
static inline const char *table_get_db_name(TABLE_LIST *table)
|
||||
@@ -348,6 +573,9 @@ public:
|
||||
Audit_json_formatter()
|
||||
: m_msg_delimiter(NULL),
|
||||
m_write_start_msg(true),
|
||||
m_write_sess_connect_attrs(true),
|
||||
m_write_client_capabilities(false),
|
||||
m_write_socket_creds(true),
|
||||
m_password_mask_regex_preg(NULL),
|
||||
m_password_mask_regex_compiled(false),
|
||||
m_perform_password_masking(NULL)
|
||||
@@ -386,7 +614,24 @@ public:
|
||||
* Public so sysvar can update.
|
||||
*/
|
||||
my_bool m_write_start_msg;
|
||||
|
||||
/**
|
||||
* include session oonnect attributes
|
||||
* Public so sysvar can update
|
||||
*/
|
||||
my_bool m_write_sess_connect_attrs;
|
||||
|
||||
/**
|
||||
* include client capabilities
|
||||
* Public for sysvar
|
||||
*/
|
||||
my_bool m_write_client_capabilities;
|
||||
|
||||
/**
|
||||
* include socket credentials from Unix Domain Socket
|
||||
* Public for sysvar
|
||||
*/
|
||||
my_bool m_write_socket_creds;
|
||||
|
||||
/**
|
||||
* Callback function to determine if password masking should be performed
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#if MYSQL_VERSION_ID >= 50709
|
||||
#include <sql/log.h>
|
||||
#if ! defined(MARIADB_BASE_VERSION)
|
||||
#include <sql/sql_plugin.h>
|
||||
#include <sql/auth/auth_common.h>
|
||||
#endif
|
||||
#endif
|
||||
@@ -94,4 +95,9 @@ extern "C" char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int
|
||||
|
||||
#endif
|
||||
|
||||
//Define HAVE_SESS_CONNECT_ATTRS. We define it for mysql 5.6 and above
|
||||
#if (!defined(MARIADB_BASE_VERSION)) && MYSQL_VERSION_ID >= 50600
|
||||
#define HAVE_SESS_CONNECT_ATTRS 1
|
||||
#endif
|
||||
|
||||
#endif // MYSQL_INCL_H
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $# = 0 ]; then
|
||||
if [ $# = 0 ]
|
||||
then
|
||||
echo "Usage: $0 <mysqld executable> [optional mysqld symbols]"
|
||||
echo "Will extract offsets from mysqld. Requires gdb, md5sum and mysqld symbols."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#extract the version of mysqld
|
||||
# Extract the version of mysqld
|
||||
|
||||
FULL_MYVER=`$1 --version | grep -P -o 'Ver\s+[\w\.-]+'| awk '{print $2}'`
|
||||
FULL_MYVER=`$1 --version | grep -P -o 'Ver\s+[\w\.-]+'| awk '{ print $2 }'`
|
||||
|
||||
#extract the md5 digest
|
||||
# Extract the md5 digest
|
||||
|
||||
MYMD5=`md5sum -b $1 | awk -v Field=1 '{print $1}'`
|
||||
MYMD5=`md5sum -b $1 | awk -v Field=1 '{ print $1 }'`
|
||||
|
||||
MYVER="$FULL_MYVER"
|
||||
echo $FULL_MYVER | grep 'log' > /dev/null
|
||||
|
||||
|
||||
if [ $? = 0 ]; then
|
||||
MYVER=`echo "$MYVER" | grep -P -o '.+(?=-log)'`
|
||||
if echo $FULL_MYVER | grep 'log' > /dev/null
|
||||
then
|
||||
MYVER=`echo "$MYVER" | grep -P -o '.+(?=-log)'`
|
||||
fi
|
||||
|
||||
COMMAND_MEMBER=command
|
||||
@@ -30,26 +29,90 @@ HOST=host
|
||||
IP=ip
|
||||
PRIV_USER=priv_user
|
||||
DB=db
|
||||
CLIENT_CAPS="print_offset THD client_capabilities"
|
||||
|
||||
#in 5.6 command member is named m_command
|
||||
echo $MYVER | grep -P '^(5\.6|5\.7|10\.)' > /dev/null
|
||||
if [ $? = 0 ]; then
|
||||
# In 5.6 command member is named m_command
|
||||
if echo $MYVER | grep -P '^(5\.6|5\.7|10\.)' > /dev/null
|
||||
then
|
||||
COMMAND_MEMBER=m_command
|
||||
HAS_CONNECT_ATTRS=yes
|
||||
fi
|
||||
#in 5.7 thread_id changed to m_thread_id. main_security_ctx changed to m_main_security_ctx
|
||||
echo $MYVER | grep -P '^(5\.7)' > /dev/null
|
||||
if [ $? = 0 ]; then
|
||||
|
||||
CONNECT_ATTRS_CS=m_session_connect_attrs_cs
|
||||
# In 5.7 thread_id changed to m_thread_id. main_security_ctx changed to m_main_security_ctx
|
||||
if echo $MYVER | grep -P '^(5\.7)' > /dev/null
|
||||
then
|
||||
THREAD_ID=m_thread_id
|
||||
SEC_CONTEXT=m_main_security_ctx
|
||||
USER=m_user
|
||||
HOST=m_host
|
||||
IP=m_ip
|
||||
PRIV_USER=m_priv_user
|
||||
DB=m_db
|
||||
SEC_CONTEXT=m_main_security_ctx
|
||||
USER=m_user
|
||||
HOST=m_host
|
||||
IP=m_ip
|
||||
PRIV_USER=m_priv_user
|
||||
DB=m_db
|
||||
# client capabilities has moved out THD in 5.7. Set to 0
|
||||
CLIENT_CAPS='print_offset THD m_protocol'
|
||||
|
||||
# comment which holds plugin name for uninstall moved into
|
||||
# a separate object
|
||||
HAS_LEX_SQL_CMD=yes
|
||||
fi
|
||||
|
||||
# In 5.6.15 and up, 5.7 and mariabdb 10.0.11 and up, mariadb 10.1
|
||||
# m_session_connect_attrs_cs changed to m_session_connect_attrs_cs_number
|
||||
if echo $MYVER | grep -P '^(5\.7|10\.1|5\.6\.(1[5-9]|[2-9][0-9])|10.0.(1[1-9]|[2-9][0-9]))' > /dev/null
|
||||
then
|
||||
CONNECT_ATTRS_CS=m_session_connect_attrs_cs_number
|
||||
fi
|
||||
|
||||
CONNECT_ATTRS=""
|
||||
if [ -n "$HAS_CONNECT_ATTRS" ]
|
||||
then
|
||||
CONNECT_ATTRS="print_offset PFS_thread m_session_connect_attrs
|
||||
print_offset PFS_thread m_session_connect_attrs_length
|
||||
print_offset PFS_thread $CONNECT_ATTRS_CS
|
||||
"
|
||||
else
|
||||
CONNECT_ATTRS='printf ", 0, 0, 0"'
|
||||
fi
|
||||
|
||||
if echo $MYVER | grep -P '^5\.7' > /dev/null
|
||||
then
|
||||
if echo $MYVER | grep -P '^5\.7\.8' > /dev/null
|
||||
then
|
||||
FOUND_ROWS="print_offset THD limit_found_rows"
|
||||
else
|
||||
FOUND_ROWS="print_offset THD previous_found_rows"
|
||||
fi
|
||||
else
|
||||
FOUND_ROWS="print_offset THD limit_found_rows"
|
||||
fi
|
||||
|
||||
if echo $MYVER | grep -P '^5\.[15]' > /dev/null
|
||||
then
|
||||
SENT_ROW_COUNT='print_offset THD sent_row_count'
|
||||
else
|
||||
SENT_ROW_COUNT="print_offset THD m_sent_row_count"
|
||||
fi
|
||||
|
||||
if echo $MYVER | grep -P '^5\.1' > /dev/null
|
||||
then
|
||||
ROW_COUNT_FUNC='print_offset THD row_count_func'
|
||||
else
|
||||
ROW_COUNT_FUNC='print_offset THD m_row_count_func'
|
||||
fi
|
||||
|
||||
LEX_SQL=""
|
||||
if [ -n "$HAS_LEX_SQL_CMD" ]
|
||||
then
|
||||
LEX_SQL="print_offset LEX m_sql_cmd
|
||||
print_offset Sql_cmd_uninstall_plugin m_comment"
|
||||
else
|
||||
LEX_SQL='printf ", 0, 0"'
|
||||
fi
|
||||
|
||||
cat <<EOF > offsets.gdb
|
||||
set logging on
|
||||
set width 0
|
||||
define print_offset
|
||||
printf ", %d", (size_t)&((\$arg0*)0)->\$arg1
|
||||
end
|
||||
@@ -66,23 +129,34 @@ print_offset Security_context $IP
|
||||
print_offset Security_context $PRIV_USER
|
||||
print_offset THD $DB
|
||||
print_offset THD killed
|
||||
$CLIENT_CAPS
|
||||
$CONNECT_ATTRS
|
||||
print_offset THD net
|
||||
$LEX_SQL
|
||||
$FOUND_ROWS
|
||||
$SENT_ROW_COUNT
|
||||
$ROW_COUNT_FUNC
|
||||
printf "}"
|
||||
EOF
|
||||
|
||||
SYMPARAM=""
|
||||
if [ -n "$2" ]; then
|
||||
if [ -n "$2" ]
|
||||
then
|
||||
SYMPARAM="-s $2 -e"
|
||||
fi
|
||||
|
||||
which gdb > /dev/null 2>&1
|
||||
if [ $? != 0 ]; then
|
||||
if which gdb > /dev/null 2>&1
|
||||
then
|
||||
:
|
||||
else
|
||||
echo "ERROR: gdb not found. Make sure gdb is installed and on the path."
|
||||
exit 3;
|
||||
exit 3
|
||||
fi
|
||||
|
||||
gdb -n -q -batch -x offsets.gdb $SYMPARAM $1 > /dev/null 2>&1
|
||||
|
||||
if [ $? != 0 ]; then
|
||||
if gdb -n -q -batch -x offsets.gdb $SYMPARAM $1 > /dev/null 2>&1
|
||||
then
|
||||
:
|
||||
else
|
||||
echo "GDB failed!!!" > /dev/stderr
|
||||
exit 2
|
||||
fi
|
||||
@@ -91,7 +165,6 @@ OFFSETS=`cat gdb.txt`
|
||||
echo "//offsets for: $1 ($FULL_MYVER)"
|
||||
echo "$OFFSETS,"
|
||||
|
||||
#clean up
|
||||
# clean up
|
||||
rm gdb.txt
|
||||
rm offsets.gdb
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
// for definition of sockaddr_un
|
||||
#include <sys/un.h>
|
||||
#include <stdio_ext.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include "static_assert.h"
|
||||
|
||||
// utility macro to log also with a date as a prefix
|
||||
@@ -178,7 +180,7 @@ void Audit_handler::log_audit(ThdSesData *pThdData)
|
||||
return;
|
||||
}
|
||||
// sanity check that offsets match
|
||||
// we can also consider using secutiry context function to do some sanity checks
|
||||
// we can also consider using security 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);
|
||||
@@ -209,11 +211,11 @@ void Audit_handler::log_audit(ThdSesData *pThdData)
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_io);
|
||||
//get the io lock. After acquiring the lock do another check that we really need to start (maybe another thread did this already)
|
||||
if(!m_failed)
|
||||
if (!m_failed)
|
||||
{
|
||||
do_log = true;
|
||||
}
|
||||
else if(m_retry_interval > 0 &&
|
||||
else if (m_retry_interval > 0 &&
|
||||
difftime(time(NULL), m_last_retry_sec_ts) > m_retry_interval)
|
||||
{
|
||||
do_log = handler_start_nolock();
|
||||
@@ -362,7 +364,8 @@ bool Audit_io_handler::handler_start_internal()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Audit_io_handler::handler_log_audit(ThdSesData *pThdData) {
|
||||
bool Audit_io_handler::handler_log_audit(ThdSesData *pThdData)
|
||||
{
|
||||
return (m_formatter->event_format(pThdData, this) >= 0);
|
||||
}
|
||||
|
||||
@@ -557,7 +560,7 @@ static const char *thd_query_str(THD *thd, size_t *len)
|
||||
#elif defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID > 50140
|
||||
|
||||
extern "C" {
|
||||
MYSQL_LEX_STRING *thd_query_string(MYSQL_THD thd);
|
||||
MYSQL_LEX_STRING *thd_query_string(MYSQL_THD thd);
|
||||
}
|
||||
|
||||
static const char *thd_query_str(THD *thd, size_t *len)
|
||||
@@ -620,6 +623,7 @@ ssize_t Audit_json_formatter::start_msg_format(IWriter *writer)
|
||||
yajl_add_string_val(gen, "mysql-program", my_progname);
|
||||
yajl_add_string_val(gen, "mysql-socket", mysqld_unix_port);
|
||||
yajl_add_uint64(gen, "mysql-port", mysqld_port);
|
||||
yajl_add_uint64(gen, "server_pid", getpid());
|
||||
ssize_t res = -2;
|
||||
|
||||
yajl_gen_status stat = yajl_gen_map_close(gen); // close the object
|
||||
@@ -671,6 +675,97 @@ static const char *replace_in_string(THD *thd,
|
||||
return new_str;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SESS_CONNECT_ATTRS
|
||||
#include <storage/perfschema/pfs_instr.h>
|
||||
|
||||
//declare the function: parse_length_encoded_string from: storage/perfschema/table_session_connect.cc
|
||||
bool parse_length_encoded_string(const char **ptr,
|
||||
char *dest, uint dest_size,
|
||||
uint *copied_len,
|
||||
const char *start_ptr, uint input_length,
|
||||
bool copy_data,
|
||||
const CHARSET_INFO *from_cs,
|
||||
uint nchars_max);
|
||||
|
||||
/**
|
||||
* Code based upon read_nth_attribute of storage/perfschema/table_session_connect.cc
|
||||
* Only difference we do once loop and write out the attributes
|
||||
*/
|
||||
static void log_session_connect_attrs(yajl_gen gen, THD *thd)
|
||||
{
|
||||
PFS_thread * pfs = PFS_thread::get_current_thread();
|
||||
const char * connect_attrs = Audit_formatter::pfs_connect_attrs(pfs);
|
||||
const uint connect_attrs_length = Audit_formatter::pfs_connect_attrs_length(pfs);
|
||||
const CHARSET_INFO *connect_attrs_cs = Audit_formatter::pfs_connect_attrs_cs(pfs);
|
||||
|
||||
//sanity max attributes
|
||||
const uint max_idx = 32;
|
||||
uint idx;
|
||||
const char *ptr;
|
||||
bool array_start = false;
|
||||
if(!connect_attrs || !connect_attrs_length || !connect_attrs_cs)
|
||||
{
|
||||
//either offsets are wrong or not set
|
||||
return;
|
||||
}
|
||||
for (ptr= connect_attrs, idx= 0;
|
||||
(uint)(ptr - connect_attrs) < connect_attrs_length && idx <= max_idx;
|
||||
idx++)
|
||||
{
|
||||
const uint MAX_COPY_CHARS_NAME = 32;
|
||||
const uint MAX_COPY_CHARS_VAL = 256;
|
||||
//time 6 (max udf8 char length)
|
||||
char attr_name[MAX_COPY_CHARS_NAME*6];
|
||||
char attr_value[MAX_COPY_CHARS_VAL *6];
|
||||
uint copy_length, attr_name_length, attr_value_length;
|
||||
/* always do copying */
|
||||
bool fill_in_attr_name= true;
|
||||
bool fill_in_attr_value= true;
|
||||
|
||||
/* read the key */
|
||||
copy_length = 0;
|
||||
if (parse_length_encoded_string(&ptr,
|
||||
attr_name, array_elements(attr_name), ©_length,
|
||||
connect_attrs,
|
||||
connect_attrs_length,
|
||||
fill_in_attr_name,
|
||||
connect_attrs_cs, MAX_COPY_CHARS_NAME) || !copy_length)
|
||||
{
|
||||
//something went wrong or we are done
|
||||
break;
|
||||
}
|
||||
|
||||
attr_name_length = copy_length;
|
||||
/* read the value */
|
||||
copy_length = 0;
|
||||
if (parse_length_encoded_string(&ptr,
|
||||
attr_value, array_elements(attr_value), ©_length,
|
||||
connect_attrs,
|
||||
connect_attrs_length,
|
||||
fill_in_attr_value,
|
||||
connect_attrs_cs, MAX_COPY_CHARS_VAL) || !copy_length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
attr_value_length= copy_length;
|
||||
if(!array_start)
|
||||
{
|
||||
yajl_add_string(gen, "connect_attrs");
|
||||
yajl_gen_map_open(gen);
|
||||
array_start = true;
|
||||
}
|
||||
yajl_gen_string(gen, (const unsigned char*)attr_name, attr_name_length);
|
||||
yajl_gen_string(gen, (const unsigned char*)attr_value, attr_value_length);
|
||||
|
||||
} //close for loop
|
||||
if(array_start)
|
||||
{
|
||||
yajl_gen_map_close(gen);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer)
|
||||
{
|
||||
THD *thd = pThdData->getTHD();
|
||||
@@ -692,9 +787,79 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
|
||||
yajl_add_uint64(gen, "query-id", qid);
|
||||
yajl_add_string_val(gen, "user", pThdData->getUserName());
|
||||
yajl_add_string_val(gen, "priv_user", Audit_formatter::thd_inst_main_security_ctx_priv_user(thd));
|
||||
yajl_add_string_val(gen, "host", Audit_formatter::thd_inst_main_security_ctx_host(thd));
|
||||
yajl_add_string_val(gen, "ip", Audit_formatter::thd_inst_main_security_ctx_ip(thd));
|
||||
|
||||
// For backwards compatibility, we always send "host".
|
||||
// If there is no value, send the IP address
|
||||
const char *host = Audit_formatter::thd_inst_main_security_ctx_host(thd);
|
||||
if (host == NULL || *host == '\0')
|
||||
{
|
||||
host = Audit_formatter::thd_inst_main_security_ctx_ip(thd);
|
||||
}
|
||||
yajl_add_string_val(gen, "host", host);
|
||||
|
||||
if (m_write_client_capabilities)
|
||||
{
|
||||
ulong caps = Audit_formatter::thd_client_capabilities(thd);
|
||||
if (caps)
|
||||
{
|
||||
yajl_add_uint64(gen, "capabilities", caps);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_SESS_CONNECT_ATTRS
|
||||
if (m_write_sess_connect_attrs)
|
||||
{
|
||||
log_session_connect_attrs(gen, thd);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pThdData->getPeerPid() != 0) // Unix Domain Socket
|
||||
{
|
||||
if (m_write_socket_creds)
|
||||
{
|
||||
yajl_add_uint64(gen, "pid", pThdData->getPeerPid());
|
||||
if (pThdData->getOsUser() != NULL)
|
||||
{
|
||||
yajl_add_string_val(gen, "os_user", pThdData->getOsUser());
|
||||
}
|
||||
if (pThdData->getAppName() != NULL)
|
||||
{
|
||||
yajl_add_string_val(gen, "appname", pThdData->getAppName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pThdData->getPort() > 0) // TCP socket
|
||||
{
|
||||
yajl_add_uint64(gen, "client_port", pThdData->getPort());
|
||||
}
|
||||
|
||||
const char *cmd = pThdData->getCmdName();
|
||||
ulonglong rows = 0;
|
||||
|
||||
if (pThdData->getStatementSource() == ThdSesData::SOURCE_QUERY_CACHE)
|
||||
{
|
||||
// from the query cache
|
||||
rows = thd_found_rows(thd);
|
||||
}
|
||||
else if (strcasestr(cmd, "insert") != NULL ||
|
||||
strcasestr(cmd, "update") != NULL ||
|
||||
strcasestr(cmd, "delete") != NULL ||
|
||||
(strcasestr(cmd, "select") != NULL && thd_row_count_func(thd) > 0))
|
||||
{
|
||||
// m_row_count_func will be -1 for most selects but can be > 0, e.g. select into file
|
||||
rows = thd_row_count_func(thd);
|
||||
}
|
||||
else
|
||||
{
|
||||
rows = thd_sent_row_count(thd);
|
||||
}
|
||||
|
||||
if (rows != 0UL)
|
||||
{
|
||||
yajl_add_uint64(gen, "rows", rows);
|
||||
}
|
||||
|
||||
yajl_add_string_val(gen, "cmd", cmd);
|
||||
|
||||
// get objects
|
||||
@@ -820,13 +985,21 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
|
||||
return res;
|
||||
}
|
||||
|
||||
ThdSesData::ThdSesData(THD *pTHD)
|
||||
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_tableInf(NULL), m_index(0), m_isSqlCmd(false),
|
||||
m_port(-1), m_source(source)
|
||||
{
|
||||
m_CmdName = retrieve_command (m_pThd, m_isSqlCmd);
|
||||
m_UserName = retrieve_user (m_pThd);
|
||||
|
||||
m_peerInfo = retrieve_peerinfo(m_pThd);
|
||||
if (m_peerInfo && m_peerInfo->pid == 0)
|
||||
{
|
||||
// not UDS, get remote port
|
||||
m_port = Audit_formatter::thd_client_port(m_pThd);
|
||||
}
|
||||
}
|
||||
|
||||
bool ThdSesData::startGetObjects()
|
||||
@@ -940,6 +1113,21 @@ bool ThdSesData::getNextObject(const char **db_name, const char **obj_name, cons
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned long ThdSesData::getPeerPid() const
|
||||
{
|
||||
return (m_peerInfo != NULL ? m_peerInfo->pid : 0L);
|
||||
}
|
||||
|
||||
const char *ThdSesData::getAppName() const
|
||||
{
|
||||
return (m_peerInfo != NULL ? m_peerInfo->appName : NULL);
|
||||
}
|
||||
|
||||
const char *ThdSesData::getOsUser() const
|
||||
{
|
||||
return (m_peerInfo != NULL ? m_peerInfo->osUser : NULL);
|
||||
}
|
||||
|
||||
pcre *Audit_json_formatter::regex_compile(const char *str)
|
||||
{
|
||||
const char *error;
|
||||
|
||||
2045
src/audit_offsets.cc
2045
src/audit_offsets.cc
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@
|
||||
#include "hot_patch.h"
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "audit_handler.h"
|
||||
#include <string.h>
|
||||
@@ -84,6 +85,14 @@ static int num_record_objs = 0;
|
||||
static int num_whitelist_users = 0;
|
||||
static SHOW_VAR com_status_vars_array [MAX_COM_STATUS_VARS_RECORDS] = {{0}};
|
||||
|
||||
enum before_after_enum {
|
||||
AUDIT_AFTER = 0, // default
|
||||
AUDIT_BEFORE,
|
||||
AUDIT_BOTH
|
||||
};
|
||||
|
||||
static ulong before_after_mode = AUDIT_AFTER;
|
||||
|
||||
// regex stuff
|
||||
static char password_masking_regex_check_buff[4096] = {0};
|
||||
static char * password_masking_regex_string = NULL;
|
||||
@@ -152,6 +161,46 @@ static MYSQL_THDVAR_ULONG(query_cache_table_list,
|
||||
#endif
|
||||
1);
|
||||
|
||||
|
||||
static MYSQL_THDVAR_BOOL(set_peer_cred,
|
||||
PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT,
|
||||
"track if peer credential information is set",
|
||||
NULL, NULL, 0);
|
||||
|
||||
static MYSQL_THDVAR_BOOL(peer_is_uds,
|
||||
PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT,
|
||||
"track if client is connected on Unix Domain Socket",
|
||||
NULL, NULL, 0);
|
||||
|
||||
// We use a THDVAR_STR to store the PeerInfo struct for this thread.
|
||||
// In order to get MySQL to allocate storage correctly, we have to
|
||||
// fool it into thinking that the storage holds a C string. To do so,
|
||||
// we create a char array of the right size and use that as the initial
|
||||
// value. Then in the constructor routines, below, we initialize the
|
||||
// contents to look like a C string with a bunch of '0' characters,
|
||||
// terminated by a final '\0'.
|
||||
char peer_info_init_value[sizeof(struct PeerInfo) + 4];
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
static MYSQL_THDVAR_ULONG(peer_info,
|
||||
PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT,
|
||||
"Pointer to peer info data",
|
||||
NULL, NULL, 0, 0,
|
||||
#ifdef __x86_64__
|
||||
0xffffffffffffff,
|
||||
#else
|
||||
0xffffffff,
|
||||
#endif
|
||||
1);
|
||||
#else // NOT mariadb
|
||||
static MYSQL_THDVAR_STR(peer_info,
|
||||
PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_READONLY |
|
||||
PLUGIN_VAR_MEMALLOC,
|
||||
"Info related to client process",
|
||||
NULL, NULL, peer_info_init_value);
|
||||
#endif
|
||||
|
||||
|
||||
THDPRINTED *GetThdPrintedList(THD *thd)
|
||||
{
|
||||
THDPRINTED *pThdPrintedList= (THDPRINTED*) THDVAR(thd, is_thd_printed_list);
|
||||
@@ -163,6 +212,173 @@ THDPRINTED *GetThdPrintedList(THD *thd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void initializePeerCredentials(THD *pThd)
|
||||
{
|
||||
int sock;
|
||||
struct stat sbuf;
|
||||
struct ucred cred;
|
||||
socklen_t cred_len = sizeof(cred);
|
||||
char buf[BUFSIZ];
|
||||
struct passwd pwd, *pwbuf = NULL;
|
||||
char *username = NULL;
|
||||
int fd;
|
||||
PeerInfo *peer;
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
if (THDVAR(pThd, peer_info) == 0)
|
||||
{
|
||||
peer = (PeerInfo *) malloc(sizeof(PeerInfo));
|
||||
if (peer)
|
||||
{
|
||||
memset(peer, 0, sizeof(PeerInfo));
|
||||
THDVAR(pThd, peer_info) = (ulong) peer;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
peer = (PeerInfo *) THDVAR(pThd, peer_info);
|
||||
}
|
||||
#else
|
||||
// zero out thread local copy of PeerInfo
|
||||
peer = (PeerInfo *) THDVAR(pThd, peer_info);
|
||||
if (peer != NULL)
|
||||
{
|
||||
memset(peer, 0, sizeof(PeerInfo));
|
||||
}
|
||||
#endif
|
||||
|
||||
// get the NET structure
|
||||
sock = Audit_formatter::thd_client_fd(pThd);
|
||||
// These tests are not chained so that we can add
|
||||
// debug prints if necessary.
|
||||
if (sock < 0)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Is it a Unix Domain socket?
|
||||
if (fstat(sock, &sbuf) < 0)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((sbuf.st_mode & S_IFMT) != S_IFSOCK)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
// At this point, we know we have a Unix domain socket.
|
||||
if (! json_formatter.m_write_socket_creds)
|
||||
{
|
||||
// We need to set this, so that we don't send the
|
||||
// client port, but we don't bother getting the command
|
||||
// name and user name, since they won't be sent.
|
||||
THDVAR(pThd, peer_is_uds) = TRUE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Do a SO_PEERCRED
|
||||
if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) < 0)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cred_len != sizeof(cred))
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (peer == NULL)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Set PID
|
||||
peer->pid = cred.pid;
|
||||
|
||||
// Get OS user name
|
||||
getpwuid_r(cred.uid, & pwd, buf, sizeof(buf), & pwbuf);
|
||||
if (pwbuf == NULL)
|
||||
{
|
||||
// no name, send UID
|
||||
snprintf(buf, sizeof(buf) - 1, "%lu", (unsigned long) cred.uid);
|
||||
username = buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
username = pwd.pw_name;
|
||||
}
|
||||
|
||||
strncpy(peer->osUser, username, PeerInfo::MAX_USER_NAME_LEN);
|
||||
peer->osUser[PeerInfo::MAX_USER_NAME_LEN] = '\0';
|
||||
|
||||
// Get the progran name out of /proc
|
||||
snprintf(buf, sizeof(buf) - 1, "/proc/%d/cmdline", cred.pid);
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
char data[PATH_MAX+1];
|
||||
|
||||
ssize_t count = read(fd, data, sizeof(data) - 1);
|
||||
if (count > 0)
|
||||
{
|
||||
data[count] = '\0'; // just in case
|
||||
|
||||
if (strlen(data) <= PeerInfo::MAX_APP_NAME_LEN)
|
||||
{
|
||||
strcpy(peer->appName, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// take last 128 characters, typically will be
|
||||
// .../x/y/appname
|
||||
char *cp = data + strlen(data) - PeerInfo::MAX_APP_NAME_LEN;
|
||||
|
||||
strncpy(peer->appName, cp, PeerInfo::MAX_APP_NAME_LEN);
|
||||
peer->appName[PeerInfo::MAX_APP_NAME_LEN] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// in case of errors:
|
||||
if (peer->appName[0] == '\0')
|
||||
{
|
||||
snprintf(peer->appName, sizeof(peer->appName) - 1, "pid:%d", cred.pid);
|
||||
}
|
||||
|
||||
// set that we have a UDS, so that THD vars will be used
|
||||
THDVAR(pThd, peer_is_uds) = TRUE;
|
||||
|
||||
done:
|
||||
THDVAR(pThd, set_peer_cred) = TRUE;
|
||||
}
|
||||
|
||||
PeerInfo *retrieve_peerinfo(THD *thd)
|
||||
{
|
||||
if (! THDVAR(thd, set_peer_cred))
|
||||
{
|
||||
initializePeerCredentials(thd);
|
||||
}
|
||||
|
||||
if (json_formatter.m_write_socket_creds)
|
||||
{
|
||||
PeerInfo *peer = (PeerInfo *) THDVAR(thd, peer_info);
|
||||
|
||||
if (THDVAR(thd, peer_is_uds) && peer != NULL);
|
||||
{
|
||||
return peer;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int check_array(const char *cmds[],const char *array, int length)
|
||||
{
|
||||
for (int k = 0; array[k * length] !='\0';k++)
|
||||
@@ -224,6 +440,23 @@ static my_bool check_do_password_masking(const char * cmd)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void do_delay(ThdSesData *pThdData)
|
||||
{
|
||||
if (delay_ms_val > 0)
|
||||
{
|
||||
const char *cmd = pThdData->getCmdName();
|
||||
const char *cmds[2];
|
||||
cmds[0] = cmd;
|
||||
cmds[1] = NULL;
|
||||
int delay = check_array(cmds, (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void audit(ThdSesData *pThdData)
|
||||
{
|
||||
THDPRINTED *pThdPrintedList = GetThdPrintedList(pThdData->getTHD());
|
||||
@@ -302,7 +535,7 @@ static void audit(ThdSesData *pThdData)
|
||||
}
|
||||
}
|
||||
|
||||
if (pThdPrintedList && pThdPrintedList->cur_index < MAX_NUM_QUEUE_ELEM)
|
||||
if (before_after_mode != AUDIT_BOTH && pThdPrintedList && pThdPrintedList->cur_index < MAX_NUM_QUEUE_ELEM)
|
||||
{
|
||||
// audit the event if we haven't done so yet or in the case of prepare_sql
|
||||
// we audit as the test "test select" doesn't go through mysql_execute_command
|
||||
@@ -320,20 +553,6 @@ static void audit(ThdSesData *pThdData)
|
||||
{
|
||||
Audit_handler::log_audit_all(pThdData);
|
||||
}
|
||||
|
||||
if (delay_ms_val > 0)
|
||||
{
|
||||
const char * cmd = pThdData->getCmdName();
|
||||
const char *cmds[2];
|
||||
cmds[0] = cmd;
|
||||
cmds[1] = NULL;
|
||||
int delay = check_array(cmds, (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -422,13 +641,13 @@ static int audit_send_result_to_client(Query_cache *pthis, THD *thd, const LEX_
|
||||
}
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||
res = trampoline_send_result_to_client (pthis,thd, sql, query_length);
|
||||
res = trampoline_send_result_to_client(pthis,thd, sql, query_length);
|
||||
#else
|
||||
res = trampoline_send_result_to_client (pthis, thd, sql_query);
|
||||
res = trampoline_send_result_to_client(pthis, thd, sql_query);
|
||||
#endif
|
||||
if (res)
|
||||
{
|
||||
ThdSesData thd_data(thd);
|
||||
ThdSesData thd_data(thd, ThdSesData::SOURCE_QUERY_CACHE);
|
||||
audit(&thd_data);
|
||||
}
|
||||
THDVAR(thd, query_cache_table_list) = 0;
|
||||
@@ -456,7 +675,9 @@ static int audit_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint f
|
||||
res = trampoline_open_tables (thd, start, counter, flags);
|
||||
#endif
|
||||
// only log if thread id or query id is non 0 (otherwise this is comming from startup activity)
|
||||
if (Audit_formatter::thd_inst_thread_id(thd) || Audit_formatter::thd_inst_query_id(thd))
|
||||
if ( (before_after_mode == AUDIT_BEFORE || before_after_mode == AUDIT_BOTH)
|
||||
&& (Audit_formatter::thd_inst_thread_id(thd)
|
||||
|| Audit_formatter::thd_inst_query_id(thd)))
|
||||
{
|
||||
ThdSesData thd_data (thd);
|
||||
audit(&thd_data);
|
||||
@@ -473,7 +694,7 @@ 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);
|
||||
ThdSesData ThdData(thd);
|
||||
if (strcasestr(ThdData.getCmdName(), "show_fields") == NULL)
|
||||
{
|
||||
audit(&ThdData);
|
||||
@@ -482,7 +703,6 @@ static void audit_post_execute(THD * thd)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Plugin descriptor
|
||||
*/
|
||||
@@ -503,6 +723,15 @@ static int audit_notify(THD *thd, mysql_event_class_t event_class,
|
||||
const void * event)
|
||||
#endif
|
||||
{
|
||||
if (thd == NULL) // can happen in replication setup
|
||||
{
|
||||
#if ! defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
return 0; // return success, keep MySQL going
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (MYSQL_AUDIT_GENERAL_CLASS == event_class)
|
||||
{
|
||||
const struct mysql_event_general *event_general =
|
||||
@@ -544,7 +773,12 @@ static int audit_notify(THD *thd, mysql_event_class_t event_class,
|
||||
const struct mysql_event_connection *event_connection =
|
||||
(const struct mysql_event_connection *) event;
|
||||
// only audit for connect and change_user. disconnect is caught by general event
|
||||
if (event_connection->event_subclass != MYSQL_AUDIT_CONNECTION_DISCONNECT)
|
||||
if (event_connection->event_subclass != MYSQL_AUDIT_CONNECTION_DISCONNECT
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
// in pre-authenticate, user info etc is empty. don't log it
|
||||
&& event_connection->event_subclass != MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE
|
||||
#endif
|
||||
)
|
||||
{
|
||||
ThdSesData ThdData(thd);
|
||||
audit(&ThdData);
|
||||
@@ -586,6 +820,13 @@ static struct st_mysql_audit audit_plugin =
|
||||
// some extern definitions which are not in include files
|
||||
extern void log_slow_statement(THD *thd);
|
||||
extern int mysql_execute_command(THD *thd);
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
extern void end_connection(THD *thd);
|
||||
static int (*trampoline_end_connection)(THD *thd) = NULL;
|
||||
static unsigned int trampoline_end_connection_size = 0;
|
||||
#endif
|
||||
|
||||
#if MYSQL_VERSION_ID >= 50505
|
||||
// in 5.5 builtins is named differently
|
||||
#define mysqld_builtins mysql_mandatory_plugins
|
||||
@@ -649,6 +890,15 @@ void remove_hot_functions()
|
||||
target_function = (void*)
|
||||
(int (*)(THD *thd, bool first_level)) &mysql_execute_command;
|
||||
#endif
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
target_function = (void*) end_connection;
|
||||
remove_hot_patch_function(target_function,
|
||||
(void*) trampoline_end_connection,
|
||||
trampoline_end_connection_size, true);
|
||||
trampoline_end_connection_size = 0;
|
||||
#endif
|
||||
|
||||
remove_hot_patch_function(target_function,
|
||||
(void*) trampoline_mysql_execute_command,
|
||||
trampoline_mysql_execute_size, true);
|
||||
@@ -663,7 +913,12 @@ int is_remove_patches(ThdSesData *pThdData)
|
||||
LEX *pLex = Audit_formatter::thd_lex(pThdData->getTHD());
|
||||
if (pThdData->getTHD() && pLex != NULL && strncasecmp(cmd, sUninstallPlugin, strlen(sUninstallPlugin)) == 0)
|
||||
{
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||
LEX_STRING Lex_comment = *(LEX_STRING*)(((unsigned char *) pLex) + Audit_formatter::thd_offsets.lex_comment);
|
||||
#else
|
||||
Sql_cmd_uninstall_plugin *up = Audit_formatter::lex_sql_cmd(pLex);
|
||||
LEX_STRING Lex_comment = *(LEX_STRING*)(((unsigned char *) up) + Audit_formatter::thd_offsets.uninstall_cmd_comment);
|
||||
#endif
|
||||
if (strncasecmp(Lex_comment.str, "AUDIT", 5) == 0)
|
||||
{
|
||||
if (! uninstall_plugin_enable)
|
||||
@@ -719,13 +974,18 @@ static int audit_mysql_execute_command(THD *thd)
|
||||
ThdSesData thd_data(thd);
|
||||
const char *cmd = thd_data.getCmdName();
|
||||
|
||||
if (strcasestr(cmd, "alter") != NULL ||
|
||||
strcasestr(cmd, "drop") != NULL ||
|
||||
strcasestr(cmd, "create") != NULL ||
|
||||
strcasestr(cmd, "truncate") != NULL ||
|
||||
strcasestr(cmd, "rename") != NULL)
|
||||
do_delay(& thd_data);
|
||||
|
||||
if (before_after_mode == AUDIT_BEFORE || before_after_mode == AUDIT_BOTH)
|
||||
{
|
||||
audit(&thd_data);
|
||||
if (strcasestr(cmd, "alter") != NULL ||
|
||||
strcasestr(cmd, "drop") != NULL ||
|
||||
strcasestr(cmd, "create") != NULL ||
|
||||
strcasestr(cmd, "truncate") != NULL ||
|
||||
strcasestr(cmd, "rename") != NULL)
|
||||
{
|
||||
audit(&thd_data);
|
||||
}
|
||||
}
|
||||
|
||||
int res;
|
||||
@@ -759,7 +1019,11 @@ static int audit_mysql_execute_command(THD *thd)
|
||||
}
|
||||
}
|
||||
|
||||
audit(&thd_data);
|
||||
|
||||
if (before_after_mode == AUDIT_AFTER || before_after_mode == AUDIT_BOTH)
|
||||
{
|
||||
audit(&thd_data);
|
||||
}
|
||||
|
||||
if (pThdPrintedList && pThdPrintedList->cur_index > 0)
|
||||
{
|
||||
@@ -808,6 +1072,24 @@ static bool audit_acl_authenticate(THD *thd, uint connect_errors, uint com_chang
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
static void audit_end_connection(THD *thd)
|
||||
{
|
||||
#if MYSQL_VERSION_ID < 50600
|
||||
ThdSesData thd_data(thd);
|
||||
thd_data.setCmdName("Quit");
|
||||
audit(&thd_data);
|
||||
#endif
|
||||
PeerInfo *peer = (PeerInfo *) THDVAR(thd, peer_info);
|
||||
if (peer)
|
||||
{
|
||||
free(peer);
|
||||
THDVAR(thd, peer_info) = 0;
|
||||
}
|
||||
trampoline_end_connection(thd);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool parse_thd_offsets_string (char *poffsets_string)
|
||||
{
|
||||
char offset_str[2048] = {0};
|
||||
@@ -874,6 +1156,14 @@ static bool parse_thd_offsets_string (char *poffsets_string)
|
||||
|
||||
static bool validate_offsets(const ThdOffsets *offset)
|
||||
{
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
if (offset->lex_m_sql_command == 0 || offset->uninstall_cmd_comment == 0)
|
||||
{
|
||||
sql_print_error("%s Offsets: missing offsets for checking 'uninstall plugin'", log_prefix);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// check that offsets are actually correct. We use a buff of memory as a dummy THD (32K is high enough)
|
||||
char buf[32*1024] = {0};
|
||||
THD *thd = (THD *)buf;
|
||||
@@ -1038,9 +1328,9 @@ 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", 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", log_prefix,
|
||||
Audit_formatter::thd_offsets.query_id,
|
||||
Audit_formatter::thd_offsets.thread_id,
|
||||
Audit_formatter::thd_offsets.main_security_ctx,
|
||||
@@ -1052,7 +1342,18 @@ static int setup_offsets()
|
||||
Audit_formatter::thd_offsets.sec_ctx_ip,
|
||||
Audit_formatter::thd_offsets.sec_ctx_priv_user,
|
||||
Audit_formatter::thd_offsets.db,
|
||||
Audit_formatter::thd_offsets.killed);
|
||||
Audit_formatter::thd_offsets.killed,
|
||||
Audit_formatter::thd_offsets.client_capabilities,
|
||||
Audit_formatter::thd_offsets.pfs_connect_attrs,
|
||||
Audit_formatter::thd_offsets.pfs_connect_attrs_length,
|
||||
Audit_formatter::thd_offsets.pfs_connect_attrs_cs,
|
||||
Audit_formatter::thd_offsets.net,
|
||||
Audit_formatter::thd_offsets.lex_m_sql_command,
|
||||
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
|
||||
);
|
||||
|
||||
if (! validate_offsets(&Audit_formatter::thd_offsets))
|
||||
{
|
||||
@@ -1134,10 +1435,43 @@ static int setup_offsets()
|
||||
decoffsets.thread_id -= dec;
|
||||
decoffsets.main_security_ctx -= dec;
|
||||
decoffsets.command -= dec;
|
||||
if(decoffsets.killed)
|
||||
{
|
||||
decoffsets.killed -= dec;
|
||||
}
|
||||
if(decoffsets.client_capabilities)
|
||||
{
|
||||
decoffsets.client_capabilities -= dec;
|
||||
}
|
||||
if(decoffsets.net)
|
||||
{
|
||||
decoffsets.net -= dec;
|
||||
}
|
||||
if (decoffsets.lex_m_sql_command)
|
||||
{
|
||||
decoffsets.lex_m_sql_command -= dec;
|
||||
}
|
||||
if (decoffsets.uninstall_cmd_comment)
|
||||
{
|
||||
decoffsets.uninstall_cmd_comment -= dec;
|
||||
}
|
||||
if (decoffsets.found_rows)
|
||||
{
|
||||
decoffsets.found_rows -= dec;
|
||||
}
|
||||
if (decoffsets.sent_row_count)
|
||||
{
|
||||
decoffsets.sent_row_count -= dec;
|
||||
}
|
||||
if (decoffsets.row_count_func)
|
||||
{
|
||||
decoffsets.row_count_func -= 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",
|
||||
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",
|
||||
log_prefix, dec, offset->version, offset->md5digest,
|
||||
Audit_formatter::thd_offsets.query_id,
|
||||
Audit_formatter::thd_offsets.thread_id,
|
||||
@@ -1148,7 +1482,19 @@ static int setup_offsets()
|
||||
Audit_formatter::thd_offsets.sec_ctx_user,
|
||||
Audit_formatter::thd_offsets.sec_ctx_host,
|
||||
Audit_formatter::thd_offsets.sec_ctx_ip,
|
||||
Audit_formatter::thd_offsets.sec_ctx_priv_user);
|
||||
Audit_formatter::thd_offsets.sec_ctx_priv_user,
|
||||
Audit_formatter::thd_offsets.killed,
|
||||
Audit_formatter::thd_offsets.client_capabilities,
|
||||
Audit_formatter::thd_offsets.pfs_connect_attrs,
|
||||
Audit_formatter::thd_offsets.pfs_connect_attrs_length,
|
||||
Audit_formatter::thd_offsets.pfs_connect_attrs_cs,
|
||||
Audit_formatter::thd_offsets.net,
|
||||
Audit_formatter::thd_offsets.lex_m_sql_command,
|
||||
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
|
||||
);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@@ -1165,7 +1511,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",
|
||||
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",
|
||||
log_prefix, inc, offset->version, offset->md5digest,
|
||||
Audit_formatter::thd_offsets.query_id,
|
||||
Audit_formatter::thd_offsets.thread_id,
|
||||
@@ -1176,7 +1522,19 @@ static int setup_offsets()
|
||||
Audit_formatter::thd_offsets.sec_ctx_user,
|
||||
Audit_formatter::thd_offsets.sec_ctx_host,
|
||||
Audit_formatter::thd_offsets.sec_ctx_ip,
|
||||
Audit_formatter::thd_offsets.sec_ctx_priv_user);
|
||||
Audit_formatter::thd_offsets.sec_ctx_priv_user,
|
||||
Audit_formatter::thd_offsets.killed,
|
||||
Audit_formatter::thd_offsets.client_capabilities,
|
||||
Audit_formatter::thd_offsets.pfs_connect_attrs,
|
||||
Audit_formatter::thd_offsets.pfs_connect_attrs_length,
|
||||
Audit_formatter::thd_offsets.pfs_connect_attrs_cs,
|
||||
Audit_formatter::thd_offsets.net,
|
||||
Audit_formatter::thd_offsets.lex_m_sql_command,
|
||||
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
|
||||
);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
@@ -1207,11 +1565,14 @@ const char *retrieve_command(THD *thd, bool &is_sql_cmd)
|
||||
}
|
||||
|
||||
const int sql_command = thd_sql_command(thd);
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100108
|
||||
if (command == COM_QUERY && sql_command >= 0 && sql_command < SQLCOM_END)
|
||||
#define MAX_SQL_COM_INDEX SQLCOM_END
|
||||
#else
|
||||
if (command != COM_STMT_PREPARE && sql_command >= 0 && sql_command < MAX_COM_STATUS_VARS_RECORDS)
|
||||
#define MAX_SQL_COM_INDEX MAX_COM_STATUS_VARS_RECORDS
|
||||
#endif
|
||||
|
||||
if (command != COM_STMT_PREPARE && sql_command >= 0 && sql_command < MAX_SQL_COM_INDEX)
|
||||
{
|
||||
is_sql_cmd = true;
|
||||
cmd = com_status_vars_array[sql_command].name;
|
||||
@@ -1345,7 +1706,7 @@ static int string_to_array(const void *save, void *array, int rows, int length)
|
||||
|
||||
__attribute__ ((noinline)) static void trampoline_dummy_func_for_mem()
|
||||
{
|
||||
TRAMPOLINE_NOP_DEF
|
||||
TRAMPOLINE_NOP_DEF
|
||||
}
|
||||
|
||||
// holds memory used for trampoline
|
||||
@@ -1601,12 +1962,35 @@ static int audit_plugin_init(void *p)
|
||||
log_prefix, MYSQL_AUDIT_PLUGIN_VERSION,
|
||||
MYSQL_AUDIT_PLUGIN_REVISION, arch, interface_ver, interface_ver,
|
||||
server_version);
|
||||
|
||||
// setup our offsets.
|
||||
|
||||
if (setup_offsets() != 0)
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if(!Audit_formatter::thd_offsets.client_capabilities)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s offsets for client_capabilities not defined. client_capabilities will not be logged.",
|
||||
log_prefix);
|
||||
}
|
||||
#ifdef HAVE_SESS_CONNECT_ATTRS
|
||||
if(!Audit_formatter::thd_offsets.pfs_connect_attrs ||
|
||||
!Audit_formatter::thd_offsets.pfs_connect_attrs_length ||
|
||||
!Audit_formatter::thd_offsets.pfs_connect_attrs_cs)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s offsets for sess_connect_attrs not defined. sess_connect_attrs will not be logged.",
|
||||
log_prefix);
|
||||
}
|
||||
#endif
|
||||
if (!Audit_formatter::thd_offsets.net)
|
||||
{
|
||||
sql_print_error("%s offset for NET structure not defined. peer attributes will not be logged.",
|
||||
log_prefix);
|
||||
}
|
||||
|
||||
if (delay_cmds_string != NULL)
|
||||
{
|
||||
delay_cmds_string_update(NULL, NULL, NULL, &delay_cmds_string);
|
||||
@@ -1627,11 +2011,11 @@ static int audit_plugin_init(void *p)
|
||||
{
|
||||
record_objs_string_update_extended(NULL, NULL, NULL, &record_objs_string);
|
||||
}
|
||||
if (NULL != password_masking_cmds_string)
|
||||
if (password_masking_cmds_string != NULL)
|
||||
{
|
||||
password_masking_cmds_string_update(NULL, NULL, NULL, &password_masking_cmds_string);
|
||||
}
|
||||
if (NULL != password_masking_regex_string)
|
||||
if (password_masking_regex_string != NULL)
|
||||
{
|
||||
password_masking_regex_string_update(NULL, NULL, NULL, &password_masking_regex_string);
|
||||
}
|
||||
@@ -1671,8 +2055,9 @@ static int audit_plugin_init(void *p)
|
||||
// align our trampoline mem on its own page
|
||||
const unsigned long page_size = GETPAGESIZE();
|
||||
const unsigned long std_page_size = 4096;
|
||||
bool use_static_memory = (page_size <= std_page_size);
|
||||
bool use_static_memory = (page_size <= std_page_size);
|
||||
int mmap_flags = MAP_PRIVATE|MAP_ANONYMOUS;
|
||||
trampoline_mem = NULL;
|
||||
|
||||
#ifdef __x86_64__
|
||||
size_t func_in_mysqld = (size_t)log_slow_statement;
|
||||
@@ -1680,33 +2065,47 @@ static int audit_plugin_init(void *p)
|
||||
if (func_in_mysqld < INT_MAX && func_in_plugin > INT_MAX)
|
||||
{
|
||||
// See comment about IndirectJump in hot_patch.cc.
|
||||
mmap_flags |= MAP_32BIT;
|
||||
use_static_memory = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (use_static_memory)
|
||||
{
|
||||
// use static executable memory we alocated via trampoline_dummy_func_for_mem
|
||||
DATATYPE_ADDRESS addrs = (DATATYPE_ADDRESS)trampoline_dummy_func_for_mem + (page_size - 1);
|
||||
trampoline_mem = (void*)(addrs & ~(page_size - 1));
|
||||
sql_print_information(
|
||||
"%s mem func addr: %p mem start addr: %p page size: %ld",
|
||||
log_prefix, trampoline_dummy_func_for_mem, trampoline_mem, page_size);
|
||||
}
|
||||
else // big pages for some reason. allocate mem using mmap
|
||||
{
|
||||
trampoline_mem = mmap(NULL, page_size, PROT_READ|PROT_EXEC, mmap_flags, -1, 0);
|
||||
//mmap_flags |= MAP_32BIT;
|
||||
trampoline_mem = mmap(NULL, page_size, PROT_READ|PROT_EXEC, mmap_flags | MAP_32BIT, -1, 0);
|
||||
if (MAP_FAILED == trampoline_mem)
|
||||
{
|
||||
sql_print_error("%s unable to mmap memory size: %lu, errno: %d. Aborting.",
|
||||
log_prefix, page_size, errno);
|
||||
DBUG_RETURN(1);
|
||||
trampoline_mem = NULL;
|
||||
sql_print_information("%s unable to mmap 32bit memory size: %lu, errno: %d. This may happen when 32bit address space is used up. Will try static and regular mmap...",
|
||||
log_prefix, page_size, errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_print_information(
|
||||
"%s mem via mmap: %p page size: %ld", log_prefix, trampoline_mem, page_size);
|
||||
"%s mem via 32bit mmap: %p page size: %ld", log_prefix, trampoline_mem, page_size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!trampoline_mem)
|
||||
{
|
||||
if (use_static_memory)
|
||||
{
|
||||
// use static executable memory we alocated via trampoline_dummy_func_for_mem
|
||||
DATATYPE_ADDRESS addrs = (DATATYPE_ADDRESS)trampoline_dummy_func_for_mem + (page_size - 1);
|
||||
trampoline_mem = (void*)(addrs & ~(page_size - 1));
|
||||
sql_print_information(
|
||||
"%s mem func addr: %p mem start addr: %p page size: %ld",
|
||||
log_prefix, trampoline_dummy_func_for_mem, trampoline_mem, page_size);
|
||||
}
|
||||
else // big pages allocate mem using mmap
|
||||
{
|
||||
trampoline_mem = mmap(NULL, page_size, PROT_READ|PROT_EXEC, mmap_flags , -1, 0);
|
||||
if (MAP_FAILED == trampoline_mem)
|
||||
{
|
||||
trampoline_mem = NULL;
|
||||
sql_print_error("%s unable to mmap 32bit memory size: %lu, errno: %d. Abborting",
|
||||
log_prefix, page_size, errno);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_print_information(
|
||||
"%s mem via mmap: %p page size: %ld", log_prefix, trampoline_mem, page_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
trampoline_mem_free = trampoline_mem;
|
||||
@@ -1785,10 +2184,21 @@ static int audit_plugin_init(void *p)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
target_function = (void*) end_connection;
|
||||
if (do_hot_patch((void **)&trampoline_end_connection, &trampoline_end_connection_size,
|
||||
(void *)target_function, (void *)audit_end_connection, "end_connection"))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (set_com_status_vars_array () != 0)
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
sql_print_information("%s Init completed successfully.", log_prefix);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@@ -1872,6 +2282,20 @@ static void json_log_socket_enable(THD *thd, struct st_mysql_sys_var *var,
|
||||
|
||||
// setup sysvars which update directly the relevant plugins
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(socket_creds, json_formatter.m_write_socket_creds,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT log socket credentials from Unix Domain Socket. Enable|Disable. Default enabled.", NULL, NULL, 1);
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(client_capabilities, json_formatter.m_write_client_capabilities,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT log client capabilities. Enable|Disable. Default disabled.", NULL, NULL, 0);
|
||||
|
||||
#ifdef HAVE_SESS_CONNECT_ATTRS
|
||||
static MYSQL_SYSVAR_BOOL(sess_connect_attrs, json_formatter.m_write_sess_connect_attrs,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT log session connect attributes (see: performance_schema.session_connect_attrs table). Enable|Disable. Default enabled.", NULL, NULL, 1);
|
||||
#endif
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(header_msg, json_formatter.m_write_start_msg,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT write header message at start of logging or file flush Enable|Disable. Default enabled.", NULL, NULL, 1);
|
||||
@@ -1884,6 +2308,7 @@ static MYSQL_SYSVAR_STR(json_log_file, json_file_handler.m_io_dest,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
|
||||
"AUDIT plugin json log file name",
|
||||
NULL, NULL, "mysql-audit.json");
|
||||
|
||||
static MYSQL_SYSVAR_LONG(json_file_bufsize, json_file_handler.m_bufsize,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT plugin json log file buffer size. Buffer size in bytes (larger size may improve performance). 0 = use default size, 1 = no buffering. If changed during runtime need to perform a flush for the new value to take affect.",
|
||||
@@ -1969,7 +2394,7 @@ static MYSQL_SYSVAR_STR(delay_cmds, delay_cmds_string,
|
||||
static MYSQL_SYSVAR_STR(whitelist_cmds, whitelist_cmds_string,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT plugin whitelisted commands for which queries are not recorded, comma separated",
|
||||
NULL, whitelist_cmds_string_update, "BEGIN,COMMIT");
|
||||
NULL, whitelist_cmds_string_update, "BEGIN,COMMIT,PING");
|
||||
static MYSQL_SYSVAR_STR(record_cmds, record_cmds_string,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT plugin commands for which queries are recorded, comma separated. If set then only queries of these commands will be recorded.",
|
||||
@@ -1979,7 +2404,7 @@ static MYSQL_SYSVAR_STR(password_masking_cmds, password_masking_cmds_string,
|
||||
"AUDIT plugin commands to apply password masking regex to, comma separated",
|
||||
NULL, password_masking_cmds_string_update,
|
||||
// set password is recorded as set_option
|
||||
"CREATE_USER,GRANT,SET_OPTION,SLAVE_START,CREATE_SERVER,ALTER_SERVER,CHANGE_MASTER");
|
||||
"CREATE_USER,GRANT,SET_OPTION,SLAVE_START,CREATE_SERVER,ALTER_SERVER,CHANGE_MASTER,UPDATE");
|
||||
static MYSQL_SYSVAR_STR(whitelist_users, whitelist_users_string,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"AUDIT plugin whitelisted users whose queries are not recorded, comma separated",
|
||||
@@ -1990,11 +2415,36 @@ static MYSQL_SYSVAR_STR(record_objs, record_objs_string,
|
||||
"AUDIT plugin objects to record, comma separated. If set then only queries containing these objects will be recorded.",
|
||||
NULL, record_objs_string_update_extended, NULL);
|
||||
|
||||
static const char *before_after_names[] =
|
||||
{
|
||||
"after", "before", "both", NullS
|
||||
};
|
||||
|
||||
|
||||
TYPELIB before_after_typelib =
|
||||
{
|
||||
array_elements(before_after_names) - 1,
|
||||
"before_after_typelib",
|
||||
before_after_names,
|
||||
NULL
|
||||
};
|
||||
|
||||
static MYSQL_SYSVAR_ENUM(before_after, before_after_mode,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
|
||||
"AUDIT plugin log statements before execution, after, or both. Default is 'after'",
|
||||
NULL, NULL, 0,
|
||||
& before_after_typelib);
|
||||
|
||||
/*
|
||||
* Plugin system vars
|
||||
*/
|
||||
static struct st_mysql_sys_var* audit_system_variables[] =
|
||||
{
|
||||
#ifdef HAVE_SESS_CONNECT_ATTRS
|
||||
MYSQL_SYSVAR(sess_connect_attrs),
|
||||
#endif
|
||||
MYSQL_SYSVAR(socket_creds),
|
||||
MYSQL_SYSVAR(client_capabilities),
|
||||
MYSQL_SYSVAR(header_msg),
|
||||
MYSQL_SYSVAR(force_record_logins),
|
||||
MYSQL_SYSVAR(json_log_file),
|
||||
@@ -2022,6 +2472,10 @@ static struct st_mysql_sys_var* audit_system_variables[] =
|
||||
MYSQL_SYSVAR(record_objs),
|
||||
MYSQL_SYSVAR(checksum),
|
||||
MYSQL_SYSVAR(password_masking_regex),
|
||||
MYSQL_SYSVAR(set_peer_cred),
|
||||
MYSQL_SYSVAR(peer_is_uds),
|
||||
MYSQL_SYSVAR(peer_info),
|
||||
MYSQL_SYSVAR(before_after),
|
||||
|
||||
NULL
|
||||
};
|
||||
@@ -2065,6 +2519,9 @@ extern "C" void __attribute__ ((constructor)) audit_plugin_so_init(void)
|
||||
"%s mysqld_builtins are null. Plugin will not load unless the mysql version is: %d. \n",
|
||||
log_prefix, audit_plugin.interface_version >> 8);
|
||||
}
|
||||
|
||||
memset(peer_info_init_value, '0', sizeof(peer_info_init_value)-1);
|
||||
peer_info_init_value[sizeof(peer_info_init_value) - 1] = '\0';
|
||||
}
|
||||
#elif MYSQL_VERSION_ID < 50600
|
||||
extern struct st_mysql_plugin *mysql_mandatory_plugins[];
|
||||
@@ -2075,6 +2532,8 @@ extern "C" void __attribute__ ((constructor)) audit_plugin_so_init(void)
|
||||
log_prefix, audit_plugin.interface_version,
|
||||
audit_plugin.interface_version >> 8);
|
||||
|
||||
memset(peer_info_init_value, '0', sizeof(peer_info_init_value)-1);
|
||||
peer_info_init_value[sizeof(peer_info_init_value) - 1] = '\0';
|
||||
}
|
||||
#elif !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID < 50709
|
||||
// Interface version for MySQL 5.6 changed in 5.6.14.
|
||||
@@ -2090,6 +2549,16 @@ extern "C" void __attribute__ ((constructor)) audit_plugin_so_init(void)
|
||||
{
|
||||
audit_plugin.interface_version = 0x0301;
|
||||
}
|
||||
|
||||
memset(peer_info_init_value, '0', sizeof(peer_info_init_value)-1);
|
||||
peer_info_init_value[sizeof(peer_info_init_value) - 1] = '\0';
|
||||
}
|
||||
#else
|
||||
// 5.7
|
||||
extern "C" void __attribute__ ((constructor)) audit_plugin_so_init(void)
|
||||
{
|
||||
memset(peer_info_init_value, '0', sizeof(peer_info_init_value)-1);
|
||||
peer_info_init_value[sizeof(peer_info_init_value) - 1] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user