List:Commits« Previous MessageNext Message »
From:Antony T Curtis Date:December 3 2007 7:35pm
Subject:Re: bk commit into 6.0 tree (acurtis:1.2699) WL#3771
View as plain text  
On 3 Dec, 2007, at 10:30, Sergei Golubchik wrote:

> Hi!
>
> On Nov 29, antony@stripped wrote:
>> ChangeSet@stripped, 2007-11-29 14:40:36-08:00, acurtis@stripped +34  
>> -0
>>  WL#3771 - Plugable Audit Interface
>>    First commit for review
>>    Have run default tests with/without plugin:
>>    mysql-test-run.pl --mysqld=--plugin-dir=<path to plugin>
>>                      --mysqld=--plugin-load=adt_null.so
>
>>  include/Makefile.am@stripped, 2007-11-29 14:40:15-08:00, acurtis@stripped 
>>  +2 -1
>>    add new source files: mysql/ftparser.h mysql/audit.h
>
> in wl#4017 patch (query rewrite plugin) BrianM also had a new file for
> the rewrite plugin. But he called it rewrite_plugin.h.
> I think that having _plugin as a part of include file name is a good
> idea - we may have other non-plugin include files someday. Even better
> to have a plugin_ prefix, not suffix, to keep all these files  
> together.
> See also my comment to your change in myisam/ha_myisam.cc (below).
>
> Please rename your include files to plugin_ftparser.h and  
> plugin_audit.h

Ok,

>
>>  include/mysql/ftparser.h@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped 
>>  +211 -0
>>    New BitKeeper file ``include/mysql/ftparser.h''
>
> It's good that you moved ftparser related code into a separate file.
> Thanks.
>
>>  plugin/audit_null/configure.in@stripped, 2007-11-29 14:40:19-08:00,
> acurtis@stripped 
>>  +9 -0
>>    New BitKeeper file ``plugin/audit_null/configure.in''
>
> did you try to build audit_plugin outside of MySQL source tree ?
> if not, and it's not needed (which, I suspect is the case) you don't
> need configure.in, NEWS/AUTHORS/ChangeLog and other files that  
> automake
>
>> diff -Nrup a/storage/myisam/ha_myisam.cc b/storage/myisam/ 
>> ha_myisam.cc
>> --- a/storage/myisam/ha_myisam.cc    2007-10-25 00:39:55 -07:00
>> +++ b/storage/myisam/ha_myisam.cc    2007-11-29 14:40:18 -08:00
>> @@ -20,7 +20,7 @@
>>
>> #define MYSQL_SERVER 1
>> #include "mysql_priv.h"
>> -#include <mysql/plugin.h>
>> +#include <mysql/ftparser.h>
>
> basically, what you've done is a change in the API (but not in ABI) -
> old plugins win't compile anymore, they'll need to be changed.
> I don't think it was necessary. And (I'm looking in a randomly picked
> directory in /usr/include) in libgnome one is expected to write only
> #include <libgnome/libgnome.h> and other 13 include files are
> included by libgnome.h
>
> Let's do the same - it's good to have plugin_ftparser.h,  
> plugin_audit.h,
> plugin_rewrite.h, it helps to keep include files structured and  
> maintainable.
> But it doesn't need to affect the API. Make all these plugin_*.h
> files to be included from the main plugin.h

Ok,

Original reason for why I did it - I was progressively adding fields  
to the audit interface and I did not want to cause recompilation of  
all of mysqld again just for adding a couple of members to a struct.

>
>> #include <m_ctype.h>
>> #include <my_bit.h>
>> #include <myisampack.h>
>> diff -Nrup a/include/mysql/plugin.h b/include/mysql/plugin.h
>> --- a/include/mysql/plugin.h 2007-08-30 23:19:49 -07:00
>> +++ b/include/mysql/plugin.h 2007-11-29 14:40:16 -08:00
>> @@ -135,6 +136,7 @@ typedef int (*mysql_show_var_func)(MYSQL
>> #define PLUGIN_VAR_STR          0x0005
>> #define PLUGIN_VAR_ENUM         0x0006
>> #define PLUGIN_VAR_SET          0x0007
>> +#define PLUGIN_VAR_OPAQUE       0x0008
>
> please remove it, as we've discussed on irc

Ok,

>
>> #define PLUGIN_VAR_UNSIGNED     0x0080
>> #define PLUGIN_VAR_THDLOCAL     0x0100 /* Variable is per- 
>> connection */
>> #define PLUGIN_VAR_READONLY     0x0200 /* Server variable is read  
>> only */
>> @@ -143,6 +145,7 @@ typedef int (*mysql_show_var_func)(MYSQL
>> #define PLUGIN_VAR_NOCMDARG     0x1000 /* No argument for cmd line */
>> #define PLUGIN_VAR_RQCMDARG     0x0000 /* Argument required for cmd  
>> line */
>> #define PLUGIN_VAR_OPCMDARG     0x2000 /* Argument optional for cmd  
>> line */
>> +#define PLUGIN_VAR_NOGLOBAL     0x4000 /* per-connection has no  
>> global */
>
> please remove it, as we've discussed on irc

Ok

>
>> #define PLUGIN_VAR_MEMALLOC     0x8000 /* String needs memory  
>> allocated */
>>
>> struct st_mysql_sys_var;
>> diff -Nrup a/sql/ha_ndbcluster_binlog.cc b/sql/ 
>> ha_ndbcluster_binlog.cc
>> --- a/sql/ha_ndbcluster_binlog.cc    2007-11-13 03:52:17 -08:00
>> +++ b/sql/ha_ndbcluster_binlog.cc    2007-11-29 14:40:16 -08:00
>> @@ -1610,6 +1615,9 @@ end:
>>         if (ndb_extra_logging)
>>           ndb_report_waiting(type_str, max_timeout,
>>                              "distributing", ndb_schema_object->key);
>> +
>> +        /* Release any held audit resources */
>> +        mysql_audit_release(thd);
>
> why here ?

I added these to occur anywhere where I thought it may block/wait for  
a period of time so that it would not cause a situation where a plugin  
cannot unload.

<snip>
>
>>     }
>>   }
>>   (void) pthread_mutex_lock(&LOCK_open);
>> diff -Nrup a/sql/scheduler.cc b/sql/scheduler.cc
>> --- a/sql/scheduler.cc   2007-11-02 12:39:00 -07:00
>> +++ b/sql/scheduler.cc   2007-11-29 14:40:17 -08:00
>> @@ -396,6 +397,8 @@ static void libevent_connection_close(TH
>>
>>   thd->killed= THD::KILL_CONNECTION;          // Avoid error messages
>>
>> +  mysql_audit_release(thd);
>> +
>
> why here ? it should be done later, e.g. in thd->cleanup()
> as late as possible, to ensure there can be no more audit events
> after mysql_audit_release()

ok.

<snip>
>
>>       pthread_mutex_lock(&di->mutex);
>>     }
>>     if (di->tables_in_use)
>> diff -Nrup a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in
>> --- a/sql/sql_builtin.cc.in  2006-12-30 17:28:54 -08:00
>> +++ b/sql/sql_builtin.cc.in  2007-11-29 14:40:17 -08:00
>> @@ -13,6 +13,7 @@
>>    along with this program; if not, write to the Free Software
>>    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA   
>> 02110-1301  USA */
>>
>> +#include <my_global.h>
>
> why ?

The audit plugin event struct has a time_t value. Actually, as the  
tree currently stands, it is unnecessary but if I have plugin.h  
include the audit interface, then it is neccessary.

>
>> #include <mysql/plugin.h>
>>
>> typedef struct st_mysql_plugin builtin_plugin[];
>> diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
>> --- a/sql/sql_class.h    2007-11-22 11:45:22 -08:00
>> +++ b/sql/sql_class.h    2007-11-29 14:40:17 -08:00
>> @@ -1100,6 +1100,10 @@ public:
>>   ulong max_client_packet_length;
>>
>>   HASH      handler_tables_hash;
>> +#ifndef EMBEDDED_LIBRARY
>> +  DYNAMIC_ARRAY audit_class_plugins;
>> +  uint64 audit_class_mask1;
>
> 1. what does 1 mean in mask1 ?
> 2. both fields need a comment

For the future, when it spills over to requiring 2 or more longlongs  
(when we have more than 64 audit classes) then the naming doesn't need  
to be modified. 1 signifies the first word in the mask.

>
>> +#endif
>>   /*
>>     One thread can hold up to one named user-level lock. This  
>> variable
>>     points to a lock object if the lock is present. See  
>> item_func.cc and
>> diff -Nrup a/sql/protocol.cc b/sql/protocol.cc
>> --- a/sql/protocol.cc    2007-11-01 04:32:31 -07:00
>> +++ b/sql/protocol.cc    2007-11-29 14:40:17 -08:00
>> @@ -132,6 +133,12 @@ void net_send_error(THD *thd, uint sql_e
>>
>>   DBUG_ASSERT(!thd->spcont);
>>
>> +   
>> MYSQL_AUDIT_GENERAL 
>> (thd,MYSQL_AUDIT_GENERAL_ERROR,sql_errno,my_time(0),
>> +                      0,0,err,err?strlen(err):0,
>> +                      thd->query,thd->query_length,
>> +                      thd->variables.character_set_client,
>> +                      thd->row_count);
>
> this wasn't part of the WL

I suspected that if one wishes to audit queries, then it would be  
desirable to be notified if the query had an error or was successful.

>
>>   if (net && net->no_send_error)
>>   {
>>     thd->clear_error();
>> @@ -210,6 +217,12 @@ send_ok(THD *thd, ha_rows affected_rows,
>>   NET *net= &thd->net;
>>   uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
>>   DBUG_ENTER("send_ok");
>> +
>> +  MYSQL_AUDIT_GENERAL(thd,MYSQL_AUDIT_GENERAL_RESULT,0,my_time(0),
>> +                      0,0,message,message?strlen(message):0,
>> +                      thd->query,thd->query_length,
>> +                      thd->variables.character_set_client,
>> +                      affected_rows);
>
> this wasn't part of the WL

ditto.
from the worklog "The number of affected/retrieved rows"

>
>>   if (net->no_send_ok || !net->vio) // hack for re-parsing queries
>>   {
>> diff -Nrup a/sql/sql_connect.cc b/sql/sql_connect.cc
>> --- a/sql/sql_connect.cc 2007-11-13 03:52:18 -08:00
>> +++ b/sql/sql_connect.cc 2007-11-29 14:40:17 -08:00
>> @@ -318,6 +319,9 @@ check_user(THD *thd, enum enum_server_co
>>   DBUG_ENTER("check_user");
>>   LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
>>
>> +  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_AUTHENTICATE,0,
>> +                       "USER",&db_str,0,0,0);
>
> it wasn't part of the WL

 From the worklog.... "to do security auditing of all security related  
operations".

>
>>   /*
>>     Clear thd->db as it points to something, that will be freed when
>>     connection is closed. We don't want to accidentally free a wrong
>> @@ -673,6 +677,8 @@ static int check_connection(THD *thd)
>> #ifdef SIGNAL_WITH_VIO_CLOSE
>>   thd->set_active_vio(net->vio);
>> #endif
>> +  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CONNECT,0,
>> +                       "CONNECTION",0,0,0,0);
>
> it wasn't part of the WL

 From the worklog.... "to do security auditing of all security related  
operations".

>
>>   if (!thd->main_security_ctx.host)         // If TCP/IP connection
>>   {
>> @@ -997,6 +1003,10 @@ bool login_connection(THD *thd)
>> void end_connection(THD *thd)
>> {
>>   NET *net= &thd->net;
>> +
>> +  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_DISCONNECT,0,
>> +                       "CONNECTION",0,0,0,0);
>
> it wasn't part of the WL

 From the worklog.... "to do security auditing of all security related  
operations".

<snip>
>
>>     end_connection(thd);
>>
>> end_thread:
>> diff -Nrup a/sql/log.cc b/sql/log.cc
>> --- a/sql/log.cc 2007-11-14 02:01:42 -08:00
>> +++ b/sql/log.cc 2007-11-29 14:40:16 -08:00
>> @@ -4387,6 +4397,33 @@ static void print_buffer_to_file(enum lo
>>   VOID(pthread_mutex_lock(&LOCK_error_log));
>>
>>   skr= my_time(0);
>> +
>> +  {
>> +    char user_host_buff[MAX_USER_HOST_SIZE];
>> +    THD *thd;
>> +    ulong id= 0;
>> +    uint user_host_len= 0;
>> +
>> +    if ((thd= current_thd))
>> +    {
>> +      Security_context *sctx= thd->security_ctx;
>> +      id= thd->thread_id;
>> +      user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
>> +                              sctx->priv_user ? sctx->priv_user :  
>> "", "[",
>> +                              sctx->user ? sctx->user : "", "] @ ",
>> +                              sctx->host ? sctx->host : "", " [",
>> +                              sctx->ip ? sctx->ip : "", "]",  
>> NullS) -
>> +                                                               
>> user_host_buff;
>> +    }
>> +    MYSQL_AUDIT_GENERAL(thd, MYSQL_AUDIT_GENERAL_CONSOLE,  
>> error_code, skr,
>> +                        user_host_buff, user_host_len,
>> +                        (level == ERROR_LEVEL ? "ERROR" :
>> +                         level == WARNING_LEVEL ? "Warning" :  
>> "Note"),
>> +                        (level == ERROR_LEVEL ? 5 :
>> +                         level == WARNING_LEVEL ? 7 : 4),
>> +                        buffer, buffer_length,0,0);
>> +  }
>> +
>
> it wasn't part of the WL

Ok, I shall remove this.

>
>>   localtime_r(&skr, &tm_tmp);
>>   start=&tm_tmp;
>>
>> diff -Nrup a/sql/sql_acl.cc b/sql/sql_acl.cc
>> --- a/sql/sql_acl.cc 2007-11-13 03:52:18 -08:00
>> +++ b/sql/sql_acl.cc 2007-11-29 14:40:17 -08:00
>> @@ -0,0 +1,95 @@
>
> WL (at least what was approved as HLS/LLD) did not need any changes to
> sql_acl.cc. Changes to grants are tracked using general audit class.
> failed privilege checks - using mysql error class.

I see in WL customer requirements "failed login/access information"  
and "accessed table/view/other objects name and action"

>
>> diff -Nrup a/include/mysql/audit.h b/include/mysql/audit.h
>> --- /dev/null    Wed Dec 31 16:00:00 196900
>> +++ b/include/mysql/audit.h  2007-11-29 14:40:19 -08:00
>> @@ -0,0 +1,126 @@
>> +/* 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_INTERFACE_VERSION 0x0100
>> +
>> +
>> +struct mysql_event
>> +{
>> +  int event_class;
>> +};
>> +
>> +#ifdef __cplusplus
>> +#define DECLARE_AUDIT_EVENT_DATA(name) \
>> +struct mysql_event_ ## name :public mysql_event {
>> +#else
>> +#define DECLARE_AUDIT_EVENT_DATA(name) \
>> +struct mysql_event_ ## name {          \
>> +  int event_class;
>> +#endif
>
> There's no need to use different code for C and C++
> please remove the #ifdef
>
>> +#define END_DECLARE_AUDIT_EVENT_DATA }
>
> I would remove DECLARE_AUDIT_EVENT_DATA and  
> END_DECLARE_AUDIT_EVENT_DATA
> macros, using struct ... and } in place, as appropriate.
> you don't save or simplify much to justify them.
> (unlike your macro helpers related to MYSQL_xxxVAR_yyy variables,
> they are useful indeed)

This was done to reduce the amount of explicit typecasting done in the  
code... I can remove them at the cost of more explicit typecasting.


>
>> +
>> +
>> +/ 
>> *************************************************************************
>> +  AUDIT CLASS : GENERAL
>> +*/
>> +
>> +#define MYSQL_AUDIT_GENERAL_CLASS 0
>> +#define MYSQL_AUDIT_GENERAL_CLASSMASK1 (1 <<  
>> MYSQL_AUDIT_GENERAL_CLASS)
>> +#define MYSQL_AUDIT_GENERAL_LOG 0
>> +#define MYSQL_AUDIT_GENERAL_ERROR 1
>> +#define MYSQL_AUDIT_GENERAL_RESULT 2
>> +#define MYSQL_AUDIT_GENERAL_CONSOLE 3
>
> only MYSQL_AUDIT_GENERAL_LOG was requested in this WL

