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
parent
d83c36627c
commit
4fbcae3a81
|
@ -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
|
||||
|
|
|
@ -92,6 +92,7 @@ print_offset THD $DB
|
|||
print_offset THD killed
|
||||
$CLIENT_CAPS
|
||||
$CONNECT_ATTRS
|
||||
print_offset THD net
|
||||
printf "}"
|
||||
EOF
|
||||
|
||||
|
|
|
@ -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), ©_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;
|
||||
//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
|
||||
|
||||
|
@ -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;
|
||||
|
|
1086
src/audit_offsets.cc
1086
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>
|
||||
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue