You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
261 lines
9.6 KiB
261 lines
9.6 KiB
/* 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, version 2.0,
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is also distributed with certain software (including
|
|
but not limited to OpenSSL) that is licensed under separate terms,
|
|
as designated in a particular file or component or in included license
|
|
documentation. The authors of MySQL hereby grant you an additional
|
|
permission to link the program and your derivative works with the
|
|
separately licensed software that they have included with MySQL.
|
|
|
|
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, version 2.0, 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_config.h"
|
|
|
|
#include <mysql/plugin_keyring.h>
|
|
#include <memory>
|
|
|
|
#include <mysql/components/my_service.h>
|
|
#include <mysql/components/services/log_builtins.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/ssl.h>
|
|
#include "my_compiler.h"
|
|
#include "my_inttypes.h"
|
|
#include "my_io.h"
|
|
#include "my_psi_config.h"
|
|
#include "mysqld_error.h"
|
|
#include "plugin/keyring/buffered_file_io.h"
|
|
#include "plugin/keyring/common/keyring.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::Key;
|
|
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)),
|
|
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);
|
|
std::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(ERROR_LEVEL, ER_KEYRING_FAILED_TO_SET_KEYRING_FILE_DATA);
|
|
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 SYS_VAR *keyring_file_system_variables[] = {
|
|
MYSQL_SYSVAR(data), MYSQL_SYSVAR(open_mode), NULL};
|
|
|
|
static SERVICE_TYPE(registry) *reg_srv = nullptr;
|
|
SERVICE_TYPE(log_builtins) *log_bi = nullptr;
|
|
SERVICE_TYPE(log_builtins_string) *log_bs = nullptr;
|
|
|
|
static int keyring_init(MYSQL_PLUGIN plugin_info MY_ATTRIBUTE((unused))) {
|
|
if (init_logging_service_for_plugin(®_srv, &log_bi, &log_bs)) return true;
|
|
|
|
try {
|
|
SSL_library_init(); // always returns 1
|
|
ERR_load_BIO_strings();
|
|
SSL_load_error_strings();
|
|
OpenSSL_add_all_algorithms();
|
|
|
|
#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());
|
|
if (create_keyring_dir_if_does_not_exist(keyring_file_data_value)) {
|
|
logger->log(ERROR_LEVEL, ER_KEYRING_FAILED_TO_CREATE_KEYRING_DIR);
|
|
return true;
|
|
}
|
|
keys.reset(new Keys_container(logger.get()));
|
|
std::vector<std::string> allowedFileVersionsToInit;
|
|
// this keyring will work with keyring files in the following versions:
|
|
allowedFileVersionsToInit.push_back(keyring::keyring_file_version_2_0);
|
|
allowedFileVersionsToInit.push_back(keyring::keyring_file_version_1_0);
|
|
IKeyring_io *keyring_io =
|
|
new Buffered_file_io(logger.get(), &allowedFileVersionsToInit);
|
|
if (keys->init(keyring_io, keyring_file_data_value)) {
|
|
is_keys_container_initialized = false;
|
|
logger->log(ERROR_LEVEL, ER_KEYRING_FILE_INIT_FAILED);
|
|
return true;
|
|
}
|
|
is_keys_container_initialized = true;
|
|
return false;
|
|
} catch (...) {
|
|
if (logger != NULL)
|
|
logger->log(ERROR_LEVEL, ER_KEYRING_INTERNAL_EXCEPTION_FAILED_FILE_INIT);
|
|
deinit_logging_service_for_plugin(®_srv, &log_bi, &log_bs);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static 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
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
ERR_remove_thread_state(0);
|
|
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
|
|
ERR_free_strings();
|
|
EVP_cleanup();
|
|
CRYPTO_cleanup_all_ex_data();
|
|
keys.reset();
|
|
logger.reset();
|
|
keyring_file_data.reset();
|
|
mysql_rwlock_destroy(&LOCK_keyring);
|
|
|
|
deinit_logging_service_for_plugin(®_srv, &log_bi, &log_bs);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static 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");
|
|
}
|
|
|
|
static 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");
|
|
}
|
|
|
|
static bool mysql_key_remove(const char *key_id, const char *user_id) {
|
|
return mysql_key_remove<keyring::Key>(key_id, user_id, "keyring_file");
|
|
}
|
|
|
|
static bool mysql_key_generate(const char *key_id, const char *key_type,
|
|
const char *user_id, size_t key_len) {
|
|
try {
|
|
std::unique_ptr<IKey> key_candidate(
|
|
new Key(key_id, key_type, user_id, NULL, 0));
|
|
|
|
std::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(ERROR_LEVEL, ER_KEYRING_FAILED_TO_GENERATE_KEY);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static void mysql_key_iterator_init(void **key_iterator) {
|
|
*key_iterator = new Keys_iterator(logger.get());
|
|
if (mysql_key_iterator_init<keyring::Key>(
|
|
static_cast<Keys_iterator *>(*key_iterator), "keyring_file") ==
|
|
true) {
|
|
delete static_cast<Keys_iterator *>(*key_iterator);
|
|
*key_iterator = nullptr;
|
|
}
|
|
}
|
|
|
|
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) */
|
|
NULL, /* check uninstall function */
|
|
keyring_deinit, /* deinit function (when unloaded) */
|
|
0x0100, /* version */
|
|
NULL, /* status variables */
|
|
keyring_file_system_variables, /* system variables */
|
|
NULL,
|
|
PLUGIN_OPT_ALLOW_EARLY,
|
|
} mysql_declare_plugin_end;
|
|
|