Because result summary was wanted, _ERROR and _RESULT was inferred.
I agree that _CONSOLE was not requested at all.

>
>> +DECLARE_AUDIT_EVENT_DATA(general)
>> +  int general_error_code;
>> +  unsigned long general_thread_id;
>> +  time_t general_time;
>> +  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_rows;
>> +END_DECLARE_AUDIT_EVENT_DATA;
>
> why "general_" prefix ?

I was in a verbose mood and since I anticipate extension of structs  
for future classes, this makes it clear where the attribute was  
declared.

>
>> +
>> +
>> +/ 
>> *************************************************************************
>> +  AUDIT CLASS : SECURITY
>> +*/
>> +
>> +#define MYSQL_AUDIT_SECURITY_CLASS 1
>> +#define MYSQL_AUDIT_SECURITY_CLASSMASK1 (1 <<  
>> MYSQL_AUDIT_SECURITY_CLASS)
>
> This wasn't specified in WL. mysql error audit class was, but it's not
> implemented

This was my interpretation of customer requirement for "all security  
related operations".

>
>> +#define MYSQL_AUDIT_SECURITY_RELOAD 0
>> +#define MYSQL_AUDIT_SECURITY_AUTHENTICATE 1
>> +#define MYSQL_AUDIT_SECURITY_CONNECT 2
>> +#define MYSQL_AUDIT_SECURITY_DISCONNECT 3
>> +#define MYSQL_AUDIT_SECURITY_CHECK_ENTER 4
>> +#define MYSQL_AUDIT_SECURITY_CHECK_LEAVE 5
>> +#define MYSQL_AUDIT_SECURITY_GRANT 6
>> +#define MYSQL_AUDIT_SECURITY_REVOKE 7
>> +DECLARE_AUDIT_EVENT_DATA(security)
>> +  int security_error_code;
>> +  unsigned long security_thread_id;
>> +  const char *security_host;
>> +  unsigned int security_host_length;
>> +  const char *security_user;
>> +  unsigned int security_user_length;
>> +  const char *security_priv_user;
>> +  unsigned int security_priv_user_length;
>> +  const char *security_ip;
>> +  unsigned int security_ip_length;
>> +  const char *security_host_or_ip;
>> +  unsigned int security_host_or_ip_length;
>> +  unsigned long security_global_access;
>> +  unsigned long security_schema_access;
>> +
>> +  const char *security_type;
>> +  unsigned int security_type_length;
>> +  const char *security_schema;
>> +  unsigned int security_schema_length;
>> +  const char *security_object;
>> +  unsigned int security_object_length;
>> +  const char *security_element;
>> +  unsigned int security_element_length;
>> +
>> +  unsigned long security_object_rights;
>> +END_DECLARE_AUDIT_EVENT_DATA;
>> +
>> +
>> +/ 
>> *************************************************************************
>> +  Here we define the descriptor structure, that is referred from
>> +  st_mysql_plugin.
>> +*/
>> +
>> +struct st_mysql_audit
>> +{
>> +  int interface_version;
>> +  const unsigned long long *class_mask;
>
> what is class_mask ? how is the mask defined ?

bitwise OR of the declared class mask macros.

>
>> +  void (*release_thd)(MYSQL_THD);
>> +  void (*event_notify)(MYSQL_THD, const struct mysql_event *);
>> +};
>> +
>
> no comments at all in this file. It *must* be commented, documenting  
> itself
> exhaustively. See ftparser.h for example

