26 changed files with 1221 additions and 273 deletions
-
3include/Makefile.am
-
220include/mysql/plugin.h
-
10include/mysql/plugin.h.pp
-
97include/mysql/plugin_audit.h
-
211include/mysql/plugin_ftparser.h
-
3libmysqld/CMakeLists.txt
-
4libmysqld/Makefile.am
-
2mysql-test/suite/perfschema/r/dml_setup_instruments.result
-
32plugin/audit_null/Makefile.am
-
130plugin/audit_null/audit_null.c
-
4plugin/audit_null/plug.in
-
2sql/CMakeLists.txt
-
4sql/Makefile.am
-
8sql/event_queue.cc
-
12sql/ha_ndbcluster.cc
-
17sql/log.cc
-
37sql/mysqld.cc
-
477sql/sql_audit.cc
-
131sql/sql_audit.h
-
5sql/sql_class.cc
-
15sql/sql_class.h
-
2sql/sql_connect.cc
-
3sql/sql_insert.cc
-
4sql/sql_parse.cc
-
58sql/sql_plugin.cc
-
3strings/longlong2str_asm.c
@ -0,0 +1,97 @@ |
|||
/* Copyright (C) 2007 MySQL AB |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
#ifndef _my_audit_h |
|||
#define _my_audit_h |
|||
|
|||
/************************************************************************* |
|||
API for Audit plugin. (MYSQL_AUDIT_PLUGIN) |
|||
*/ |
|||
|
|||
#include "plugin.h" |
|||
|
|||
#define MYSQL_AUDIT_CLASS_MASK_SIZE 1 |
|||
|
|||
#define MYSQL_AUDIT_INTERFACE_VERSION 0x0100 |
|||
|
|||
/* |
|||
The first word in every event class struct indicates the specific |
|||
class of the event. |
|||
*/ |
|||
struct mysql_event |
|||
{ |
|||
int event_class; |
|||
}; |
|||
|
|||
|
|||
/************************************************************************* |
|||
AUDIT CLASS : GENERAL |
|||
|
|||
LOG events occurs before emitting to the general query log. |
|||
ERROR events occur before transmitting errors to the user. |
|||
RESULT events occur after transmitting a resultset to the user. |
|||
*/ |
|||
|
|||
#define MYSQL_AUDIT_GENERAL_CLASS 0 |
|||
#define MYSQL_AUDIT_GENERAL_CLASSMASK (1 << MYSQL_AUDIT_GENERAL_CLASS) |
|||
#define MYSQL_AUDIT_GENERAL_LOG 0 |
|||
#define MYSQL_AUDIT_GENERAL_ERROR 1 |
|||
#define MYSQL_AUDIT_GENERAL_RESULT 2 |
|||
|
|||
struct mysql_event_general |
|||
{ |
|||
int event_class; |
|||
int general_error_code; |
|||
unsigned long general_thread_id; |
|||
const char *general_user; |
|||
unsigned int general_user_length; |
|||
const char *general_command; |
|||
unsigned int general_command_length; |
|||
const char *general_query; |
|||
unsigned int general_query_length; |
|||
struct charset_info_st *general_charset; |
|||
unsigned long long general_time; |
|||
unsigned long long general_rows; |
|||
}; |
|||
|
|||
|
|||
/************************************************************************* |
|||
Here we define the descriptor structure, that is referred from |
|||
st_mysql_plugin. |
|||
|
|||
release_thd() event occurs when the event class consumer is to be |
|||
disassociated from the specified THD. This would typically occur |
|||
before some operation which may require sleeping - such as when |
|||
waiting for the next query from the client. |
|||
|
|||
event_notify() is invoked whenever an event occurs which is of any |
|||
class for which the plugin has interest. The first word of the |
|||
mysql_event argument indicates the specific event class and the |
|||
remainder of the structure is as required for that class. |
|||
|
|||
class_mask is an array of bits used to indicate what event classes |
|||
that this plugin wants to receive. |
|||
*/ |
|||
|
|||
struct st_mysql_audit |
|||
{ |
|||
int interface_version; |
|||
void (*release_thd)(MYSQL_THD); |
|||
void (*event_notify)(MYSQL_THD, const struct mysql_event *); |
|||
unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; |
|||
}; |
|||
|
|||
|
|||
#endif |
@ -0,0 +1,211 @@ |
|||
/* Copyright (C) 2005 MySQL AB |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
#ifndef _my_plugin_ftparser_h |
|||
#define _my_plugin_ftparser_h |
|||
#include "plugin.h" |
|||
|
|||
/************************************************************************* |
|||
API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) |
|||
*/ |
|||
|
|||
#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0100 |
|||
|
|||
/* Parsing modes. Set in MYSQL_FTPARSER_PARAM::mode */ |
|||
enum enum_ftparser_mode |
|||
{ |
|||
/* |
|||
Fast and simple mode. This mode is used for indexing, and natural |
|||
language queries. |
|||
|
|||
The parser is expected to return only those words that go into the |
|||
index. Stopwords or too short/long words should not be returned. The |
|||
'boolean_info' argument of mysql_add_word() does not have to be set. |
|||
*/ |
|||
MYSQL_FTPARSER_SIMPLE_MODE= 0, |
|||
|
|||
/* |
|||
Parse with stopwords mode. This mode is used in boolean searches for |
|||
"phrase matching." |
|||
|
|||
The parser is not allowed to ignore words in this mode. Every word |
|||
should be returned, including stopwords and words that are too short |
|||
or long. The 'boolean_info' argument of mysql_add_word() does not |
|||
have to be set. |
|||
*/ |
|||
MYSQL_FTPARSER_WITH_STOPWORDS= 1, |
|||
|
|||
/* |
|||
Parse in boolean mode. This mode is used to parse a boolean query string. |
|||
|
|||
The parser should provide a valid MYSQL_FTPARSER_BOOLEAN_INFO |
|||
structure in the 'boolean_info' argument to mysql_add_word(). |
|||
Usually that means that the parser should recognize boolean operators |
|||
in the parsing stream and set appropriate fields in |
|||
MYSQL_FTPARSER_BOOLEAN_INFO structure accordingly. As for |
|||
MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored. |
|||
Instead, use FT_TOKEN_STOPWORD for the token type of such a word. |
|||
*/ |
|||
MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2 |
|||
}; |
|||
|
|||
/* |
|||
Token types for boolean mode searching (used for the type member of |
|||
MYSQL_FTPARSER_BOOLEAN_INFO struct) |
|||
|
|||
FT_TOKEN_EOF: End of data. |
|||
FT_TOKEN_WORD: Regular word. |
|||
FT_TOKEN_LEFT_PAREN: Left parenthesis (start of group/sub-expression). |
|||
FT_TOKEN_RIGHT_PAREN: Right parenthesis (end of group/sub-expression). |
|||
FT_TOKEN_STOPWORD: Stopword. |
|||
*/ |
|||
|
|||
enum enum_ft_token_type |
|||
{ |
|||
FT_TOKEN_EOF= 0, |
|||
FT_TOKEN_WORD= 1, |
|||
FT_TOKEN_LEFT_PAREN= 2, |
|||
FT_TOKEN_RIGHT_PAREN= 3, |
|||
FT_TOKEN_STOPWORD= 4 |
|||
}; |
|||
|
|||
/* |
|||
This structure is used in boolean search mode only. It conveys |
|||
boolean-mode metadata to the MySQL search engine for every word in |
|||
the search query. A valid instance of this structure must be filled |
|||
in by the plugin parser and passed as an argument in the call to |
|||
mysql_add_word (the callback function in the MYSQL_FTPARSER_PARAM |
|||
structure) when a query is parsed in boolean mode. |
|||
|
|||
type: The token type. Should be one of the enum_ft_token_type values. |
|||
|
|||
yesno: Whether the word must be present for a match to occur: |
|||
>0 Must be present |
|||
<0 Must not be present |
|||
0 Neither; the word is optional but its presence increases the relevance |
|||
With the default settings of the ft_boolean_syntax system variable, |
|||
>0 corresponds to the '+' operator, <0 corrresponds to the '-' operator, |
|||
and 0 means neither operator was used. |
|||
|
|||
weight_adjust: A weighting factor that determines how much a match |
|||
for the word counts. Positive values increase, negative - decrease the |
|||
relative word's importance in the query. |
|||
|
|||
wasign: The sign of the word's weight in the query. If it's non-negative |
|||
the match for the word will increase document relevance, if it's |
|||
negative - decrease (the word becomes a "noise word", the less of it the |
|||
better). |
|||
|
|||
trunc: Corresponds to the '*' operator in the default setting of the |
|||
ft_boolean_syntax system variable. |
|||
*/ |
|||
|
|||
typedef struct st_mysql_ftparser_boolean_info |
|||
{ |
|||
enum enum_ft_token_type type; |
|||
int yesno; |
|||
int weight_adjust; |
|||
char wasign; |
|||
char trunc; |
|||
/* These are parser state and must be removed. */ |
|||
char prev; |
|||
char *quot; |
|||
} MYSQL_FTPARSER_BOOLEAN_INFO; |
|||
|
|||
/* |
|||
The following flag means that buffer with a string (document, word) |
|||
may be overwritten by the caller before the end of the parsing (that is |
|||
before st_mysql_ftparser::deinit() call). If one needs the string |
|||
to survive between two successive calls of the parsing function, she |
|||
needs to save a copy of it. The flag may be set by MySQL before calling |
|||
st_mysql_ftparser::parse(), or it may be set by a plugin before calling |
|||
st_mysql_ftparser_param::mysql_parse() or |
|||
st_mysql_ftparser_param::mysql_add_word(). |
|||
*/ |
|||
#define MYSQL_FTFLAGS_NEED_COPY 1 |
|||
|
|||
/* |
|||
An argument of the full-text parser plugin. This structure is |
|||
filled in by MySQL server and passed to the parsing function of the |
|||
plugin as an in/out parameter. |
|||
|
|||
mysql_parse: A pointer to the built-in parser implementation of the |
|||
server. It's set by the server and can be used by the parser plugin |
|||
to invoke the MySQL default parser. If plugin's role is to extract |
|||
textual data from .doc, .pdf or .xml content, it might extract |
|||
plaintext from the content, and then pass the text to the default |
|||
MySQL parser to be parsed. |
|||
|
|||
mysql_add_word: A server callback to add a new word. When parsing |
|||
a document, the server sets this to point at a function that adds |
|||
the word to MySQL full-text index. When parsing a search query, |
|||
this function will add the new word to the list of words to search |
|||
for. The boolean_info argument can be NULL for all cases except |
|||
when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO. |
|||
|
|||
ftparser_state: A generic pointer. The plugin can set it to point |
|||
to information to be used internally for its own purposes. |
|||
|
|||
mysql_ftparam: This is set by the server. It is used by MySQL functions |
|||
called via mysql_parse() and mysql_add_word() callback. The plugin |
|||
should not modify it. |
|||
|
|||
cs: Information about the character set of the document or query string. |
|||
|
|||
doc: A pointer to the document or query string to be parsed. |
|||
|
|||
length: Length of the document or query string, in bytes. |
|||
|
|||
flags: See MYSQL_FTFLAGS_* constants above. |
|||
|
|||
mode: The parsing mode. With boolean operators, with stopwords, or |
|||
nothing. See enum_ftparser_mode above. |
|||
*/ |
|||
|
|||
typedef struct st_mysql_ftparser_param |
|||
{ |
|||
int (*mysql_parse)(struct st_mysql_ftparser_param *, |
|||
char *doc, int doc_len); |
|||
int (*mysql_add_word)(struct st_mysql_ftparser_param *, |
|||
char *word, int word_len, |
|||
MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info); |
|||
void *ftparser_state; |
|||
void *mysql_ftparam; |
|||
struct charset_info_st *cs; |
|||
char *doc; |
|||
int length; |
|||
int flags; |
|||
enum enum_ftparser_mode mode; |
|||
} MYSQL_FTPARSER_PARAM; |
|||
|
|||
/* |
|||
Full-text parser descriptor. |
|||
|
|||
interface_version is, e.g., MYSQL_FTPARSER_INTERFACE_VERSION. |
|||
The parsing, initialization, and deinitialization functions are |
|||
invoked per SQL statement for which the parser is used. |
|||
*/ |
|||
|
|||
struct st_mysql_ftparser |
|||
{ |
|||
int interface_version; |
|||
int (*parse)(MYSQL_FTPARSER_PARAM *param); |
|||
int (*init)(MYSQL_FTPARSER_PARAM *param); |
|||
int (*deinit)(MYSQL_FTPARSER_PARAM *param); |
|||
}; |
|||
|
|||
|
|||
#endif |
|||
|
@ -0,0 +1,32 @@ |
|||
# Copyright (C) 2007 MySQL AB
|
|||
#
|
|||
# This program is free software; you can redistribute it and/or modify
|
|||
# it under the terms of the GNU General Public License as published by
|
|||
# the Free Software Foundation; version 2 of the License.
|
|||
#
|
|||
# This program is distributed in the hope that it will be useful,
|
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
# GNU General Public License for more details.
|
|||
#
|
|||
# You should have received a copy of the GNU General Public License
|
|||
# along with this program; if not, write to the Free Software
|
|||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
|||
#Makefile.am example for a plugin
|
|||
|
|||
pkgplugindir= $(pkglibdir)/plugin |
|||
|
|||
AM_CPPFLAGS = -I$(top_srcdir)/include |
|||
|
|||
EXTRA_LTLIBRARIES= adt_null.la |
|||
pkgplugin_LTLIBRARIES= @plugin_audit_null_shared_target@ |
|||
adt_null_la_LDFLAGS= -module -rpath $(pkgplugindir) |
|||
adt_null_la_CPPFLAGS= $(AM_CPPFLAGS) -DMYSQL_DYNAMIC_PLUGIN |
|||
adt_null_la_SOURCES= audit_null.c |
|||
|
|||
EXTRA_LIBRARIES= libadtnull.a |
|||
noinst_LIBRARIES= @plugin_audit_null_static_target@ |
|||
libadtnull_a_SOURCES= audit_null.c |
|||
|
|||
EXTRA_DIST= plug.in |
@ -0,0 +1,130 @@ |
|||
/* Copyright (C) 2006-2007 MySQL AB |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
|||
|
|||
#include <stdio.h> |
|||
#include <mysql/plugin.h> |
|||
#include <mysql/plugin_audit.h> |
|||
|
|||
#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8) |
|||
#define __attribute__(A) |
|||
#endif |
|||
|
|||
static volatile int number_of_calls; /* for SHOW STATUS, see below */ |
|||
|
|||
|
|||
/* |
|||
Initialize the plugin at server start or plugin installation. |
|||
|
|||
SYNOPSIS |
|||
audit_null_plugin_init() |
|||
|
|||
DESCRIPTION |
|||
Does nothing. |
|||
|
|||
RETURN VALUE |
|||
0 success |
|||
1 failure (cannot happen) |
|||
*/ |
|||
|
|||
static int audit_null_plugin_init(void *arg __attribute__((unused))) |
|||
{ |
|||
number_of_calls= 0; |
|||
return(0); |
|||
} |
|||
|
|||
|
|||
/* |
|||
Terminate the plugin at server shutdown or plugin deinstallation. |
|||
|
|||
SYNOPSIS |
|||
audit_null_plugin_deinit() |
|||
Does nothing. |
|||
|
|||
RETURN VALUE |
|||
0 success |
|||
1 failure (cannot happen) |
|||
|
|||
*/ |
|||
|
|||
static int audit_null_plugin_deinit(void *arg __attribute__((unused))) |
|||
{ |
|||
printf("audit_null was invoked %u times\n", number_of_calls); |
|||
return(0); |
|||
} |
|||
|
|||
|
|||
/* |
|||
Foo |
|||
|
|||
SYNOPSIS |
|||
audit_null_notify() |
|||
thd connection context |
|||
|
|||
DESCRIPTION |
|||
*/ |
|||
|
|||
static void audit_null_notify(MYSQL_THD thd __attribute__((unused)), |
|||
const struct mysql_event *event |
|||
__attribute__((unused))) |
|||
{ |
|||
/* prone to races, oh well */ |
|||
number_of_calls++; |
|||
} |
|||
|
|||
|
|||
/* |
|||
Plugin type-specific descriptor |
|||
*/ |
|||
|
|||
static struct st_mysql_audit audit_null_descriptor= |
|||
{ |
|||
MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */ |
|||
NULL, /* release_thd function */ |
|||
audit_null_notify, /* notify function */ |
|||
{ (unsigned long) -1 } /* class mask */ |
|||
}; |
|||
|
|||
/* |
|||
Plugin status variables for SHOW STATUS |
|||
*/ |
|||
|
|||
static struct st_mysql_show_var simple_status[]= |
|||
{ |
|||
{"audit_null_called", (char *)&number_of_calls, SHOW_INT}, |
|||
{0,0,0} |
|||
}; |
|||
|
|||
|
|||
/* |
|||
Plugin library descriptor |
|||
*/ |
|||
|
|||
mysql_declare_plugin(audit_null) |
|||
{ |
|||
MYSQL_AUDIT_PLUGIN, /* type */ |
|||
&audit_null_descriptor, /* descriptor */ |
|||
"NULL_AUDIT", /* name */ |
|||
"MySQL AB", /* author */ |
|||
"Simple NULL Audit", /* description */ |
|||
PLUGIN_LICENSE_GPL, |
|||
audit_null_plugin_init, /* init function (when loaded) */ |
|||
audit_null_plugin_deinit, /* deinit function (when unloaded) */ |
|||
0x0001, /* version */ |
|||
simple_status, /* status variables */ |
|||
NULL, /* system variables */ |
|||
NULL |
|||
} |
|||
mysql_declare_plugin_end; |
|||
|
@ -0,0 +1,4 @@ |
|||
MYSQL_PLUGIN(audit_null, [NULL Audit Plug-in], |
|||
[Simple black-hole Audit example plug-in]) |
|||
MYSQL_PLUGIN_DYNAMIC(audit_null, [adt_null.la]) |
|||
MYSQL_PLUGIN_STATIC(audit_null, [libadtnull.a]) |
@ -0,0 +1,477 @@ |
|||
/* Copyright (C) 2007 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
#include "mysql_priv.h"
|
|||
#include "sql_audit.h"
|
|||
|
|||
extern int initialize_audit_plugin(st_plugin_int *plugin); |
|||
extern int finalize_audit_plugin(st_plugin_int *plugin); |
|||
|
|||
#ifndef EMBEDDED_LIBRARY
|
|||
|
|||
unsigned long mysql_global_audit_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; |
|||
|
|||
static mysql_mutex_t LOCK_audit_mask; |
|||
|
|||
static void event_class_dispatch(THD *thd, const struct mysql_event *event); |
|||
|
|||
|
|||
static inline |
|||
void set_audit_mask(unsigned long *mask, uint event_class) |
|||
{ |
|||
mask[0]= 1; |
|||
mask[0]<<= event_class; |
|||
} |
|||
|
|||
static inline |
|||
void add_audit_mask(unsigned long *mask, const unsigned long *rhs) |
|||
{ |
|||
mask[0]|= rhs[0]; |
|||
} |
|||
|
|||
static inline |
|||
bool check_audit_mask(const unsigned long *lhs, |
|||
const unsigned long *rhs) |
|||
{ |
|||
return !(lhs[0] & rhs[0]); |
|||
} |
|||
|
|||
|
|||
typedef void (*audit_handler_t)(THD *thd, uint event_subtype, va_list ap); |
|||
|
|||
/**
|
|||
MYSQL_AUDIT_GENERAL_CLASS handler |
|||
|
|||
@param[in] thd |
|||
@param[in] event_subtype |
|||
@param[in] error_code |
|||
@param[in] ap |
|||
|
|||
*/ |
|||
|
|||
static void general_class_handler(THD *thd, uint event_subtype, va_list ap) |
|||
{ |
|||
mysql_event_general event; |
|||
event.event_class= MYSQL_AUDIT_GENERAL_CLASS; |
|||
event.general_error_code= va_arg(ap, int); |
|||
event.general_thread_id= thd ? thd->thread_id : 0; |
|||
event.general_time= va_arg(ap, time_t); |
|||
event.general_user= va_arg(ap, const char *); |
|||
event.general_user_length= va_arg(ap, unsigned int); |
|||
event.general_command= va_arg(ap, const char *); |
|||
event.general_command_length= va_arg(ap, unsigned int); |
|||
event.general_query= va_arg(ap, const char *); |
|||
event.general_query_length= va_arg(ap, unsigned int); |
|||
event.general_charset= va_arg(ap, struct charset_info_st *); |
|||
event.general_rows= (unsigned long long) va_arg(ap, ha_rows); |
|||
event_class_dispatch(thd, (const mysql_event*) &event); |
|||
} |
|||
|
|||
|
|||
static audit_handler_t audit_handlers[] = |
|||
{ |
|||
general_class_handler |
|||
}; |
|||
|
|||
static const uint audit_handlers_count= |
|||
(sizeof(audit_handlers) / sizeof(audit_handler_t)); |
|||
|
|||
|
|||
/**
|
|||
Acquire and lock any additional audit plugins as required |
|||
|
|||
@param[in] thd |
|||
@param[in] plugin |
|||
@param[in] arg |
|||
|
|||
@retval FALSE Always |
|||
*/ |
|||
|
|||
static my_bool acquire_plugins(THD *thd, plugin_ref plugin, void *arg) |
|||
{ |
|||
uint event_class= *(uint*) arg; |
|||
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; |
|||
st_mysql_audit *data= plugin_data(plugin, struct st_mysql_audit *); |
|||
|
|||
set_audit_mask(event_class_mask, event_class); |
|||
|
|||
/* Check if this plugin is interested in the event */ |
|||
if (check_audit_mask(data->class_mask, event_class_mask)) |
|||
return 0; |
|||
|
|||
/*
|
|||
Check if this plugin may already be registered. This will fail to |
|||
acquire a newly installed plugin on a specific corner case where |
|||
one or more event classes already in use by the calling thread |
|||
are an event class of which the audit plugin has interest. |
|||
*/ |
|||
if (!check_audit_mask(data->class_mask, thd->audit_class_mask)) |
|||
return 0; |
|||
|
|||
/* Check if we need to initialize the array of acquired plugins */ |
|||
if (unlikely(!thd->audit_class_plugins.buffer)) |
|||
{ |
|||
/* specify some reasonable initialization defaults */ |
|||
my_init_dynamic_array(&thd->audit_class_plugins, |
|||
sizeof(plugin_ref), 16, 16); |
|||
} |
|||
|
|||
/* lock the plugin and add it to the list */ |
|||
plugin= my_plugin_lock(NULL, &plugin); |
|||
insert_dynamic(&thd->audit_class_plugins, (uchar*) &plugin); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Notify the audit system of an event |
|||
|
|||
@param[in] thd |
|||
@param[in] event_class |
|||
@param[in] event_subtype |
|||
@param[in] error_code |
|||
|
|||
*/ |
|||
|
|||
void mysql_audit_notify(THD *thd, uint event_class, uint event_subtype, ...) |
|||
{ |
|||
va_list ap; |
|||
audit_handler_t *handlers= audit_handlers + event_class; |
|||
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; |
|||
|
|||
DBUG_ASSERT(event_class < audit_handlers_count); |
|||
|
|||
set_audit_mask(event_class_mask, event_class); |
|||
/*
|
|||
Check to see if we have acquired the audit plugins for the |
|||
required audit event classes. |
|||
*/ |
|||
if (thd && check_audit_mask(thd->audit_class_mask, event_class_mask)) |
|||
{ |
|||
plugin_foreach(thd, acquire_plugins, MYSQL_AUDIT_PLUGIN, &event_class); |
|||
add_audit_mask(thd->audit_class_mask, event_class_mask); |
|||
} |
|||
|
|||
va_start(ap, event_subtype); |
|||
(*handlers)(thd, event_subtype, ap); |
|||
va_end(ap); |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Release any resources associated with the current thd. |
|||
|
|||
@param[in] thd |
|||
|
|||
*/ |
|||
|
|||
void mysql_audit_release(THD *thd) |
|||
{ |
|||
plugin_ref *plugins, *plugins_last; |
|||
|
|||
if (!thd || !(thd->audit_class_plugins.elements)) |
|||
return; |
|||
|
|||
plugins= (plugin_ref*) thd->audit_class_plugins.buffer; |
|||
plugins_last= plugins + thd->audit_class_plugins.elements; |
|||
for (; plugins < plugins_last; plugins++) |
|||
{ |
|||
st_mysql_audit *data= plugin_data(*plugins, struct st_mysql_audit *); |
|||
|
|||
/* Check to see if the plugin has a release method */ |
|||
if (!(data->release_thd)) |
|||
continue; |
|||
|
|||
/* Tell the plugin to release its resources */ |
|||
data->release_thd(thd); |
|||
} |
|||
|
|||
/* Now we actually unlock the plugins */ |
|||
plugin_unlock_list(NULL, (plugin_ref*) thd->audit_class_plugins.buffer, |
|||
thd->audit_class_plugins.elements); |
|||
|
|||
/* Reset the state of thread values */ |
|||
reset_dynamic(&thd->audit_class_plugins); |
|||
bzero(thd->audit_class_mask, sizeof(thd->audit_class_mask)); |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Initialize thd variables used by Audit |
|||
|
|||
@param[in] thd |
|||
|
|||
*/ |
|||
|
|||
void mysql_audit_init_thd(THD *thd) |
|||
{ |
|||
bzero(&thd->audit_class_plugins, sizeof(thd->audit_class_plugins)); |
|||
bzero(thd->audit_class_mask, sizeof(thd->audit_class_mask)); |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Free thd variables used by Audit |
|||
|
|||
@param[in] thd |
|||
@param[in] plugin |
|||
@param[in] arg |
|||
|
|||
@retval FALSE Always |
|||
*/ |
|||
|
|||
void mysql_audit_free_thd(THD *thd) |
|||
{ |
|||
mysql_audit_release(thd); |
|||
DBUG_ASSERT(thd->audit_class_plugins.elements == 0); |
|||
delete_dynamic(&thd->audit_class_plugins); |
|||
} |
|||
|
|||
#ifdef HAVE_PSI_INTERFACE
|
|||
static PSI_mutex_key key_LOCK_audit_mask; |
|||
|
|||
static PSI_mutex_info all_audit_mutexes[]= |
|||
{ |
|||
{ &key_LOCK_audit_mask, "LOCK_audit_mask", PSI_FLAG_GLOBAL} |
|||
}; |
|||
|
|||
static void init_audit_psi_keys(void) |
|||
{ |
|||
const char* category= "sql"; |
|||
int count; |
|||
|
|||
if (PSI_server == NULL) |
|||
return; |
|||
|
|||
count= array_elements(all_audit_mutexes); |
|||
PSI_server->register_mutex(category, all_audit_mutexes, count); |
|||
} |
|||
#endif /* HAVE_PSI_INTERFACE */
|
|||
|
|||
/**
|
|||
Initialize Audit global variables |
|||
*/ |
|||
|
|||
void mysql_audit_initialize() |
|||
{ |
|||
#ifdef HAVE_PSI_INTERFACE
|
|||
init_audit_psi_keys(); |
|||
#endif
|
|||
|
|||
mysql_mutex_init(key_LOCK_audit_mask, &LOCK_audit_mask, MY_MUTEX_INIT_FAST); |
|||
bzero(mysql_global_audit_mask, sizeof(mysql_global_audit_mask)); |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Finalize Audit global variables |
|||
*/ |
|||
|
|||
void mysql_audit_finalize() |
|||
{ |
|||
mysql_mutex_destroy(&LOCK_audit_mask); |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Initialize an Audit plug-in |
|||
|
|||
@param[in] plugin |
|||
|
|||
@retval FALSE OK |
|||
@retval TRUE There was an error. |
|||
*/ |
|||
|
|||
int initialize_audit_plugin(st_plugin_int *plugin) |
|||
{ |
|||
st_mysql_audit *data= (st_mysql_audit*) plugin->plugin->info; |
|||
|
|||
if (!data->class_mask || !data->event_notify || |
|||
!data->class_mask[0]) |
|||
{ |
|||
sql_print_error("Plugin '%s' has invalid data.", |
|||
plugin->name.str); |
|||
return 1; |
|||
} |
|||
|
|||
if (plugin->plugin->init && plugin->plugin->init(NULL)) |
|||
{ |
|||
sql_print_error("Plugin '%s' init function returned error.", |
|||
plugin->name.str); |
|||
return 1; |
|||
} |
|||
|
|||
/* Make the interface info more easily accessible */ |
|||
plugin->data= plugin->plugin->info; |
|||
|
|||
/* Add the bits the plugin is interested in to the global mask */ |
|||
mysql_mutex_lock(&LOCK_audit_mask); |
|||
add_audit_mask(mysql_global_audit_mask, data->class_mask); |
|||
mysql_mutex_unlock(&LOCK_audit_mask); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Performs a bitwise OR of the installed plugins event class masks |
|||
|
|||
@param[in] thd |
|||
@param[in] plugin |
|||
@param[in] arg |
|||
|
|||
@retval FALSE always |
|||
*/ |
|||
static my_bool calc_class_mask(THD *thd, plugin_ref plugin, void *arg) |
|||
{ |
|||
st_mysql_audit *data= plugin_data(plugin, struct st_mysql_audit *); |
|||
if ((data= plugin_data(plugin, struct st_mysql_audit *))) |
|||
add_audit_mask((unsigned long *) arg, data->class_mask); |
|||
return 0; |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Finalize an Audit plug-in |
|||
|
|||
@param[in] plugin |
|||
|
|||
@retval FALSE OK |
|||
@retval TRUE There was an error. |
|||
*/ |
|||
int finalize_audit_plugin(st_plugin_int *plugin) |
|||
{ |
|||
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; |
|||
|
|||
if (plugin->plugin->deinit && plugin->plugin->deinit(NULL)) |
|||
{ |
|||
DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.", |
|||
plugin->name.str)); |
|||
DBUG_EXECUTE("finalize_audit_plugin", return 1; ); |
|||
} |
|||
|
|||
plugin->data= NULL; |
|||
bzero(&event_class_mask, sizeof(event_class_mask)); |
|||
|
|||
/* Iterate through all the installed plugins to create new mask */ |
|||
|
|||
/*
|
|||
LOCK_audit_mask/LOCK_plugin order is not fixed, but serialized with table |
|||
lock on mysql.plugin. |
|||
*/ |
|||
mysql_mutex_lock(&LOCK_audit_mask); |
|||
plugin_foreach(current_thd, calc_class_mask, MYSQL_AUDIT_PLUGIN, |
|||
&event_class_mask); |
|||
|
|||
/* Set the global audit mask */ |
|||
bmove(mysql_global_audit_mask, event_class_mask, sizeof(event_class_mask)); |
|||
mysql_mutex_unlock(&LOCK_audit_mask); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Dispatches an event by invoking the plugin's event_notify method. |
|||
|
|||
@param[in] thd |
|||
@param[in] plugin |
|||
@param[in] arg |
|||
|
|||
@retval FALSE always |
|||
*/ |
|||
|
|||
static my_bool plugins_dispatch(THD *thd, plugin_ref plugin, void *arg) |
|||
{ |
|||
const struct mysql_event *event= (const struct mysql_event *) arg; |
|||
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; |
|||
st_mysql_audit *data= plugin_data(plugin, struct st_mysql_audit *); |
|||
|
|||
set_audit_mask(event_class_mask, event->event_class); |
|||
|
|||
/* Check to see if the plugin is interested in this event */ |
|||
if (check_audit_mask(data->class_mask, event_class_mask)) |
|||
return 0; |
|||
|
|||
/* Actually notify the plugin */ |
|||
data->event_notify(thd, event); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Distributes an audit event to plug-ins |
|||
|
|||
@param[in] thd |
|||
@param[in] event |
|||
*/ |
|||
|
|||
static void event_class_dispatch(THD *thd, const struct mysql_event *event) |
|||
{ |
|||
/*
|
|||
Check if we are doing a slow global dispatch. This event occurs when |
|||
thd == NULL as it is not associated with any particular thread. |
|||
*/ |
|||
if (unlikely(!thd)) |
|||
{ |
|||
plugin_foreach(thd, plugins_dispatch, MYSQL_AUDIT_PLUGIN, (void*) event); |
|||
} |
|||
else |
|||
{ |
|||
plugin_ref *plugins, *plugins_last; |
|||
|
|||
/* Use the cached set of audit plugins */ |
|||
plugins= (plugin_ref*) thd->audit_class_plugins.buffer; |
|||
plugins_last= plugins + thd->audit_class_plugins.elements; |
|||
|
|||
for (; plugins < plugins_last; plugins++) |
|||
plugins_dispatch(thd, *plugins, (void*) event); |
|||
} |
|||
} |
|||
|
|||
|
|||
#else /* EMBEDDED_LIBRARY */
|
|||
|
|||
|
|||
void mysql_audit_initialize() |
|||
{ |
|||
} |
|||
|
|||
|
|||
void mysql_audit_finalize() |
|||
{ |
|||
} |
|||
|
|||
|
|||
int initialize_audit_plugin(st_plugin_int *plugin) |
|||
{ |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
int finalize_audit_plugin(st_plugin_int *plugin) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void mysql_audit_release(THD *thd) |
|||
{ |
|||
} |
|||
|
|||
|
|||
#endif /* EMBEDDED_LIBRARY */
|
@ -0,0 +1,131 @@ |
|||
#ifndef SQL_AUDIT_INCLUDED |
|||
#define SQL_AUDIT_INCLUDED |
|||
|
|||
/* Copyright (C) 2007 MySQL AB |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
|
|||
#include <mysql/plugin_audit.h> |
|||
|
|||
extern unsigned long mysql_global_audit_mask[]; |
|||
|
|||
|
|||
extern void mysql_audit_initialize(); |
|||
extern void mysql_audit_finalize(); |
|||
|
|||
|
|||
extern void mysql_audit_init_thd(THD *thd); |
|||
extern void mysql_audit_free_thd(THD *thd); |
|||
|
|||
|
|||
extern void mysql_audit_notify(THD *thd, uint event_class, |
|||
uint event_subtype, ...); |
|||
extern void mysql_audit_release(THD *thd); |
|||
|
|||
#define MAX_USER_HOST_SIZE 512 |
|||
static inline uint make_user_name(THD *thd, char *buf) |
|||
{ |
|||
Security_context *sctx= thd->security_ctx; |
|||
return strxnmov(buf, MAX_USER_HOST_SIZE, |
|||
sctx->priv_user ? sctx->priv_user : "", "[", |
|||
sctx->user ? sctx->user : "", "] @ ", |
|||
sctx->host ? sctx->host : "", " [", |
|||
sctx->ip ? sctx->ip : "", "]", NullS) - buf; |
|||
} |
|||
|
|||
/** |
|||
Call audit plugins of GENERAL audit class, MYSQL_AUDIT_GENERAL_LOG subtype. |
|||
|
|||
@param[in] thd |
|||
@param[in] time time that event occurred |
|||
@param[in] user User name |
|||
@param[in] userlen User name length |
|||
@param[in] cmd Command name |
|||
@param[in] cmdlen Command name length |
|||
@param[in] query Query string |
|||
@param[in] querylen Query string length |
|||
*/ |
|||
|
|||
static inline |
|||
void mysql_audit_general_log(THD *thd, time_t time, |
|||
const char *user, uint userlen, |
|||
const char *cmd, uint cmdlen, |
|||
const char *query, uint querylen) |
|||
{ |
|||
#ifndef EMBEDDED_LIBRARY |
|||
if (mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK) |
|||
{ |
|||
CHARSET_INFO *clientcs= thd ? thd->variables.character_set_client |
|||
: global_system_variables.character_set_client; |
|||
|
|||
mysql_audit_notify(thd, MYSQL_AUDIT_GENERAL_CLASS, MYSQL_AUDIT_GENERAL_LOG, |
|||
0, time, user, userlen, cmd, cmdlen, |
|||
query, querylen, clientcs, 0); |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
/** |
|||
Call audit plugins of GENERAL audit class. |
|||
event_subtype should be set to one of: |
|||
MYSQL_AUDIT_GENERAL_ERROR |
|||
MYSQL_AUDIT_GENERAL_RESULT |
|||
|
|||
@param[in] thd |
|||
@param[in] event_subtype Type of general audit event. |
|||
@param[in] error_code Error code |
|||
@param[in] msg Message |
|||
*/ |
|||
static inline |
|||
void mysql_audit_general(THD *thd, uint event_subtype, |
|||
int error_code, const char *msg) |
|||
{ |
|||
#ifndef EMBEDDED_LIBRARY |
|||
if (mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK) |
|||
{ |
|||
time_t time= my_time(0); |
|||
uint msglen= msg ? strlen(msg) : 0; |
|||
const char *query, *user; |
|||
uint querylen, userlen; |
|||
char user_buff[MAX_USER_HOST_SIZE]; |
|||
CHARSET_INFO *clientcs; |
|||
ha_rows rows; |
|||
|
|||
if (thd) |
|||
{ |
|||
query= thd->query(); |
|||
querylen= thd->query_length(); |
|||
user= user_buff; |
|||
userlen= make_user_name(thd, user_buff); |
|||
clientcs= thd->variables.character_set_client; |
|||
rows= thd->warning_info->current_row_for_warning(); |
|||
} |
|||
else |
|||
{ |
|||
query= user= 0; |
|||
querylen= userlen= 0; |
|||
clientcs= global_system_variables.character_set_client; |
|||
rows= 0; |
|||
} |
|||
|
|||
mysql_audit_notify(thd, MYSQL_AUDIT_GENERAL_CLASS, event_subtype, |
|||
error_code, time, user, userlen, msg, msglen, |
|||
query, querylen, clientcs, rows); |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
|
|||
#endif /* SQL_AUDIT_INCLUDED */ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue