summaryrefslogtreecommitdiff
path: root/sql/sql_plugin.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_plugin.cc')
-rw-r--r--sql/sql_plugin.cc89
1 files changed, 64 insertions, 25 deletions
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 066a7512eaf..d36654c4c18 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 MySQL AB, 2009 Sun Microsystems, Inc.
+/* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
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
@@ -11,7 +11,7 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "sql_priv.h" // SHOW_MY_BOOL
#include "unireg.h"
@@ -30,6 +30,7 @@
#include <my_pthread.h>
#include <my_getopt.h>
#include "sql_audit.h"
+#include <mysql/plugin_auth.h>
#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
#include <mysql/plugin_auth.h>
#define REPORT_TO_LOG 1
@@ -42,9 +43,8 @@ extern struct st_maria_plugin *mysql_mandatory_plugins[];
@note The order of the enumeration is critical.
@see construct_options
*/
-static const char *global_plugin_typelib_names[]=
- { "OFF", "ON", "FORCE", NULL };
-enum enum_plugin_load_policy {PLUGIN_OFF, PLUGIN_ON, PLUGIN_FORCE};
+const char *global_plugin_typelib_names[]=
+ { "OFF", "ON", "FORCE", "FORCE_PLUS_PERMANENT", NULL };
static TYPELIB global_plugin_typelib=
{ array_elements(global_plugin_typelib_names)-1,
"", global_plugin_typelib_names, NULL };
@@ -301,6 +301,26 @@ static void report_error(int where_to, uint error, ...)
}
}
+/**
+ Check if the provided path is valid in the sense that it does cause
+ a relative reference outside the directory.
+
+ @note Currently, this function only check if there are any
+ characters in FN_DIRSEP in the string, but it might change in the
+ future.
+
+ @code
+ check_valid_path("../foo.so") -> true
+ check_valid_path("foo.so") -> false
+ @endcode
+ */
+bool check_valid_path(const char *path, size_t len)
+{
+ size_t prefix= my_strcspn(files_charset_info, path, path + len, FN_DIRSEP);
+ return prefix < len;
+}
+
+
/****************************************************************************
Value type thunks, allows the C world to play in the C++ world
****************************************************************************/
@@ -492,7 +512,8 @@ static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl,
if (!cur)
{
free_plugin_mem(plugin_dl);
- report_error(report, ER_OUTOFMEMORY, plugin_dl->dl.length);
+ report_error(report, ER_OUTOFMEMORY,
+ static_cast<int>(plugin_dl.dl.length));
DBUG_RETURN(TRUE);
}
/*
@@ -617,7 +638,8 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl,
if (!cur)
{
free_plugin_mem(plugin_dl);
- report_error(report, ER_OUTOFMEMORY, plugin_dl->dl.length);
+ report_error(report, ER_OUTOFMEMORY,
+ static_cast<int>(plugin_dl.dl.length));
DBUG_RETURN(TRUE);
}
/*
@@ -648,13 +670,15 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
struct st_plugin_dl *tmp, plugin_dl;
void *sym;
DBUG_ENTER("plugin_dl_add");
+ DBUG_PRINT("enter", ("dl->str: '%s', dl->length: %d",
+ dl->str, (int) dl->length));
plugin_dir_len= strlen(opt_plugin_dir);
/*
Ensure that the dll doesn't have a path.
This is done to ensure that only approved libraries from the
plugin directory are used (to make this even remotely secure).
*/
- if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) ||
+ if (check_valid_path(dl->str, dl->length) ||
check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
system_charset_info, 1) ||
plugin_dir_len + dl->length + 1 >= FN_REFLEN)
@@ -729,7 +753,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
{
free_plugin_mem(&plugin_dl);
- report_error(report, ER_OUTOFMEMORY, plugin_dl.dl.length);
+ report_error(report, ER_OUTOFMEMORY,
+ static_cast<int>(plugin_dl.dl.length));
DBUG_RETURN(0);
}
plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length,
@@ -740,7 +765,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
{
free_plugin_mem(&plugin_dl);
- report_error(report, ER_OUTOFMEMORY, sizeof(struct st_plugin_dl));
+ report_error(report, ER_OUTOFMEMORY,
+ static_cast<int>(sizeof(struct st_plugin_dl)));
DBUG_RETURN(0);
}
DBUG_RETURN(tmp);
@@ -1014,6 +1040,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
tmp.name.length= name_len;
tmp.ref_count= 0;
tmp.state= PLUGIN_IS_UNINITIALIZED;
+ tmp.load_option= PLUGIN_ON;
if (test_plugin_options(tmp_root, &tmp, argc, argv))
tmp.state= PLUGIN_IS_DISABLED;
@@ -1460,7 +1487,7 @@ int plugin_init(int *argc, char **argv, int flags)
tmp.name.str= (char *)plugin->name;
tmp.name.length= strlen(plugin->name);
tmp.state= 0;
- tmp.is_mandatory= mandatory;
+ tmp.load_option= mandatory ? PLUGIN_FORCE : PLUGIN_ON;
/*
If the performance schema is compiled in,
@@ -1479,7 +1506,7 @@ int plugin_init(int *argc, char **argv, int flags)
to work, by using '--skip-performance-schema' (the plugin)
*/
if (!my_strcasecmp(&my_charset_latin1, plugin->name, "PERFORMANCE_SCHEMA"))
- tmp.is_mandatory= true;
+ tmp.load_option= PLUGIN_FORCE;
free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
if (test_plugin_options(&tmp_root, &tmp, argc, argv))
@@ -1557,7 +1584,8 @@ int plugin_init(int *argc, char **argv, int flags)
while ((plugin_ptr= *(--reap)))
{
mysql_mutex_unlock(&LOCK_plugin);
- if (plugin_ptr->is_mandatory)
+ if (plugin_ptr->load_option == PLUGIN_FORCE ||
+ plugin_ptr->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
reaped_mandatory_plugin= TRUE;
plugin_deinitialize(plugin_ptr, true);
mysql_mutex_lock(&LOCK_plugin);
@@ -1961,7 +1989,11 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
mysql_mutex_lock(&LOCK_plugin);
mysql_rwlock_wrlock(&LOCK_system_variables_hash);
- my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL);
+ if (my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL))
+ {
+ report_error(REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str);
+ goto err;
+ }
error= plugin_add(thd->mem_root, name, dl, &argc, argv, REPORT_TO_USER);
if (argv)
free_defaults(argv);
@@ -2073,6 +2105,11 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
goto err;
}
+ if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
+ {
+ my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str);
+ goto err;
+ }
plugin->state= PLUGIN_IS_DELETED;
if (plugin->ref_count)
@@ -3283,7 +3320,8 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
plugin_dash.length + 1);
strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, plugin_name_ptr, NullS);
- if (!tmp->is_mandatory)
+ if (tmp->load_option != PLUGIN_FORCE &&
+ tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
{
/* support --skip-plugin-foo syntax */
options[0].name= plugin_name_ptr;
@@ -3543,7 +3581,8 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
{
struct sys_var_chain chain= { NULL, NULL };
bool disable_plugin;
- enum_plugin_load_policy plugin_load_policy= tmp->is_mandatory ? PLUGIN_FORCE : PLUGIN_ON;
+ enum_plugin_load_option plugin_load_option= tmp->load_option;
+
MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
&tmp->mem_root : &plugin_mem_root;
st_mysql_sys_var **opt;
@@ -3557,13 +3596,11 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
DBUG_ENTER("test_plugin_options");
DBUG_ASSERT(tmp->plugin && tmp->name.str);
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
/*
The 'ndbcluster' storage engines is always disabled by default.
*/
if (!my_strcasecmp(&my_charset_latin1, tmp->name.str, "ndbcluster"))
- plugin_load_policy= PLUGIN_OFF;
-#endif
+ plugin_load_option= PLUGIN_OFF;
for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
@@ -3587,8 +3624,9 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
We adjust the default value to account for the hardcoded exceptions
we have set for the federated and ndbcluster storage engines.
*/
- if (!tmp->is_mandatory)
- opts[0].def_value= opts[1].def_value= plugin_load_policy;
+ if (tmp->load_option != PLUGIN_FORCE &&
+ tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ opts[0].def_value= opts[1].def_value= plugin_load_option;
error= handle_options(argc, &argv, opts, NULL);
(*argc)++; /* add back one for the program name */
@@ -3603,12 +3641,13 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
Set plugin loading policy from option value. First element in the option
list is always the <plugin name> option value.
*/
- if (!tmp->is_mandatory)
- plugin_load_policy= (enum_plugin_load_policy)*(ulong*)opts[0].value;
+ if (tmp->load_option != PLUGIN_FORCE &&
+ tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ plugin_load_option= (enum_plugin_load_option) *(ulong*) opts[0].value;
}
- disable_plugin= (plugin_load_policy == PLUGIN_OFF);
- tmp->is_mandatory= (plugin_load_policy == PLUGIN_FORCE);
+ disable_plugin= (plugin_load_option == PLUGIN_OFF);
+ tmp->load_option= plugin_load_option;
/*
If the plugin is disabled it should not be initialized.