ok. Will add comments.

>
>> +
>> +#endif
>> diff -Nrup a/plugin/audit_null/audit_null.c b/plugin/audit_null/ 
>> audit_null.c
>> --- /dev/null    Wed Dec 31 16:00:00 196900
>> +++ b/plugin/audit_null/audit_null.c 2007-11-29 14:40:19 -08:00
>> @@ -0,0 +1,142 @@
>> +/* 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 <my_global.h>
>> +#include <my_sys.h>
>> +#include <my_atomic.h>
>
> don't use internal MySQL include files in the example plugins
> (instead of my_atomic you can use a mutex or simply allow your
> counter to be approximate, accessing it without a lock -
> it's an example after all)

Ok.

>
>> +#include <mysql/audit.h>
>> +
>> +#if !defined(__attribute__) && (defined(__cplusplus) || ! 
>> defined(__GNUC__)  || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
>> +#define __attribute__(A)
>> +#endif
>> +
>> +static volatile uint32 number_of_calls; /* for SHOW STATUS, see  
>> below */
>> +static my_atomic_rwlock_t rwl;
>> +
>> +
>> +/*
>> +  Initialize the plugin at server start or plugin installation.
>> +
>> +  SYNOPSIS
>> +    null_audit_plugin_init()
>> +
>> +  DESCRIPTION
>> +    Does nothing.
>> +
>> +  RETURN VALUE
>> +    0                    success
>> +    1                    failure (cannot happen)
>> +*/
>> +
>> +static int null_audit_plugin_init(void *arg __attribute__((unused)))
>> +{
>> +  my_atomic_rwlock_init(&rwl);
>> +  number_of_calls= 0;
>> +  return(0);
>> +}
>> +
>> +
>> +/*
>> +  Terminate the plugin at server shutdown or plugin deinstallation.
>> +
>> +  SYNOPSIS
>> +    null_audit_plugin_deinit()
>> +    Does nothing.
>> +
>> +  RETURN VALUE
>> +    0                    success
>> +    1                    failure (cannot happen)
>> +
>> +*/
>> +
>> +static int null_audit_plugin_deinit(void *arg  
>> __attribute__((unused)))
>> +{
>> +  my_atomic_rwlock_destroy(&rwl);
>> +  printf("audit_null was invoked %lu times\n",
>> +         (ulong) number_of_calls);
>> +  return(0);
>> +}
>> +
>> +
>> +/*
>> +  Foo
>> +
>> +  SYNOPSIS
>> +    null_notify()
>> +      thd                connection context
>> +
>> +  DESCRIPTION
>> +*/
>> +
>> +static void null_notify(MYSQL_THD thd __attribute__((unused)),
>> +                        const struct mysql_event *event
>> +                        __attribute__((unused)))
>> +{
>> +  my_atomic_rwlock_wrlock(&rwl);
>> +  my_atomic_add32(&number_of_calls, 1);
>> +  my_atomic_rwlock_wrunlock(&rwl);
>> +}
>> +
>> +
>> +static unsigned long long null_audit_mask[]=
>> +{
>> +  (unsigned long long) -1
>> +};
>> +
>> +
>> +/*
>> +  Plugin type-specific descriptor
>> +*/
>> +
>> +static struct st_mysql_audit null_audit_descriptor=
>> +{
>> +  MYSQL_AUDIT_INTERFACE_VERSION,    /* interface version      */
>> +  null_audit_mask,                  /* class mask             */
>> +  NULL,                             /* release_thd function   */
>> +  null_notify                       /* notify function        */
>> +};
>> +
>> +/*
>> +  Plugin status variables for SHOW STATUS
>> +*/
>> +
>> +static struct st_mysql_show_var simple_status[]=
>> +{
>> +  {"null_audit_called", (char *)&number_of_calls, SHOW_INT},
>> +  {0,0,0}
>> +};
>> +
>> +
>> +/*
>> +  Plugin library descriptor
>> +*/
>> +
>> +mysql_declare_plugin(null_audit)
>> +{
>> +  MYSQL_AUDIT_PLUGIN,         /* type                            */
>> +  &null_audit_descriptor,     /* descriptor                      */
>> +  "NULL_AUDIT",               /* name                            */
>> +  "MySQL AB",                 /* author                          */
>> +  "Simple NULL Audit",        /* description                     */
>> +  PLUGIN_LICENSE_GPL,
>> +  null_audit_plugin_init,     /* init function (when loaded)     */
>> +  null_audit_plugin_deinit,   /* deinit function (when unloaded) */
>> +  0x0001,                     /* version                         */
>> +  simple_status,              /* status variables                */
>> +  NULL,                       /* system variables                */
>> +  NULL
>> +}
>> +mysql_declare_plugin_end;
>> +
>> diff -Nrup a/sql/sql_audit.h b/sql/sql_audit.h
>> --- /dev/null    Wed Dec 31 16:00:00 196900
>> +++ b/sql/sql_audit.h    2007-11-29 14:40:18 -08:00
>> @@ -0,0 +1,95 @@
>> +/* 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 EMBEDDED_LIBRARY
>> +
>> +#include <mysql/audit.h>
>> +
>> +
>> +extern uint64 mysql_global_audit_mask1;
>
> there're no comments in this file either
>
>> +
>> +
>> +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,
>> +                               int error_code, ...);
>
> remove error_code (it should be in the varargs part)

Ok.

>
>> +extern void mysql_audit_release(THD *thd);
>> +
>> +
>> +
>> +
>
> please remove end-of-line blanks and expands tabs in all new files.

Ok.

>
>> +#define MYSQL_AUDIT_GENERAL(thd,event_subtype,rc,time,          \
>> +                            user,userlen,cmd,cmdlen,            \
>> +                            query,querylen,clientcs,rows) do {  \
>> +  if (mysql_global_audit_mask1 & MYSQL_AUDIT_GENERAL_CLASSMASK1)\
>> +  {                                                             \
>> +    time_t audit_time= (time);                                  \
>> +    const char *audit_user= (user), *audit_cmd= (cmd);          \
>> +    const char *audit_query= (query);                           \
>> +    uint audit_user_len= (userlen), audit_cmd_len= (cmdlen);    \
>> +    uint audit_query_len= (querylen);                           \
>> +    CHARSET_INFO *audit_client_cs= (clientcs);                  \
>> +    ha_rows audit_rows=(rows);                                  \
>> +    mysql_audit_notify((thd), MYSQL_AUDIT_GENERAL_CLASS,        \
>> +                       (event_subtype), (rc), audit_time,       \
>> +                       audit_user, audit_user_len,              \
>> +                       audit_cmd, audit_cmd_len,                \
>> +                       audit_query, audit_query_len,            \
>> +                       audit_client_cs,audit_rows);             \
>> +  }                                                             \
>> +} while (0)
>
> it's C++, use inline functions instead of complex macros

Ok,

>
>> +
>> +
>> +
>> +#define MYSQL_AUDIT_SECURITY(thd,event_subtype,rc,type,schema,  \
>> +                             object,element,rights) do {        \
>> +  if (mysql_global_audit_mask1 & MYSQL_AUDIT_SECURITY_CLASSMASK1)\
>> +  {                                                             \
>> +    LEX_STRING audit_object_type= {C_STRING_WITH_LEN(type)};    \
>> +    LEX_STRING *audit_schema= (schema);                         \
>> +    LEX_STRING *audit_object= (object);                         \
>> +    LEX_STRING *audit_element= (element);                       \
>> +    ulong audit_rights= (rights);                               \
>> +    mysql_audit_notify((thd), MYSQL_AUDIT_SECURITY_CLASS,       \
>> +                       (event_subtype),(rc),&audit_object_type, \
>> +                       &audit_schema,&audit_object,             \
>> +                       &audit_element,audit_rights);            \
>> +  }                                                             \
>> +} while (0)
>> +
>> +#else /* EMBEDDED_LIBRARY */
>> +
>> +/* In EMBEDDED_LIBRARY builds, these do nothing */
>> +
>> +#define MYSQL_AUDIT_GENERAL(thd,event_subtype,rc,time,          \
>> +                            user,userlen,cmd,cmdlen,            \
>> +                            query,querylen,clientcs,rows) do {  \
>> +} while (0)
>> +#define MYSQL_AUDIT_SECURITY(thd,event_subtype,rc,type,schema,  \
>> +                             object,element,rights) do {        \
>> +} while (0)
>> +
>> +#define mysql_audit_release(thd)  do { } while (0)
>> +
>> +
>> +#endif /* EMBEDDED_LIBRARY */
>> diff -Nrup a/sql/sql_audit.cc b/sql/sql_audit.cc
>> --- /dev/null    Wed Dec 31 16:00:00 196900
>> +++ b/sql/sql_audit.cc   2007-11-29 14:40:18 -08:00
>> @@ -0,0 +1,502 @@
>> +/* 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_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
>> +
>> +uint64 mysql_global_audit_mask1= 0;
>> +
>> +
>> +static void event_class_dispatch(THD *thd, const struct  
>> mysql_event *event);
>> +
>> +typedef void (*audit_handler_t)(THD *thd, uint event_subtype,
>> +                                int error_code, 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,
>> +                                  int error_code, va_list ap)
>> +{
>> +  mysql_event_general event;
>> +  event.event_class= MYSQL_AUDIT_GENERAL_CLASS;
>> +  event.general_error_code= error_code;
>> +  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, &event);
>> +}
>> +
>> +
>> +/**
>> +  MYSQL_AUDIT_SECURITY_CLASS handler
>> +
>> +  @param[in] thd
>> +  @param[in] event_subtype
>> +  @param[in] error_code
>> +  @param[in] ap
>> +
>> +*/
>> +
>> +static void security_class_handler(THD *thd, uint event_subtype,
>> +                                   int error_code, va_list ap)
>> +{
>> +  mysql_event_security event;
>> +  LEX_STRING *str;
>> +
>> +  bzero(&event, sizeof(event));
>> +  event.event_class= MYSQL_AUDIT_SECURITY_CLASS;
>> +  event.security_error_code= error_code;
>> +
>> +  if (thd)
>> +  {
>> +    event.security_thread_id= thd->thread_id;
>> +    Security_context *ctx= thd->security_ctx;
>> +    event.security_host= ctx->host;
>> +    event.security_host_length=
>> +      event.security_host ? strlen(event.security_host) : 0;
>> +    event.security_user= ctx->user;
>> +    event.security_user_length=
>> +      event.security_user ? strlen(event.security_user) : 0;
>> +    event.security_priv_user= ctx->priv_user;
>> +    event.security_priv_user_length=
>> +      event.security_priv_user ?  
>> strlen(event.security_priv_user) : 0;
>> +    event.security_ip= ctx->ip;
>> +    event.security_ip_length=
>> +      event.security_ip ? strlen(event.security_ip) : 0;
>> +    event.security_host_or_ip= ctx->host_or_ip;
>> +    event.security_host_or_ip_length=
>> +      event.security_host_or_ip ?  
>> strlen(event.security_host_or_ip) : 0;
>> +    event.security_global_access= ctx->master_access;
>> +    event.security_schema_access= ctx->db_access;
>> +  }
>> +
>> +  if ((str= va_arg(ap, LEX_STRING *)))
>> +  {
>> +    event.security_type= str->str;
>> +    event.security_type_length= str->length;
>> +  }
>> +  if ((str= va_arg(ap, LEX_STRING *)))
>> +  {
>> +    event.security_schema= str->str;
>> +    event.security_schema_length= str->length;
>> +  }
>> +  if ((str= va_arg(ap, LEX_STRING *)))
>> +  {
>> +    event.security_object= str->str;
>> +    event.security_object_length= str->length;
>> +  }
>> +  if ((str= va_arg(ap, LEX_STRING *)))
>> +  {
>> +    event.security_element= str->str;
>> +    event.security_element_length= str->length;
>> +  }
>> +  event.security_object_rights= va_arg(ap, ulong);
>> +
>> +  event_class_dispatch(thd, &event);
>> +}
>> +
>> +
>> +static audit_handler_t audit_handlers[] =
>> +{
>> +  /* MYSQL_AUDIT_GENERAL_CLASS */   general_class_handler,
>> +  /* MYSQL_AUDIT_SECURITY_CLASS */  security_class_handler,
>
> these two comments inside audit_handlers[] are redundant
> it's like
>   i++; // increment i

I originally had less informative function names - I will correct this.

>
>> +  NULL
>
> it doesn't have to be NULL-terminated. Furthermore it's confusing and
> wrong to make it NULL-terminated

Laziness on my part... Originally it was null terminated and I haven't  
removed it.

>
>
>> +};
>> +
>> +static const uint audit_handlers_count=
>> +  (sizeof(audit_handlers) / sizeof(audit_handler_t)) - 1;
>> +
>> +
>> +/**
>> +  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;
>> +  uint64 event_class_mask1= (1 << event_class);
>> +  st_mysql_audit *data= plugin_data(plugin, struct st_mysql_audit  
>> *);
>> +
>> +  /* Check if this plugin is interested in the event */
>> +  if (!(data->class_mask[0] & event_class_mask1))
>> +    return 0;
>
> So, you preferred to scan the list of plugins...
> (in the schema that I suggested it would be not necessary)
> okay, I think it shouldn't be a problem for a resonable (read: small)
> number of plugins. I don't see us having a couple of thousands
> of active audit plugins yet.
>
>> +
>> +  /* 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);
>> +  }
>> +  else
>> +  {
>> +    plugin_ref *plugins, *plugins_last;
>> +
>> +    plugins= (plugin_ref*) thd->audit_class_plugins.buffer;
>> +    plugins_last= plugins + thd->audit_class_plugins.elements;
>> +    for (; plugins < plugins_last; plugins++)
>> +    {
>> +      st_mysql_audit *data2= plugin_data(*plugins, struct  
>> st_mysql_audit *);
>> +
>> +      /* Check if we already have acquired this plugin */
>> +      if (data == data2)
>> +        return 0;
>> +    }
>
> you don't need this loop. a plugin can be already acquired only if
> this plugin has registered for many audit classes, and it was acquired
> for a different audit class. Thus, instead of the loop you can write
>
>  if (thd->audit_class_mask1 & data->class_mask[0]) // already acquired
>    return 0;
>
> there's a boundary case when a plugin was installed after thd has  
> registered
> plugins for this class, as in
>   plugin1 (classA) is installed
>   thd emits event of the classA
>   thd acquires plugin1, adds classA to audit_class_mask1
>   plugin2 (classA + classB) is installed
>   thd emits event of the classB
> in this case my if() will skip plugin2. I believe we can ignore this  
> special
> case and optimize for all plugins being installed.

Ok, I will alter the implementation and document the special case.

>
>> +  }
>> +
>> +  /* 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,
>> +                        int error_code, ...)
>> +{
>> +  va_list ap;
>> +  audit_handler_t *handlers= audit_handlers + event_class;
>> +  uint64 event_class_mask1= (1 << event_class);
>> +
>> +  DBUG_ASSERT(event_class < audit_handlers_count);
>> +
>> +  if (thd && thd->killed == THD::KILL_CONNECTION &&
>> +      !(thd->audit_class_mask1 & event_class_mask1))
>> +    thd= NULL;
>
> why ? (add a comment)

Ok,

>
>> +
>> +  /*
>> +    Check to see if we have acquired the audit plugins for the
>> +    required audit event classes.
>> +  */
>> +  if (thd && !(thd->audit_class_mask1 & event_class_mask1))
>> +  {
>> +    plugin_foreach(thd, acquire_plugins, MYSQL_AUDIT_PLUGIN,  
>> &event_class);
>> +    thd->audit_class_mask1|= event_class_mask1;
>> +  }
>> +
>> +  va_start(ap, error_code);
>> +  (*handlers)(thd, event_subtype, error_code, 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);
>> +  thd->audit_class_mask1= 0;
>> +}
>> +
>> +
>> +/**
>> +  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));
>> +  thd->audit_class_mask1= 0;
>> +}
>> +
>> +
>> +/**
>> +  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);
>> +}
>> +
>> +
>> +static DYNAMIC_ARRAY installed_audit_plugins;
>> +static pthread_mutex_t LOCK_audit;
>
> why do you need a second list of all audit plugins ?
> it'll be a copy of duplicate plugin_hash[MYSQL_AUDIT_PLUGIN].records
> (which you can iterate with plugin_foreach(), as you know)

When sending event notifications when thd==NULL, I did not want to  
rely on obtaining plugin system lock in case where a specific plugin  
has created its own threads and performed some operation which would  
result in deadlock. So implementation is declared so that


>
>> +
>> +
>> +/**
>> +  Initialize Audit global variables
>> +*/
>> +
>> +void mysql_audit_initialize()
>> +{
>> +  (void) pthread_mutex_init(&LOCK_audit, MY_MUTEX_INIT_FAST);
>> +  my_init_dynamic_array(&installed_audit_plugins, sizeof(void*),  
>> 16, 16);
>> +}
>> +
>> +
>> +/**
>> +  Finalize Audit global variables
>> +*/
>> +
>> +void mysql_audit_finalize()
>> +{
>> +  delete_dynamic(&installed_audit_plugins);
>> +  (void) pthread_mutex_destroy(&LOCK_audit);
>> +}
>> +
>> +
>> +/**
>> +  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;
>> +  int rc;
>> +
>> +  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;
>> +
>> +  pthread_mutex_lock(&LOCK_audit);
>> +
>> +  rc= insert_dynamic(&installed_audit_plugins, (uchar*) &plugin- 
>> >data);
>> +
>> +  /* Add the bits the plugin is interested in to the global mask */
>> +  mysql_global_audit_mask1|= data->class_mask[0];
>> +
>> +  pthread_mutex_unlock(&LOCK_audit);
>> +
>> +  return rc;
>> +}
>> +
>> +
>> +/**
>> +  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)
>> +{
>> +  uint64 event_class_mask1= 0;
>> +  st_mysql_audit **data, **data_last;
>> +  uint index, index_to_delete= (uint) -1;
>> +
>> +  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; );
>> +  }
>> +
>> +  pthread_mutex_lock(&LOCK_audit);
>> +
>> +  /* Iterate through all the installed plugins to create new mask */
>> +  data= (st_mysql_audit**) installed_audit_plugins.buffer;
>> +  data_last= data + installed_audit_plugins.elements;
>> +  for (index= 0; data < data_last; data++, index++)
>> +  {
>> +    if (plugin->data == *data)
>> +      index_to_delete= index;
>> +    else
>> +      event_class_mask1|= (*data)->class_mask[0];
>> +  }
>> +
>> +  /* Set the global audit mask */
>> +  mysql_global_audit_mask1= event_class_mask1;
>> +
>> +  /* Remove this plugin from the list */
>> +  if (likely(index_to_delete != (uint) -1))
>> +    delete_dynamic_element(&installed_audit_plugins,  
>> index_to_delete);
>> +  else
>> +  {
>> +    sql_print_error("Plugin '%s' was not found in  
>> installed_audit_plugins",
>> +                    plugin->name.str);
>> +  }
>> +
>> +  pthread_mutex_unlock(&LOCK_audit);
>> +
>> +  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)
>> +{
>> +  uint64 event_class_mask1= (1 << event->event_class);
>> +
>> +  if (thd)
>> +  {
>> +    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++)
>> +    {
>> +      st_mysql_audit *data= plugin_data(*plugins, struct  
>> st_mysql_audit *);
>> +
>> +      /* Check to see if the plugin is interested in this event */
>> +      if (!(data->class_mask[0] & event_class_mask1))
>> +        continue;
>> +
>> +      /* Actually notify the plugin */
>> +      data->event_notify(thd, event);
>> +    }
>> +  }
>> +  else
>> +  {
>> +    st_mysql_audit **data, **data_last;
>> +
>> +    pthread_mutex_lock(&LOCK_audit);
>> +
>> +    /* Use our own list of all audit plugins */
>> +    data= (st_mysql_audit**) installed_audit_plugins.buffer;
>> +    data_last= data + installed_audit_plugins.elements;
>> +    for (; data < data_last; data++)
>> +    {
>> +      if (!((*data)->class_mask[0] & event_class_mask1))
>> +        continue;
>> +
>> +      /* Actually notify the plugin */
>> +      (*data)->event_notify(0, event);
>> +    }
>> +
>> +    pthread_mutex_unlock(&LOCK_audit);
>> +  }
>> +}
>> +
>> +
>> +
>> +
>> +#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;
>> +}
>> +
>> +#endif /* EMBEDDED_LIBRARY */
>> diff -Nrup a/sql/sql_plugin.cc b/sql/sql_plugin.cc
>> --- a/sql/sql_plugin.cc  2007-11-21 12:19:04 -08:00
>> +++ b/sql/sql_plugin.cc  2007-11-29 14:40:18 -08:00
>> @@ -174,7 +186,8 @@ public:
>>   sys_var_pluginvar *cast_pluginvar() { return this; }
>>   bool is_readonly() const { return plugin_var->flags &  
>> PLUGIN_VAR_READONLY; }
>>   bool check_type(enum_var_type type)
>> -  { return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) && type != 
> 
>> OPT_GLOBAL; }
>> +  { return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ? (type !=  
>> OPT_GLOBAL)
>> +    : ((type == OPT_GLOBAL) && (plugin_var->flags &  
>> PLUGIN_VAR_NOGLOBAL)); }
>
> no PLUGIN_VAR_NOGLOBAL

