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
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
051b1fd67e | ||
|
|
4e4387cebd | ||
|
|
d9129cc112 | ||
|
|
685b20e20c | ||
|
|
94b7274600 | ||
|
|
051daf06a4 | ||
|
|
15c77835bf | ||
|
|
ee115750e5 | ||
|
|
a46b02b834 | ||
|
|
ef67fba5e6 | ||
|
|
c6d57e7205 | ||
|
|
b29ebeac51 | ||
|
|
a5bf3035e5 | ||
|
|
734882dfaa | ||
|
|
3ac3682926 | ||
|
|
7fcd565e9d | ||
|
|
83b85084fb | ||
|
|
24f157beb2 | ||
|
|
8d28867ee5 | ||
|
|
b47ec14636 | ||
|
|
1ac2324ab9 | ||
|
|
56462bd9d4 | ||
|
|
00194ab4bb | ||
|
|
de390805f1 | ||
|
|
9d66bfbdd3 | ||
|
|
a1c8250058 | ||
|
|
08899ffc55 | ||
|
|
272a1ae190 | ||
|
|
4c1af961c5 | ||
|
|
60074c0518 | ||
|
|
c81adbd7ee | ||
|
|
dd3d261f53 | ||
|
|
caf75d3c46 |
@@ -60,3 +60,100 @@ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
%% The following software may be included in this product: PCRE (http://www.pcre.org/)
|
||||
|
||||
Use of any of this software is governed by the terms of the license below:
|
||||
|
||||
PCRE LICENCE
|
||||
------------
|
||||
|
||||
PCRE is a library of functions to support regular expressions whose syntax
|
||||
and semantics are as close as possible to those of the Perl 5 language.
|
||||
|
||||
Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
|
||||
specified below. The documentation for PCRE, supplied in the "doc"
|
||||
directory, is distributed under the same terms as the software itself.
|
||||
|
||||
The basic library functions are written in C and are freestanding. Also
|
||||
included in the distribution is a set of C++ wrapper functions, and a
|
||||
just-in-time compiler that can be used to optimize pattern matching. These
|
||||
are both optional features that can be omitted when the library is built.
|
||||
|
||||
|
||||
THE BASIC LIBRARY FUNCTIONS
|
||||
---------------------------
|
||||
|
||||
Written by: Philip Hazel
|
||||
Email local part: ph10
|
||||
Email domain: cam.ac.uk
|
||||
|
||||
University of Cambridge Computing Service,
|
||||
Cambridge, England.
|
||||
|
||||
Copyright (c) 1997-2014 University of Cambridge
|
||||
All rights reserved.
|
||||
|
||||
|
||||
PCRE JUST-IN-TIME COMPILATION SUPPORT
|
||||
-------------------------------------
|
||||
|
||||
Written by: Zoltan Herczeg
|
||||
Email local part: hzmester
|
||||
Emain domain: freemail.hu
|
||||
|
||||
Copyright(c) 2010-2014 Zoltan Herczeg
|
||||
All rights reserved.
|
||||
|
||||
|
||||
STACK-LESS JUST-IN-TIME COMPILER
|
||||
--------------------------------
|
||||
|
||||
Written by: Zoltan Herczeg
|
||||
Email local part: hzmester
|
||||
Emain domain: freemail.hu
|
||||
|
||||
Copyright(c) 2009-2014 Zoltan Herczeg
|
||||
All rights reserved.
|
||||
|
||||
|
||||
THE C++ WRAPPER FUNCTIONS
|
||||
-------------------------
|
||||
|
||||
Contributed by: Google Inc.
|
||||
|
||||
Copyright (c) 2007-2012, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
|
||||
THE "BSD" LICENCE
|
||||
-----------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the name of Google
|
||||
Inc. nor the names of their contributors may be used to endorse or
|
||||
promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
End
|
||||
|
||||
13
compiling.txt
Executable file → Normal file
13
compiling.txt
Executable file → Normal file
@@ -35,16 +35,23 @@ This will create configure script. Then run:
|
||||
CXX='gcc -static-libgcc' CC='gcc -static-libgcc' ./configure --with-mysql=mysql-5.1.40
|
||||
|
||||
|
||||
==== MySQL 5.5 / 5.6 ======
|
||||
==== MySQL 5.5 / 5.6 / 5.7 ======
|
||||
|
||||
Extract MySQL 5.5 or 5.6 source code
|
||||
Extract MySQL 5.5, 5.6, or 5.7 source code
|
||||
|
||||
go to mysql-src dir and run:
|
||||
|
||||
cd mysql-5.5.x or mysql-5.6.x
|
||||
cd mysql-5.5.x or mysql-5.6.x or mysql-5.7.x
|
||||
cmake .
|
||||
make
|
||||
|
||||
Note: MySQL 5.7 requires Boost 1.59. You may have to install that
|
||||
first (see www.boost.org). In such a case, use:
|
||||
|
||||
cmake -DWITH_BOOST=/path/to/boost_1_59_0 .
|
||||
|
||||
Note: For MariaDB use: cmake . -DBUILD_CONFIG=mysql_release
|
||||
|
||||
Note: to speed things up it is possible to build just the following directories:
|
||||
libservices
|
||||
extra
|
||||
|
||||
@@ -27,8 +27,13 @@ AC_DEFUN([MYSQL_SRC_TEST], [
|
||||
AC_MSG_ERROR([Failed to find required header file $file in $withval, check the path and make sure you've run './configure ..<options>.. && cd include && make' in MySQL 5.1 sources dir or 'cmake . && make' in MySQL 5.5 sources dir.])
|
||||
fi
|
||||
done
|
||||
dnl binary_log_types.h included by mysql_com.h included by mysql_inc.h -
|
||||
dnl is found in libbinlogevents/export.
|
||||
dnl
|
||||
dnl table_id.h included from table.h included by mysql_inc.h is
|
||||
dnl in libbinlogevents/include.
|
||||
AC_DEFINE([MYSQL_SRC], [1], [Source directory for MySQL])
|
||||
MYSQL_INC="-I$withval/sql -I$withval/include -I$withval/regex -I$withval"
|
||||
MYSQL_INC="-I$withval/sql -I$withval/libbinlogevents/export -I$withval/libbinlogevents/include -I$withval/include -I$withval/regex -I$withval"
|
||||
AC_MSG_RESULT(["$withval"])
|
||||
],
|
||||
[
|
||||
|
||||
@@ -116,12 +116,17 @@ fi
|
||||
if test -z "$MYSQL_AUDIT_PLUGIN_REVISION" ;then
|
||||
MYSQL_AUDIT_PLUGIN_REVISION=99999
|
||||
fi
|
||||
if test -z "$MYSQL_AUDIT_PLUGIN_SYMBOL_VERSION" ;then
|
||||
MYSQL_AUDIT_PLUGIN_SYMBOL_VERSION=${MYSQL_AUDIT_PLUGIN_VERSION//./_}_$MYSQL_AUDIT_PLUGIN_REVISION
|
||||
fi
|
||||
|
||||
|
||||
AC_SUBST(MYSQL_AUDIT_PLUGIN_VERSION)
|
||||
AC_SUBST(MYSQL_AUDIT_PLUGIN_REVISION)
|
||||
echo "Version: $MYSQL_AUDIT_PLUGIN_VERSION-$MYSQL_AUDIT_PLUGIN_REVISION"
|
||||
echo "Version: $MYSQL_AUDIT_PLUGIN_VERSION-$MYSQL_AUDIT_PLUGIN_REVISION Symbol version: $MYSQL_AUDIT_PLUGIN_SYMBOL_VERSION"
|
||||
CPPFLAGS="$CPPFLAGS -DMYSQL_AUDIT_PLUGIN_VERSION='\"$MYSQL_AUDIT_PLUGIN_VERSION\"'"
|
||||
CPPFLAGS="$CPPFLAGS -DMYSQL_AUDIT_PLUGIN_REVISION='\"$MYSQL_AUDIT_PLUGIN_REVISION\"'"
|
||||
CPPFLAGS="$CPPFLAGS '-DMYSQL_AUDIT_PLUGIN_SYMBOL_VERSION()=extern const char audit_plugin_version_$MYSQL_AUDIT_PLUGIN_SYMBOL_VERSION'"
|
||||
|
||||
|
||||
#subst the relevant variables
|
||||
|
||||
@@ -10,12 +10,28 @@
|
||||
|
||||
#include "mysql_inc.h"
|
||||
#include <yajl/yajl_gen.h>
|
||||
|
||||
#ifndef PCRE_STATIC
|
||||
#define PCRE_STATIC
|
||||
#endif
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
#define AUDIT_LOG_PREFIX "Audit Plugin:"
|
||||
#define AUDIT_PROTOCOL_VERSION "1.0"
|
||||
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
// For locking we use the native lock routines provided by MySQL.
|
||||
// The data types and functions for native locking changed at 5.7.x.
|
||||
// Try to hide this with macros.
|
||||
#define rw_lock_t native_rw_lock_t
|
||||
#define rw_rdlock native_rw_rdlock
|
||||
#define rw_wrlock native_rw_wrlock
|
||||
#define rw_unlock native_rw_unlock
|
||||
#define rwlock_destroy native_rw_destroy
|
||||
#define my_rwlock_init(lock, unused) native_rw_init(lock)
|
||||
#endif
|
||||
|
||||
class THD;
|
||||
|
||||
#define MAX_NUM_QUERY_TABLE_ELEM 100
|
||||
@@ -45,7 +61,7 @@ typedef size_t OFFSET;
|
||||
#define MAX_NUM_USER_ELEM 256
|
||||
|
||||
/**
|
||||
* The struct usd to hold offsets. We should have one per version.
|
||||
* The struct used to hold offsets. We should have one per version.
|
||||
*/
|
||||
typedef struct ThdOffsets
|
||||
{
|
||||
@@ -60,9 +76,17 @@ typedef struct ThdOffsets
|
||||
OFFSET sec_ctx_user;
|
||||
OFFSET sec_ctx_host;
|
||||
OFFSET sec_ctx_ip;
|
||||
OFFSET sec_ctx_priv_user;
|
||||
OFFSET sec_ctx_priv_user;
|
||||
OFFSET db;
|
||||
OFFSET killed;
|
||||
} ThdOffsets;
|
||||
|
||||
/*
|
||||
* The offsets array
|
||||
*/
|
||||
extern const ThdOffsets thd_offsets_arr[];
|
||||
extern const size_t thd_offsets_arr_size;
|
||||
|
||||
/*
|
||||
* On success, the number of bytes written are returned (zero indicates nothing was written). On error, -1 is returned,
|
||||
*/
|
||||
@@ -174,12 +198,40 @@ public:
|
||||
+ Audit_formatter::thd_offsets.main_security_ctx);
|
||||
}
|
||||
|
||||
static inline const char * thd_db(THD * thd)
|
||||
{
|
||||
if(!Audit_formatter::thd_offsets.db) //no offsets use compiled in header
|
||||
{
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||
return thd->db;
|
||||
#else
|
||||
return thd->db().str;
|
||||
#endif
|
||||
}
|
||||
return *(const char **) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.db);
|
||||
}
|
||||
|
||||
static inline int thd_killed(THD * thd)
|
||||
{
|
||||
if(!Audit_formatter::thd_offsets.killed) //no offsets use thd_killed function
|
||||
{
|
||||
return ::thd_killed(thd);
|
||||
}
|
||||
return *(int *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.killed);
|
||||
}
|
||||
|
||||
static inline const char * thd_inst_main_security_ctx_user(THD * thd)
|
||||
{
|
||||
Security_context * sctx = thd_inst_main_security_ctx(thd);
|
||||
if(!Audit_formatter::thd_offsets.sec_ctx_user) //no offsets use compiled in header
|
||||
{
|
||||
return sctx->user;
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||
return sctx->user;
|
||||
#else
|
||||
return sctx->user().str;
|
||||
#endif
|
||||
}
|
||||
return *(const char **) (((unsigned char *) sctx)
|
||||
+ Audit_formatter::thd_offsets.sec_ctx_user);
|
||||
@@ -192,11 +244,20 @@ public:
|
||||
{
|
||||
//interface changed in 5.5.34 and 5.6.14 and up host changed to get_host()
|
||||
//see: http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/4407.1.1/sql/sql_class.h
|
||||
#if ( !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50534 && MYSQL_VERSION_ID < 50600) || (MYSQL_VERSION_ID >= 50614)
|
||||
return sctx->get_host()->ptr();
|
||||
#else
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
return sctx->host;
|
||||
#else
|
||||
// MySQL
|
||||
#if MYSQL_VERSION_ID < 50534 || (MYSQL_VERSION_ID >= 50600 && MYSQL_VERSION_ID < 50614)
|
||||
return sctx->host;
|
||||
#elif (MYSQL_VERSION_ID >= 50534 && MYSQL_VERSION_ID < 50600) \
|
||||
|| (MYSQL_VERSION_ID >= 50614 && MYSQL_VERSION_ID < 50709)
|
||||
return sctx->get_host()->ptr();
|
||||
#else
|
||||
// interface changed again in 5.7
|
||||
return sctx->host().str;
|
||||
#endif
|
||||
#endif // ! defined(MARIADB_BASE_VERSION)
|
||||
}
|
||||
return *(const char **) (((unsigned char *) sctx)
|
||||
+ Audit_formatter::thd_offsets.sec_ctx_host);
|
||||
@@ -208,11 +269,20 @@ public:
|
||||
if(!Audit_formatter::thd_offsets.sec_ctx_ip) //no offsets use compiled in header
|
||||
{
|
||||
//interface changed in 5.5.34 and 5.6.14 and up host changed to get_ip()
|
||||
#if ( !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50534 && MYSQL_VERSION_ID < 50600) || (MYSQL_VERSION_ID >= 50614)
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
return sctx->ip;
|
||||
#else
|
||||
// MySQL
|
||||
#if MYSQL_VERSION_ID < 50534 || (MYSQL_VERSION_ID >= 50600 && MYSQL_VERSION_ID < 50614)
|
||||
return sctx->ip;
|
||||
#elif (MYSQL_VERSION_ID >= 50534 && MYSQL_VERSION_ID < 50600) \
|
||||
|| (MYSQL_VERSION_ID >= 50614 && MYSQL_VERSION_ID < 50709)
|
||||
return sctx->get_ip()->ptr();
|
||||
#else
|
||||
return sctx->ip;
|
||||
#endif
|
||||
// interface changed again in 5.7
|
||||
return sctx->ip().str;
|
||||
#endif
|
||||
#endif // ! defined(MARIADB_BASE_VERSION)
|
||||
}
|
||||
return *(const char **) (((unsigned char *) sctx)
|
||||
+ Audit_formatter::thd_offsets.sec_ctx_ip);
|
||||
@@ -223,7 +293,11 @@ public:
|
||||
Security_context * sctx = thd_inst_main_security_ctx(thd);
|
||||
if(!Audit_formatter::thd_offsets.sec_ctx_priv_user) //no offsets use compiled in header
|
||||
{
|
||||
return sctx->priv_user;
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||
return sctx->priv_user;
|
||||
#else
|
||||
return sctx->priv_user().str;
|
||||
#endif
|
||||
}
|
||||
#if MYSQL_VERSION_ID < 50505
|
||||
//in 5.1.x priv_user is a pointer
|
||||
@@ -522,7 +596,7 @@ class Audit_file_handler: public Audit_io_handler
|
||||
public:
|
||||
|
||||
Audit_file_handler() :
|
||||
m_sync_period(0), m_log_file(NULL), m_sync_counter(0)
|
||||
m_sync_period(0), m_log_file(NULL), m_sync_counter(0), m_bufsize(0)
|
||||
{
|
||||
m_io_type = "file";
|
||||
}
|
||||
@@ -539,6 +613,11 @@ public:
|
||||
*/
|
||||
unsigned int m_sync_period;
|
||||
|
||||
/**
|
||||
* The buf size used by the file stream. 0 = use default, negative or 1 = no buffering
|
||||
*/
|
||||
long m_bufsize;
|
||||
|
||||
/**
|
||||
* Write function we pass to formatter
|
||||
*/
|
||||
|
||||
@@ -14,17 +14,27 @@
|
||||
|
||||
#include <my_config.h>
|
||||
#include <mysql_version.h>
|
||||
|
||||
#if MYSQL_VERSION_ID < 50505
|
||||
#include <mysql_priv.h>
|
||||
#else
|
||||
|
||||
//version 5.5.x doesn't contain mysql_priv.h . We need to add the includes provided by it.
|
||||
|
||||
|
||||
#if MYSQL_VERSION_ID >= 50505
|
||||
|
||||
// These two are not present in 5.7.9
|
||||
#if MYSQL_VERSION_ID < 50709
|
||||
#include <my_pthread.h>
|
||||
#include <sql_priv.h>
|
||||
#endif
|
||||
|
||||
#include <mysql/plugin.h>
|
||||
|
||||
#if MYSQL_VERSION_ID >= 50600
|
||||
//in 5.6 we use the audit plugin interface
|
||||
// From 5.6 we use the audit plugin interface
|
||||
#include <mysql/plugin_audit.h>
|
||||
#endif
|
||||
|
||||
#include <sql_parse.h>
|
||||
#include <sql_class.h>
|
||||
#include <my_global.h>
|
||||
@@ -41,9 +51,14 @@
|
||||
#define pthread_mutex_destroy mysql_mutex_destroy
|
||||
#define pthread_mutex_t mysql_mutex_t
|
||||
*/
|
||||
#endif /* ! if MYSQL_VERSION_ID >= 50505 */
|
||||
#endif /* ! if MYSQL_VERSION_ID < 50505 */
|
||||
|
||||
#else
|
||||
#include <mysql_priv.h>
|
||||
#if MYSQL_VERSION_ID >= 50709
|
||||
#include <sql/log.h>
|
||||
#if ! defined(MARIADB_BASE_VERSION)
|
||||
#include <sql/auth/auth_common.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <violite.h>
|
||||
@@ -51,7 +66,6 @@
|
||||
#include <my_md5.h>
|
||||
#include <my_dir.h>
|
||||
#include <my_sys.h>
|
||||
#include <my_regex.h>
|
||||
|
||||
//5.5 use my_free with a single param. 5.1 use with 2 params
|
||||
//based on: http://bazaar.launchpad.net/~mysql/myodbc/5.1/view/head:/util/stringutil.h
|
||||
@@ -70,8 +84,16 @@
|
||||
//MariaDB has a kill service that overrides thd_killed as a macro. It also has thd_killed function defined for backwards compatibility, so we redefine it.
|
||||
#undef thd_killed
|
||||
extern "C" int thd_killed(const MYSQL_THD thd);
|
||||
|
||||
//MariadDB 10.0.10 removed the include for thd_security_context
|
||||
#if MYSQL_VERSION_ID >= 100010
|
||||
extern "C" char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length, unsigned int max_query_len);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif //MYSQL_INCL_H
|
||||
|
||||
|
||||
|
||||
28
offset-extract/offset-extract.sh
Executable file → Normal file
28
offset-extract/offset-extract.sh
Executable file → Normal file
@@ -23,21 +23,45 @@ if [ $? = 0 ]; then
|
||||
fi
|
||||
|
||||
COMMAND_MEMBER=command
|
||||
THREAD_ID=thread_id
|
||||
SEC_CONTEXT=main_security_ctx
|
||||
USER=user
|
||||
HOST=host
|
||||
IP=ip
|
||||
PRIV_USER=priv_user
|
||||
DB=db
|
||||
|
||||
#in 5.6 command member is named m_command
|
||||
echo $MYVER | grep -P '^5.6' > /dev/null
|
||||
echo $MYVER | grep -P '^(5\.6|5\.7|10\.)' > /dev/null
|
||||
if [ $? = 0 ]; then
|
||||
COMMAND_MEMBER=m_command
|
||||
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
|
||||
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
|
||||
fi
|
||||
|
||||
echo "set logging on" > offsets.gdb
|
||||
echo 'printf "{\"'$MYVER'\",\"'$MYMD5'\", %d, %d, %d, %d, %d, %d, %d, %d, %d, %d}", ((size_t)&((THD *)log_slow_statement)->query_id) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->thread_id) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->main_security_ctx) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->'$COMMAND_MEMBER') - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->lex) - (size_t)log_slow_statement, (size_t)&((LEX*)log_slow_statement)->comment - (size_t) log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->user) - (size_t)log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->host) - (size_t)log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->ip) - (size_t)log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->priv_user) - (size_t)log_slow_statement' >> offsets.gdb
|
||||
echo 'printf "{\"'$MYVER'\",\"'$MYMD5'\", %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d}", ((size_t)&((THD *)log_slow_statement)->query_id) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->'$THREAD_ID') - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->'$SEC_CONTEXT') - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->'$COMMAND_MEMBER') - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->lex) - (size_t)log_slow_statement, (size_t)&((LEX*)log_slow_statement)->comment - (size_t) log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->'$USER') - (size_t)log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->'$HOST') - (size_t)log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->'$IP') - (size_t)log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->'$PRIV_USER') - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->'$DB') - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->killed) - (size_t)log_slow_statement' >> offsets.gdb
|
||||
|
||||
SYMPARAM=""
|
||||
if [ -n "$2" ]; then
|
||||
SYMPARAM="-s $2 -e"
|
||||
fi
|
||||
|
||||
which gdb > /dev/null 2>&1
|
||||
if [ $? != 0 ]; then
|
||||
echo "ERROR: gdb not found. Make sure gdb is installed and on the path."
|
||||
exit 3;
|
||||
fi
|
||||
|
||||
gdb -n -q -batch -x offsets.gdb $SYMPARAM $1 > /dev/null 2>&1
|
||||
|
||||
if [ $? != 0 ]; then
|
||||
|
||||
@@ -26,7 +26,7 @@ libaudit_plugin_la_DEPENDENCIESADD = pcre
|
||||
|
||||
libaudit_plugin_la_LDFLAGS = -module -Wl,--version-script=MySQLPlugin.map
|
||||
|
||||
libaudit_plugin_la_SOURCES = hot_patch.cc audit_plugin.cc audit_handler.cc md5.cc
|
||||
libaudit_plugin_la_SOURCES = hot_patch.cc audit_offsets.cc audit_plugin.cc audit_handler.cc md5.cc
|
||||
|
||||
libaudit_plugin_la_LIBADD = $(top_srcdir)/yajl/src/libyajl.la $(top_srcdir)/udis86/libudis86/libudis86.la $(top_srcdir)/pcre/libpcre.la $(MYSQL_LIBSERVICES)
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "audit_handler.h"
|
||||
//for definition of sockaddr_un
|
||||
#include <sys/un.h>
|
||||
#include <stdio_ext.h>
|
||||
#include "static_assert.h"
|
||||
|
||||
//utility macro to log also with a date as a prefix
|
||||
@@ -47,7 +48,9 @@ ThdOffsets Audit_formatter::thd_offsets = { 0 };
|
||||
Audit_handler * Audit_handler::m_audit_handler_list[Audit_handler::MAX_AUDIT_HANDLERS_NUM];
|
||||
const char * Audit_json_formatter::DEF_MSG_DELIMITER = "\\n";
|
||||
|
||||
#if MYSQL_VERSION_ID < 50709
|
||||
#define C_STRING_WITH_LEN(X) ((char *) (X)), ((size_t) (sizeof(X) - 1))
|
||||
#endif
|
||||
|
||||
|
||||
const char * Audit_formatter::retrieve_object_type (TABLE_LIST *pObj)
|
||||
@@ -198,7 +201,7 @@ int Audit_file_handler::open(const char * io_dest, bool log_errors)
|
||||
{
|
||||
char format_name[FN_REFLEN];
|
||||
fn_format(format_name, io_dest, "", "", MY_UNPACK_FILENAME);
|
||||
m_log_file = my_fopen(format_name, O_RDWR | O_APPEND, MYF(0));
|
||||
m_log_file = my_fopen(format_name, O_WRONLY | O_APPEND| O_CREAT, MYF(0));
|
||||
if (!m_log_file)
|
||||
{
|
||||
if(log_errors)
|
||||
@@ -209,12 +212,47 @@ int Audit_file_handler::open(const char * io_dest, bool log_errors)
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
ssize_t bufsize = BUFSIZ;
|
||||
int res =0;
|
||||
//0 -> use default, 1 or negative -> disabled
|
||||
if(m_bufsize > 1)
|
||||
{
|
||||
bufsize = m_bufsize;
|
||||
}
|
||||
if(1 == m_bufsize || m_bufsize < 0)
|
||||
{
|
||||
//disabled
|
||||
res = setvbuf(m_log_file, NULL, _IONBF, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = setvbuf(m_log_file, NULL, _IOFBF, bufsize);
|
||||
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to set bufzie [%zd (%ld)] for file %s: %s.",
|
||||
AUDIT_LOG_PREFIX, bufsize, m_bufsize, m_io_dest, strerror(errno));
|
||||
}
|
||||
sql_print_information("%s bufsize for file [%s]: %zd. Value of json_file_bufsize: %ld.", AUDIT_LOG_PREFIX, m_io_dest,
|
||||
__fbufsize(m_log_file), m_bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//no locks. called by handler_start and when it is time to retry
|
||||
bool Audit_io_handler::handler_start_internal()
|
||||
{
|
||||
if(!m_io_dest || strlen(m_io_dest) == 0)
|
||||
{
|
||||
if(m_log_io_errors)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s %s: io destination not set. Not connecting.",
|
||||
AUDIT_LOG_PREFIX, m_io_type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (open(m_io_dest, m_log_io_errors) != 0)
|
||||
{
|
||||
//open failed
|
||||
@@ -319,7 +357,7 @@ ssize_t Audit_socket_handler::write(const char * data, size_t size)
|
||||
}
|
||||
|
||||
int Audit_socket_handler::open(const char * io_dest, bool log_errors)
|
||||
{
|
||||
{
|
||||
//open the socket
|
||||
int sock = socket(AF_UNIX,SOCK_STREAM,0);
|
||||
if (sock < 0)
|
||||
@@ -369,12 +407,12 @@ bool Audit_socket_handler::handler_log_audit(ThdSesData *pThdData)
|
||||
|
||||
|
||||
|
||||
static inline yajl_gen_status yajl_add_string(yajl_gen hand, const char * str)
|
||||
static yajl_gen_status yajl_add_string(yajl_gen hand, const char * str)
|
||||
{
|
||||
return yajl_gen_string(hand, (const unsigned char*)str, strlen(str));
|
||||
}
|
||||
|
||||
static inline void yajl_add_string_val(yajl_gen hand, const char * name, const char* val)
|
||||
static void yajl_add_string_val(yajl_gen hand, const char * name, const char* val)
|
||||
{
|
||||
if(0 == val)
|
||||
{
|
||||
@@ -384,22 +422,25 @@ static inline void yajl_add_string_val(yajl_gen hand, const char * name, const c
|
||||
yajl_add_string(hand, val);
|
||||
}
|
||||
|
||||
static inline void yajl_add_string_val(yajl_gen hand, const char * name, const char* val, size_t val_len)
|
||||
static void yajl_add_string_val(yajl_gen hand, const char * name, const char* val, size_t val_len)
|
||||
{
|
||||
yajl_add_string(hand, name);
|
||||
yajl_gen_string(hand, (const unsigned char*)val, val_len);
|
||||
}
|
||||
|
||||
static inline void yajl_add_uint64(yajl_gen gen, const char * name, uint64 num)
|
||||
static void yajl_add_uint64(yajl_gen gen, const char * name, uint64 num)
|
||||
{
|
||||
const size_t max_int64_str_len = 21;
|
||||
char buf[max_int64_str_len];
|
||||
snprintf(buf, max_int64_str_len, "%llu", num);
|
||||
yajl_add_string_val(gen, name, buf);
|
||||
}
|
||||
static inline void yajl_add_obj( yajl_gen gen, const char *db,const char* ptype,const char * name =NULL)
|
||||
static void yajl_add_obj( yajl_gen gen, const char *db,const char* ptype,const char * name =NULL)
|
||||
{
|
||||
yajl_add_string_val(gen, "db", db);
|
||||
if(db)
|
||||
{
|
||||
yajl_add_string_val(gen, "db", db);
|
||||
}
|
||||
if (name)
|
||||
{
|
||||
yajl_add_string_val(gen, "name", name);
|
||||
@@ -407,7 +448,7 @@ static inline void yajl_add_obj( yajl_gen gen, const char *db,const char* ptype
|
||||
yajl_add_string_val(gen, "obj_type",ptype);
|
||||
}
|
||||
|
||||
static inline const char * retrieve_user (THD * thd)
|
||||
static const char * retrieve_user (THD * thd)
|
||||
{
|
||||
|
||||
const char * user = Audit_formatter::thd_inst_main_security_ctx_user(thd);
|
||||
@@ -426,7 +467,25 @@ static inline const char * retrieve_user (THD * thd)
|
||||
|
||||
//will return a pointer to the query and set len with the length of the query
|
||||
//starting with MySQL version 5.1.41 thd_query_string is added
|
||||
#if MYSQL_VERSION_ID > 50140
|
||||
//And at 5.7 it changed
|
||||
#if ! defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
|
||||
extern "C" LEX_CSTRING thd_query_unsafe(MYSQL_THD thd);
|
||||
|
||||
static const char * thd_query_str(THD * thd, size_t * len)
|
||||
{
|
||||
const LEX_CSTRING str = thd_query_unsafe(thd);
|
||||
if(str.length > 0)
|
||||
{
|
||||
*len = str.length;
|
||||
return str.str;
|
||||
}
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#elif defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID > 50140
|
||||
|
||||
extern "C" {
|
||||
MYSQL_LEX_STRING *thd_query_string(MYSQL_THD thd);
|
||||
}
|
||||
@@ -509,6 +568,40 @@ ssize_t Audit_json_formatter::start_msg_format(IWriter * writer)
|
||||
|
||||
}
|
||||
|
||||
// This routine replaces clear text with the string in `replace', leaving the rest of the string intact.
|
||||
//
|
||||
// thd - MySQL thread, used for allocating memory
|
||||
// str - pointer to start of original string
|
||||
// str_len - length thereof
|
||||
// cleartext_start - start of cleartext to replace
|
||||
// cleartext_len - length of cleartext
|
||||
// replace - \0 terminated string with replacement text
|
||||
static const char *replace_in_string(THD *thd,
|
||||
const char *str, size_t str_len,
|
||||
size_t cleartext_start, size_t cleartext_len,
|
||||
const char *replace)
|
||||
{
|
||||
size_t to_alloc = str_len + strlen(replace) + 1;
|
||||
char *new_str = (char *) thd_alloc(thd, to_alloc);
|
||||
memset(new_str, '\0', to_alloc);
|
||||
|
||||
// point to text after clear text
|
||||
const char *trailing = str + cleartext_start + cleartext_len;
|
||||
// how much text after clear text to copy in
|
||||
size_t final_to_move = ((str + str_len) - trailing);
|
||||
|
||||
char *pos = new_str;
|
||||
memcpy(pos, str, cleartext_start); // copy front of string
|
||||
pos += cleartext_start;
|
||||
|
||||
memcpy(pos, replace, strlen(replace)); // copy replacement text
|
||||
pos += strlen(replace);
|
||||
|
||||
memcpy(pos, trailing, final_to_move); // copy trailing part of string
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * writer)
|
||||
{
|
||||
THD * thd = pThdData->getTHD();
|
||||
@@ -559,16 +652,35 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
||||
const CHARSET_INFO *col_connection;
|
||||
#endif
|
||||
col_connection = Item::default_charset();
|
||||
|
||||
String sQuery (query,qlen,col_connection) ;
|
||||
if (strcmp (col_connection->csname,"utf8")!=0) {
|
||||
pThdData->getTHD()->convert_string (&sQuery,col_connection,&my_charset_utf8_general_ci);
|
||||
|
||||
// See comment below as to why we don't use String class directly, or call
|
||||
// pThdData->getTHD()->convert_string (&sQuery,col_connection,&my_charset_utf8_general_ci);
|
||||
const char *query_text = query;
|
||||
size_t query_len = qlen;
|
||||
|
||||
if (strcmp(col_connection->csname, "utf8") != 0) {
|
||||
// max UTF-8 bytes per char is 4.
|
||||
size_t to_amount = (qlen * 4) + 1;
|
||||
char* to = (char *) thd_alloc(thd, to_amount);
|
||||
|
||||
uint errors = 0;
|
||||
|
||||
size_t len = copy_and_convert(to, to_amount,
|
||||
&my_charset_utf8_general_ci,
|
||||
query, qlen,
|
||||
col_connection, & errors);
|
||||
|
||||
to[len] = '\0';
|
||||
|
||||
query = to;
|
||||
qlen = len;
|
||||
}
|
||||
|
||||
if(m_perform_password_masking && m_password_mask_regex_compiled && m_password_mask_regex_preg && m_perform_password_masking(cmd))
|
||||
{
|
||||
//do password masking
|
||||
int matches[90] = {0};
|
||||
if(pcre_exec(m_password_mask_regex_preg, NULL, sQuery.ptr(), sQuery.length(), 0, 0, matches, array_elements(matches)) >= 0)
|
||||
if(pcre_exec(m_password_mask_regex_preg, NULL, query_text, query_len, 0, 0, matches, array_elements(matches)) >= 0)
|
||||
{
|
||||
//search for the first substring that matches with the name psw
|
||||
char *first = NULL, *last = NULL;
|
||||
@@ -580,17 +692,24 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
||||
//first 2 bytes give us the number
|
||||
int n = (((int)(entry)[0]) << 8) | (entry)[1];
|
||||
if (n > 0 && n < (int)array_elements(matches) && matches[n*2] >= 0)
|
||||
{ //we have a match
|
||||
sQuery.copy(); //make sure string is alloced before doing replace
|
||||
const char * pass_replace = "***";
|
||||
sQuery.replace(matches[n*2], matches[(n*2) + 1] - matches[n*2], pass_replace, strlen(pass_replace));
|
||||
{
|
||||
// We have a match.
|
||||
|
||||
// Starting with MySQL 5.7, we cannot use the String::replace() function.
|
||||
// Doing so causes a crash in the string's destructor. It appears that the
|
||||
// interfaces in MySQL have changed fairly drastically. So we just do the
|
||||
// replacement ourselves.
|
||||
const char *pass_replace = "***";
|
||||
const char *updated = replace_in_string(thd, query_text, query_len, matches[n*2], matches[(n*2) + 1] - matches[n*2], pass_replace);
|
||||
query_text = updated;
|
||||
query_len = strlen(query_text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
yajl_add_string_val(gen, "query", sQuery.ptr(), sQuery.length());
|
||||
yajl_add_string_val(gen, "query", query_text, query_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -652,9 +771,11 @@ bool ThdSesData::startGetObjects()
|
||||
}
|
||||
const char *cmd = getCmdName();
|
||||
//commands which have single database object
|
||||
if (strcmp (cmd,"Init DB") ==0 || strcmp (cmd, "SHOW TABLES")== 0 || strcmp (cmd, "SHOW TABLE")==0)
|
||||
if (strcmp (cmd,"Init DB") ==0
|
||||
|| strcmp (cmd, "SHOW TABLES")== 0
|
||||
|| strcmp (cmd, "SHOW TABLE")==0)
|
||||
{
|
||||
if(getTHD()->db)
|
||||
if(Audit_formatter::thd_db(getTHD()))
|
||||
{
|
||||
m_objIterType = OBJ_DB;
|
||||
return true;
|
||||
@@ -681,7 +802,7 @@ bool ThdSesData::getNextObject(const char ** db_name, const char ** obj_name, co
|
||||
{
|
||||
if(m_firstTable)
|
||||
{
|
||||
*db_name = getTHD()->db;
|
||||
*db_name = Audit_formatter::thd_db(getTHD());
|
||||
*obj_name = NULL;
|
||||
if(obj_type)
|
||||
{
|
||||
|
||||
1006
src/audit_offsets.cc
Normal file
1006
src/audit_offsets.cc
Normal file
File diff suppressed because it is too large
Load Diff
1183
src/audit_plugin.cc
1183
src/audit_plugin.cc
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user