246 lines
8.7 KiB
C++
246 lines
8.7 KiB
C++
/* Copyright (c) 2016, 2019, 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
|
|
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 <mysql/plugin_keyring.h>
|
|
#include "keyring.h"
|
|
#include "buffered_file_io.h"
|
|
|
|
#ifdef _WIN32
|
|
#define MYSQL_DEFAULT_KEYRINGFILE MYSQL_KEYRINGDIR"\\keyring"
|
|
#else
|
|
#define MYSQL_DEFAULT_KEYRINGFILE MYSQL_KEYRINGDIR"/keyring"
|
|
#endif
|
|
|
|
using keyring::Buffered_file_io;
|
|
using keyring::Keys_container;
|
|
using keyring::Keys_iterator;
|
|
using keyring::Logger;
|
|
|
|
mysql_rwlock_t LOCK_keyring;
|
|
|
|
int check_keyring_file_data(MYSQL_THD thd MY_ATTRIBUTE((unused)),
|
|
struct st_mysql_sys_var *var MY_ATTRIBUTE((unused)),
|
|
void *save, st_mysql_value *value)
|
|
{
|
|
char buff[FN_REFLEN+1];
|
|
const char *keyring_filename;
|
|
int len = sizeof(buff);
|
|
boost::movelib::unique_ptr<IKeys_container> new_keys(new Keys_container(logger.get()));
|
|
|
|
(*(const char **) save)= NULL;
|
|
keyring_filename= value->val_str(value, buff, &len);
|
|
mysql_rwlock_wrlock(&LOCK_keyring);
|
|
if (create_keyring_dir_if_does_not_exist(keyring_filename))
|
|
{
|
|
mysql_rwlock_unlock(&LOCK_keyring);
|
|
logger->log(MY_ERROR_LEVEL, "keyring_file_data cannot be set to new value"
|
|
" as the keyring file cannot be created/accessed in the provided path");
|
|
return 1;
|
|
}
|
|
try
|
|
{
|
|
IKeyring_io *keyring_io(new Buffered_file_io(logger.get()));
|
|
if (new_keys->init(keyring_io, keyring_filename))
|
|
{
|
|
mysql_rwlock_unlock(&LOCK_keyring);
|
|
return 1;
|
|
}
|
|
*reinterpret_cast<IKeys_container **>(save)= new_keys.get();
|
|
new_keys.release();
|
|
mysql_rwlock_unlock(&LOCK_keyring);
|
|
}
|
|
catch (...)
|
|
{
|
|
mysql_rwlock_unlock(&LOCK_keyring);
|
|
return 1;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
static char *keyring_file_data_value= NULL;
|
|
static MYSQL_SYSVAR_STR(
|
|
data, /* name */
|
|
keyring_file_data_value, /* value */
|
|
PLUGIN_VAR_RQCMDARG, /* flags */
|
|
"The path to the keyring file. Must be specified", /* comment */
|
|
check_keyring_file_data, /* check() */
|
|
update_keyring_file_data, /* update() */
|
|
MYSQL_DEFAULT_KEYRINGFILE /* default */
|
|
);
|
|
static MYSQL_SYSVAR_BOOL(open_mode, keyring_open_mode,
|
|
PLUGIN_VAR_INVISIBLE | PLUGIN_VAR_RQCMDARG,
|
|
"Mode in which keyring file should be opened", NULL,
|
|
NULL, TRUE);
|
|
|
|
static struct st_mysql_sys_var *keyring_file_system_variables[]= {
|
|
MYSQL_SYSVAR(data),
|
|
MYSQL_SYSVAR(open_mode),
|
|
NULL
|
|
};
|
|
|
|
static int keyring_init(MYSQL_PLUGIN plugin_info)
|
|
{
|
|
try
|
|
{
|
|
#ifdef HAVE_PSI_INTERFACE
|
|
keyring_init_psi_keys();
|
|
#endif
|
|
|
|
DBUG_EXECUTE_IF("simulate_keyring_init_error", return TRUE;);
|
|
|
|
if (init_keyring_locks())
|
|
return TRUE;
|
|
|
|
logger.reset(new Logger(plugin_info));
|
|
if (create_keyring_dir_if_does_not_exist(keyring_file_data_value))
|
|
{
|
|
logger->log(MY_ERROR_LEVEL, "Could not create keyring directory "
|
|
"The keyring_file will stay unusable until correct path to the keyring "
|
|
"directory gets provided");
|
|
return TRUE;
|
|
}
|
|
keys.reset(new Keys_container(logger.get()));
|
|
IKeyring_io *keyring_io= new Buffered_file_io(logger.get());
|
|
if (keys->init(keyring_io, keyring_file_data_value))
|
|
{
|
|
is_keys_container_initialized = FALSE;
|
|
logger->log(MY_ERROR_LEVEL, "keyring_file initialization failure. Please check"
|
|
" if the keyring_file_data points to readable keyring file or keyring file"
|
|
" can be created in the specified location. "
|
|
"The keyring_file will stay unusable until correct path to the keyring file "
|
|
"gets provided");
|
|
return TRUE;
|
|
}
|
|
is_keys_container_initialized = TRUE;
|
|
return FALSE;
|
|
}
|
|
catch (...)
|
|
{
|
|
if (logger != NULL)
|
|
logger->log(MY_ERROR_LEVEL, "keyring_file initialization failure due to internal"
|
|
" exception inside the plugin");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
int keyring_deinit(void *arg MY_ATTRIBUTE((unused)))
|
|
{
|
|
//not taking a lock here as the calls to keyring_deinit are serialized by
|
|
//the plugin framework
|
|
keys.reset();
|
|
logger.reset();
|
|
keyring_file_data.reset();
|
|
mysql_rwlock_destroy(&LOCK_keyring);
|
|
return 0;
|
|
}
|
|
|
|
my_bool mysql_key_fetch(const char *key_id, char **key_type, const char *user_id,
|
|
void **key, size_t *key_len)
|
|
{
|
|
return mysql_key_fetch<keyring::Key>(key_id, key_type, user_id, key, key_len,
|
|
"keyring_file");
|
|
}
|
|
|
|
my_bool mysql_key_store(const char *key_id, const char *key_type,
|
|
const char *user_id, const void *key, size_t key_len)
|
|
{
|
|
return mysql_key_store<keyring::Key>(key_id, key_type, user_id, key, key_len,
|
|
"keyring_file");
|
|
}
|
|
|
|
my_bool mysql_key_remove(const char *key_id, const char *user_id)
|
|
{
|
|
return mysql_key_remove<keyring::Key>(key_id, user_id, "keyring_file");
|
|
}
|
|
|
|
|
|
my_bool mysql_key_generate(const char *key_id, const char *key_type,
|
|
const char *user_id, size_t key_len)
|
|
{
|
|
try
|
|
{
|
|
boost::movelib::unique_ptr<IKey> key_candidate(new keyring::Key(key_id, key_type, user_id, NULL, 0));
|
|
|
|
boost::movelib::unique_ptr<uchar[]> key(new uchar[key_len]);
|
|
if (key.get() == NULL)
|
|
return TRUE;
|
|
memset(key.get(), 0, key_len);
|
|
if (is_keys_container_initialized == FALSE || check_key_for_writing(key_candidate.get(), "generating") ||
|
|
my_rand_buffer(key.get(), key_len))
|
|
return TRUE;
|
|
|
|
return mysql_key_store(key_id, key_type, user_id, key.get(), key_len) == TRUE;
|
|
}
|
|
catch (...)
|
|
{
|
|
if (logger != NULL)
|
|
logger->log(MY_ERROR_LEVEL, "Failed to generate a key due to internal exception inside keyring_file plugin");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
static void mysql_key_iterator_init(void **key_iterator)
|
|
{
|
|
*key_iterator= new Keys_iterator(logger.get());
|
|
mysql_key_iterator_init<keyring::Key>(static_cast<Keys_iterator*>(*key_iterator),
|
|
"keyring_file");
|
|
}
|
|
|
|
static void mysql_key_iterator_deinit(void *key_iterator)
|
|
{
|
|
mysql_key_iterator_deinit<keyring::Key>(static_cast<Keys_iterator*>(key_iterator),
|
|
"keyring_file");
|
|
delete static_cast<Keys_iterator*>(key_iterator);
|
|
}
|
|
|
|
static bool mysql_key_iterator_get_key(void *key_iterator,
|
|
char *key_id, char *user_id)
|
|
{
|
|
return mysql_key_iterator_get_key<keyring::Key>(static_cast<Keys_iterator*>(key_iterator),
|
|
key_id, user_id, "keyring_file");
|
|
}
|
|
|
|
/* Plugin type-specific descriptor */
|
|
static struct st_mysql_keyring keyring_descriptor=
|
|
{
|
|
MYSQL_KEYRING_INTERFACE_VERSION,
|
|
mysql_key_store,
|
|
mysql_key_fetch,
|
|
mysql_key_remove,
|
|
mysql_key_generate,
|
|
mysql_key_iterator_init,
|
|
mysql_key_iterator_deinit,
|
|
mysql_key_iterator_get_key
|
|
};
|
|
|
|
mysql_declare_plugin(keyring_file)
|
|
{
|
|
MYSQL_KEYRING_PLUGIN, /* type */
|
|
&keyring_descriptor, /* descriptor */
|
|
"keyring_file", /* name */
|
|
"Oracle Corporation", /* author */
|
|
"store/fetch authentication data to/from a flat file", /* description */
|
|
PLUGIN_LICENSE_GPL,
|
|
keyring_init, /* init function (when loaded) */
|
|
keyring_deinit, /* deinit function (when unloaded) */
|
|
0x0100, /* version */
|
|
NULL, /* status variables */
|
|
keyring_file_system_variables, /* system variables */
|
|
NULL,
|
|
0,
|
|
}
|
|
mysql_declare_plugin_end;
|