Add info about process on other end of UNIX Domain Socket and

also client port of remote connection for TCP Socket. New offset
required for this, so updated the offsets as well.
pull/179/head
Arnold Robbins 2017-01-02 11:52:28 +02:00
parent d83c36627c
commit 4fbcae3a81
5 changed files with 1062 additions and 715 deletions

View File

@ -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
@ -82,6 +95,7 @@ typedef struct ThdOffsets {
OFFSET pfs_connect_attrs;
OFFSET pfs_connect_attrs_length;
OFFSET pfs_connect_attrs_cs;
OFFSET net;
} ThdOffsets;
/*
@ -115,10 +129,14 @@ 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; }
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; }
/**
* Start fetching objects. Return true if there are objects available.
*/
@ -145,6 +163,10 @@ private:
QueryTableInf *m_tableInf;
int m_index;
PeerInfo *m_peerInfo;
int m_port; // TCP port of remote side
protected:
ThdSesData(const ThdSesData&);
ThdSesData &operator =(const ThdSesData&);
@ -322,57 +344,57 @@ 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;
}
return *(const char **) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs);
}
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);
}
#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;
}
return *(const char **) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs);
}
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)
{
@ -415,7 +437,51 @@ static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
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;
}
// 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)
@ -446,7 +512,8 @@ public:
: m_msg_delimiter(NULL),
m_write_start_msg(true),
m_write_sess_connect_attrs(true),
m_write_client_capabilities(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)
@ -491,13 +558,18 @@ public:
* 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 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

View File

@ -92,6 +92,7 @@ print_offset THD $DB
print_offset THD killed
$CLIENT_CAPS
$CONNECT_ATTRS
print_offset THD net
printf "}"
EOF

View File

@ -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
@ -558,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)
@ -621,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
@ -677,12 +680,12 @@ static const char *replace_in_string(THD *thd,
//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);
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
@ -690,76 +693,76 @@ bool parse_length_encoded_string(const char **ptr,
*/
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;
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);
/* read the key */
copy_length = 0;
if (parse_length_encoded_string(&ptr,
attr_name, array_elements(attr_name), &copy_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), &copy_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;
//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), &copy_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), &copy_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
@ -786,12 +789,14 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
yajl_add_string_val(gen, "priv_user", Audit_formatter::thd_inst_main_security_ctx_priv_user(thd));
yajl_add_string_val(gen, "ip", Audit_formatter::thd_inst_main_security_ctx_ip(thd));
// Don't send host unless there's a real value
// 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')
if (host == NULL || *host == '\0')
{
yajl_add_string_val(gen, "host", host);
host = Audit_formatter::thd_inst_main_security_ctx_ip(thd);
}
yajl_add_string_val(gen, "host", host);
if (m_write_client_capabilities)
{
@ -809,6 +814,26 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
}
#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();
yajl_add_string_val(gen, "cmd", cmd);
@ -938,10 +963,18 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
ThdSesData::ThdSesData(THD *pTHD)
: 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_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()
@ -1055,6 +1088,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;

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@
#include "hot_patch.h"
#include <stdlib.h>
#include <ctype.h>
#include <pwd.h>
#include "audit_handler.h"
#include <string.h>
@ -152,6 +153,32 @@ 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];
static MYSQL_THDVAR_STR(peer_info,
PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_READONLY | /* PLUGIN_VAR_NOCMDOPT | */ PLUGIN_VAR_MEMALLOC,
"Info related to client process",
NULL, NULL, peer_info_init_value);
THDPRINTED *GetThdPrintedList(THD *thd)
{
THDPRINTED *pThdPrintedList= (THDPRINTED*) THDVAR(thd, is_thd_printed_list);
@ -163,6 +190,153 @@ 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;
// zero out thread local copy of PeerInfo
peer = (PeerInfo *) THDVAR(pThd, peer_info);
if (peer != NULL)
{
memset(peer, 0, sizeof(PeerInfo));
}
// 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++)
@ -1043,9 +1217,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 %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", log_prefix,
Audit_formatter::thd_offsets.query_id,
Audit_formatter::thd_offsets.thread_id,
Audit_formatter::thd_offsets.main_security_ctx,
@ -1061,8 +1235,9 @@ static int setup_offsets()
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.pfs_connect_attrs_cs,
Audit_formatter::thd_offsets.net
);
if (! validate_offsets(&Audit_formatter::thd_offsets))
{
@ -1144,18 +1319,22 @@ 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.killed)
{
decoffsets.killed -= dec;
}
if(decoffsets.client_capabilities)
{
decoffsets.client_capabilities -= dec;
}
if(decoffsets.net)
{
decoffsets.net -= 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",
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",
log_prefix, dec, offset->version, offset->md5digest,
Audit_formatter::thd_offsets.query_id,
Audit_formatter::thd_offsets.thread_id,
@ -1167,8 +1346,12 @@ static int setup_offsets()
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.killed,
Audit_formatter::thd_offsets.client_capabilities);
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);
DBUG_RETURN(0);
}
@ -1185,7 +1368,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",
log_prefix, inc, offset->version, offset->md5digest,
Audit_formatter::thd_offsets.query_id,
Audit_formatter::thd_offsets.thread_id,
@ -1196,7 +1379,13 @@ 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);
DBUG_RETURN(0);
}
}
@ -1227,11 +1416,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;
@ -1365,7 +1557,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
@ -1621,28 +1813,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(
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(
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);
@ -1840,6 +2039,8 @@ static int audit_plugin_init(void *p)
{
DBUG_RETURN(1);
}
sql_print_information("%s Init completed successfully.", log_prefix);
DBUG_RETURN(0);
}
@ -1923,6 +2124,10 @@ 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);
@ -2059,7 +2264,8 @@ static struct st_mysql_sys_var* audit_system_variables[] =
#ifdef HAVE_SESS_CONNECT_ATTRS
MYSQL_SYSVAR(sess_connect_attrs),
#endif
MYSQL_SYSVAR(client_capabilities),
MYSQL_SYSVAR(socket_creds),
MYSQL_SYSVAR(client_capabilities),
MYSQL_SYSVAR(header_msg),
MYSQL_SYSVAR(force_record_logins),
MYSQL_SYSVAR(json_log_file),
@ -2087,6 +2293,9 @@ 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),
NULL
};
@ -2130,6 +2339,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[];
@ -2140,6 +2352,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.
@ -2155,6 +2369,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