ok

>
>>   bool check_update_type(Item_result type);
>>   SHOW_TYPE show_type();
>>   uchar* real_value_ptr(THD *thd, enum_var_type type);
>> @@ -330,6 +343,11 @@ static inline void free_plugin_mem(struc
>>     my_free((uchar*)p->plugins, MYF(MY_ALLOW_ZERO_PTR));
>> }
>>
>> +extern "C" char *mysqld_plugin_path(char *tgt, unsigned int  
>> tgt_size,
>> +                                    const char *name)
>> +{
>> +  return strxnmov(tgt, tgt_size - 1, opt_plugin_dir, "/", name,  
>> NullS);
>> +}
>
> What is that ?
>
>> static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
>> {
>> @@ -346,7 +364,8 @@ static st_plugin_dl *plugin_dl_add(const
>>     plugin directory are used (to make this even remotely secure).
>>   */
>>   if (my_strchr(files_charset_info, dl->str, dl->str + dl->length,  
>> FN_LIBCHAR) ||
>> -      check_identifier_name((LEX_STRING *) dl) ||
>> +      check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
>
> indeed
>
>> +                               system_charset_info, 1) ||
>>       plugin_dir_len + dl->length + 1 >= FN_REFLEN)
>>   {
>>     if (report & REPORT_TO_USER)
>> @@ -1179,9 +1198,7 @@ int plugin_init(int *argc, char **argv,
>>   /* Register all dynamic plugins */
>>   if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
>>   {
>> -    if (opt_plugin_load &&
>> -        plugin_load_list(&tmp_root, argc, argv, opt_plugin_load))
>> -      goto err;
>> +    plugin_load_list(&tmp_root, argc, argv, opt_plugin_load);
>
> what was wrong with plugin_load_list ?

I did not want failure to load a plugin to cause the mysqld to  
terminate.

>
>>     if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE))
>>       plugin_load(&tmp_root, argc, argv);
>>   }
>> @@ -1310,27 +1327,23 @@ end:
>> */
>> static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
>> {
>> +  THD thd;
>>   TABLE_LIST tables;
>>   TABLE *table;
>>   READ_RECORD read_record_info;
>>   int error;
>> -  THD *new_thd;
>> +  THD *new_thd= &thd;
>
> why ?

did not seem to be much value declaring this temporary THD on the heap.

>
>> #ifdef EMBEDDED_LIBRARY
>>   bool table_exists;
>> #endif /* EMBEDDED_LIBRARY */
>>   DBUG_ENTER("plugin_load");
>>
>> -  if (!(new_thd= new THD))
>> -  {
>> -    sql_print_error("Can't allocate memory for plugin structures");
>> -    delete new_thd;
>> -    DBUG_VOID_RETURN;
>> -  }
>>   new_thd->thread_stack= (char*) &tables;
>>   new_thd->store_globals();
>>   lex_start(new_thd);
>>   new_thd->db= my_strdup("mysql", MYF(0));
>>   new_thd->db_length= 5;
>> +  bzero((char*) &thd.net, sizeof(thd.net));
>>   bzero((uchar*)&tables, sizeof(tables));
>>   tables.alias= tables.table_name= (char*)"plugin";
>>   tables.lock_type= TL_READ;
>> @@ -1406,11 +1418,15 @@ static bool plugin_load_list(MEM_ROOT *t
>>   struct st_plugin_dl *plugin_dl;
>
> by the way, please remove argument names from the forward  
> declaration of
> plugin_load_list:
>
> -static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char  
> **argv,
> -                             const char *list);
> +static bool plugin_load_list(MEM_ROOT *, int *, char **, const char  
> *);

ok

>
>>   struct st_mysql_plugin *plugin;
>>   char *p= buffer;
>> +  bool result= FALSE;
>>   DBUG_ENTER("plugin_load_list");
>>   while (list)
>>   {
>>     if (p == buffer + sizeof(buffer) - 1)
>> +    {
>> +      sql_print_warning("plugin-load argument too long");
>>       break;
>> +    }
>>     switch ((*(p++)= *(list++))) {
>>     case '\0':
>>       list= NULL; /* terminate the loop */
>> @@ -1420,6 +1436,7 @@ static bool plugin_load_list(MEM_ROOT *t
>> #endif
>>     case ';':
>>       name.str[name.length]= '\0';
>> +      pthread_mutex_lock(&LOCK_plugin);
>
> why ? safe_mutex_assert_owner()'s ?
> why not to lock once in the beginning on the function and unlock on  
> return ?
> some other code that expects the mutex to be NOT locked ?

I will alter accordingly.

>
>>       if (str != &dl)  // load all plugins in named module
>>       {
>>         dl= name;
>> @@ -1459,12 +1483,12 @@ static bool plugin_load_list(MEM_ROOT *t
>>       str->length++;
>>       continue;
>>     }
>> -  }
>> -  DBUG_RETURN(FALSE);
>> error:
>> -  sql_print_error("Couldn't load plugin named '%s' with soname  
>> '%s'.",
>> -                  name.str, dl.str);
>> -  DBUG_RETURN(TRUE);
>> +    sql_print_warning("Couldn't load plugin named '%s' with soname  
>> '%s'.",
>> +                      name.str, dl.str);
>> +    result= TRUE;
>> +  }
>> +  DBUG_RETURN(result);
>
> why do you return a value if you ignore it in the caller ?

I am undecided if a failure to load a plugin is reasonable grounds to  
terminate the server. I would appreciate your input on that decision.

>
>> }
>>
>>
>> @@ -1625,16 +1649,28 @@ bool mysql_install_plugin(THD *thd, cons
>>     DBUG_RETURN(TRUE);
>>
>>   pthread_mutex_lock(&LOCK_plugin);
>> -  rw_wrlock(&LOCK_system_variables_hash);
>> +
>> +  table->use_all_columns();
>> +  restore_record(table, s->default_values);
>> +  table->field[0]->store(name->str, name->length,  
>> system_charset_info);
>> +  table->field[1]->store(dl->str, dl->length, files_charset_info);
>> +  error= table->file->ha_write_row(table->record[0]);
>> +  if (error)
>> +  {
>> +    table->file->print_error(error, MYF(0));
>> +    goto err;
>> +  }
>
> why ?

This, I need to try to remember as I vaguely recall a deadlock/crash  
scenario which resulted in these changes in sql_plugin.cc

>
>>   /* handle_options() assumes arg0 (program name) always exists */
>>   argv[0]= const_cast<char*>(""); // without a cast gcc emits a  
>> warning
>>   argv[1]= 0;
>>   argc= 1;
>> +  rw_wrlock(&LOCK_system_variables_hash);
>>   error= plugin_add(thd->mem_root, name, dl, &argc, argv,  
>> REPORT_TO_USER);
>>   rw_unlock(&LOCK_system_variables_hash);
>>
>>   if (error || !(tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
>> -    goto err;
>> +    goto deinit;
>>
>>   if (plugin_initialize(tmp))
>>   {
>>

Regards,
Antony
Thread
bk commit into 6.0 tree (acurtis:1.2699) WL#3771antony29 Nov
  • Re: bk commit into 6.0 tree (acurtis:1.2699) WL#3771Sergei Golubchik3 Dec
    • Re: bk commit into 6.0 tree (acurtis:1.2699) WL#3771Antony T Curtis3 Dec
    • Re: bk commit into 6.0 tree (acurtis:1.2699) WL#3771Sergei Golubchik3 Dec
      • Re: bk commit into 6.0 tree (acurtis:1.2699) WL#3771Antony T Curtis3 Dec