33 Commits

Author SHA1 Message Date
Arnold Robbins
051b1fd67e Add MariaDB 10.1.12 offsets. 2016-03-10 13:57:44 +02:00
Arnold Robbins
4e4387cebd Add offsets for MariaDB 10.0.24 and MariaDB 5.5.48. 2016-02-25 12:34:12 +02:00
Arnold Robbins
d9129cc112 Add support for MySQL 5.7.{9,10,11}.
Add support for MariaDB 10.1.{10,11}.
Fix segfault for set var to null (issue 133).
If password masking regex doesn't compile, revert to default regex.
2016-02-07 15:59:41 +02:00
Arnold Robbins
685b20e20c Offsets for MariaDB 10.0.22 and 10.0.23. 2015-12-28 10:21:25 +02:00
Arnold Robbins
94b7274600 Offsets for MySQL 5.5.47, 5.6.28, MariaDB 5.5.47. 2015-12-13 14:17:46 +02:00
Guy Lichtman
051daf06a4 offsets for MySQL 5.5.46/5.6.27 and MariadDB 5.5.46 2015-10-12 14:03:54 +03:00
Guy Lichtman
15c77835bf mariadb offsets 10.0.21 and 5.5.45. Offset validation following experience with issue: #118. 2015-08-11 13:47:51 +03:00
Guy Lichtman
ee115750e5 Remove inlines for better investigation of issue #118 2015-08-02 16:38:04 +03:00
Guy Lichtman
a46b02b834 offsets 5.5.45 and 5.6.26 2015-07-29 15:19:34 +03:00
Guy Lichtman
ef67fba5e6 issue #118. Possible fix for the issue. 2015-07-29 15:16:07 +03:00
Guy Lichtman
c6d57e7205 documentation fixes. see issue #115 2015-07-12 17:58:36 +03:00
Guy Lichtman
b29ebeac51 Offsets for MariaDB 10.0.20 2015-07-12 17:58:07 +03:00
Guy Lichtman
a5bf3035e5 offsets for MariaDB 5.5.44 2015-06-16 12:35:51 +03:00
Guy Lichtman
734882dfaa offsets for 5.6.25 and 5.5.44 2015-06-07 17:21:06 +03:00
Guy Lichtman
3ac3682926 mariadb offsets for: 10.0.19 2015-05-17 13:25:48 +03:00
Guy Lichtman
7fcd565e9d mariadb offsets for 5.5.43 2015-05-06 14:10:56 +03:00
Guy Lichtman
83b85084fb offsets for 5.5.43 and 5.6.24 2015-04-15 12:13:49 +03:00
Guy Lichtman
24f157beb2 new configuration: audit_json_file_bufsize . Controls the buffer size used when logging to a file. Value of 0 means default size, value of 1 means no buffering. 2015-03-09 10:37:31 +02:00
Guy Lichtman
8d28867ee5 Offsets for MariaDB 5.5.42 and 10.0.17 2015-03-09 10:30:28 +02:00
Guy Lichtman
b47ec14636 Modifications to pull request #103 . Changed the name of the record_logins var to: force_record_logins and default value is disabled for backwards compatibility. Also changed the implementation a bit regarding flow and filtering on the empty user. issue #101 2015-02-10 15:06:42 +02:00
Guy Lichtman
1ac2324ab9 offsets for 5.5.42, 5.6.23, mariadb 10.0.16 2015-02-10 00:08:46 +02:00
Guy Lichtman
56462bd9d4 fix for empty "Connect" entries at startup. issue #40 and pr #103 : 2015-02-10 00:04:21 +02:00
Guy Lichtman
00194ab4bb Merge pull request #103 from RickPizzi/master
new option audit_record_logins to enable logging of Connect and Quit cmds
2015-02-09 23:38:29 +02:00
Riccardo Pizzi
de390805f1 added Failed Login auditing 2015-02-07 16:18:05 -05:00
Rick Pizzi
9d66bfbdd3 new option audit_record_logins to enable logging of Connect/Quit regardless the content of variable audit_record_cmds 2015-02-07 15:43:01 -05:00
Guy Lichtman
a1c8250058 New offsets added. Fixing issue #98 and a crash seen on percona when changing default database ("use <db>"). 2015-01-26 18:11:55 +02:00
Guy Lichtman
08899ffc55 offsets for 5.6.22 and 5.5.41 2014-12-28 16:53:43 +02:00
Guy Lichtman
272a1ae190 added special variable named audit_plugin_version_<version>_<revision> where '.' is repalced with '_'. This variable can be used to extract the version of the plugin by using a tool such as nm or objdump. issue #96. 2014-12-20 20:29:36 +02:00
Guy Lichtman
4c1af961c5 MariaDB 10.0.15 offsets 2014-11-30 17:20:15 +02:00
Guy Lichtman
60074c0518 Protection for case where tcp port or unix socket is not set and plugin tries to set default socket name at startup. The tcp port or unix socket may not be set when they are not passed either on the command line or configured in my.cnf. In this case the plugin init function is called before mysql has set the default values for these. 2014-11-09 12:05:39 +02:00
Guy Lichtman
c81adbd7ee mariadb 5.5.40 offsets 2014-10-27 14:48:41 +02:00
Guy Lichtman
dd3d261f53 mariadb 10 offsets (upto 10.0.14). Update to third party license file to include pcre. 2014-10-12 18:02:44 +02:00
Guy Lichtman
caf75d3c46 offset support for 5.5.40 and 5.6.21. Better auto offset detection for debina/ubuntu using 5.6.x. Compilation support with MariaDB 10 source code. 2014-10-06 09:29:35 +02:00
11 changed files with 1711 additions and 934 deletions

View File

@@ -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
View 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

View File

@@ -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"])
],
[

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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
View 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

View File

@@ -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)

View File

@@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff