481 lines
14 KiB
C++
481 lines
14 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, 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 <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <boost/optional/optional.hpp>
|
|
#include <new>
|
|
|
|
#include "my_dbug.h"
|
|
#include "my_inttypes.h"
|
|
#include "mysql/plugin.h"
|
|
#include "sql/current_thd.h"
|
|
#include "sql/sql_class.h" // THD
|
|
|
|
#define MAX_KEYRING_UDF_KEY_LENGTH_IN_BITS 16384
|
|
#define MAX_KEYRING_UDF_KEY_TEXT_LENGTH MAX_KEYRING_UDF_KEY_LENGTH_IN_BITS / 8
|
|
#define KEYRING_UDF_KEY_TYPE_LENGTH 3
|
|
|
|
#ifdef WIN32
|
|
#define PLUGIN_EXPORT extern "C" __declspec(dllexport)
|
|
#else
|
|
#define PLUGIN_EXPORT extern "C"
|
|
#endif
|
|
|
|
static bool is_keyring_udf_initialized = false;
|
|
|
|
static int keyring_udf_init(void *) {
|
|
DBUG_TRACE;
|
|
is_keyring_udf_initialized = true;
|
|
return 0;
|
|
}
|
|
|
|
static int keyring_udf_deinit(void *) {
|
|
DBUG_TRACE;
|
|
is_keyring_udf_initialized = false;
|
|
return 0;
|
|
}
|
|
|
|
struct st_mysql_daemon keyring_udf_decriptor = {MYSQL_DAEMON_INTERFACE_VERSION};
|
|
|
|
/*
|
|
Plugin library descriptor
|
|
*/
|
|
|
|
mysql_declare_plugin(keyring_udf){
|
|
MYSQL_DAEMON_PLUGIN,
|
|
&keyring_udf_decriptor,
|
|
"keyring_udf",
|
|
"Oracle Corporation",
|
|
"Keyring UDF plugin",
|
|
PLUGIN_LICENSE_GPL,
|
|
keyring_udf_init, /* Plugin Init */
|
|
NULL, /* Plugin check uninstall */
|
|
keyring_udf_deinit, /* Plugin Deinit */
|
|
0x0100 /* 1.0 */,
|
|
NULL, /* status variables */
|
|
NULL, /* system variables */
|
|
NULL, /* config options */
|
|
0, /* flags */
|
|
} mysql_declare_plugin_end;
|
|
|
|
static bool get_current_user(std::string *current_user) {
|
|
THD *thd = current_thd;
|
|
MYSQL_SECURITY_CONTEXT sec_ctx;
|
|
LEX_CSTRING user, host;
|
|
|
|
if (thd_get_security_context(thd, &sec_ctx) ||
|
|
security_context_get_option(sec_ctx, "priv_user", &user) ||
|
|
security_context_get_option(sec_ctx, "priv_host", &host))
|
|
return true;
|
|
|
|
if (user.length) current_user->append(user.str, user.length);
|
|
DBUG_ASSERT(host.length);
|
|
current_user->append("@").append(host.str, host.length);
|
|
|
|
return false;
|
|
}
|
|
|
|
enum what_to_validate {
|
|
VALIDATE_KEY = 1,
|
|
VALIDATE_KEY_ID = 2,
|
|
VALIDATE_KEY_TYPE = 4,
|
|
VALIDATE_KEY_LENGTH = 8
|
|
};
|
|
|
|
static uint get_args_count_from_validation_request(int to_validate) {
|
|
uint args_count = 0;
|
|
|
|
// Since to_validate is a bit mask - count the number of bits set
|
|
for (; to_validate; to_validate >>= 1)
|
|
if (to_validate & 1) ++args_count;
|
|
|
|
return args_count;
|
|
}
|
|
|
|
static bool validate(UDF_ARGS *args, uint expected_arg_count, int to_validate,
|
|
char *message) {
|
|
THD *thd = current_thd;
|
|
MYSQL_SECURITY_CONTEXT sec_ctx;
|
|
my_svc_bool has_current_user_execute_privilege = 0;
|
|
|
|
if (is_keyring_udf_initialized == false) {
|
|
strcpy(message,
|
|
"This function requires keyring_udf plugin which is not installed."
|
|
" Please install keyring_udf plugin and try again.");
|
|
return true;
|
|
}
|
|
|
|
if (thd_get_security_context(thd, &sec_ctx) ||
|
|
security_context_get_option(sec_ctx, "privilege_execute",
|
|
&has_current_user_execute_privilege))
|
|
return true;
|
|
|
|
if (has_current_user_execute_privilege == false) {
|
|
strcpy(message,
|
|
"The user is not privileged to execute this function. "
|
|
"User needs to have EXECUTE permission.");
|
|
return true;
|
|
}
|
|
|
|
if (args->arg_count != expected_arg_count) {
|
|
strcpy(message, "Mismatch in number of arguments to the function.");
|
|
return true;
|
|
}
|
|
|
|
if (to_validate & VALIDATE_KEY_ID &&
|
|
(args->args[0] == NULL || args->arg_type[0] != STRING_RESULT)) {
|
|
strcpy(message,
|
|
"Mismatch encountered. A string argument is expected "
|
|
"for key id.");
|
|
return true;
|
|
}
|
|
|
|
if (to_validate & VALIDATE_KEY_TYPE &&
|
|
(args->args[1] == NULL || args->arg_type[1] != STRING_RESULT)) {
|
|
strcpy(message,
|
|
"Mismatch encountered. A string argument is expected "
|
|
"for key type.");
|
|
return true;
|
|
}
|
|
|
|
if (to_validate & VALIDATE_KEY_LENGTH) {
|
|
if (args->args[2] == NULL || args->arg_type[2] != INT_RESULT) {
|
|
strcpy(message,
|
|
"Mismatch encountered. An integer argument is expected "
|
|
"for key length.");
|
|
return true;
|
|
}
|
|
long long key_length = *reinterpret_cast<long long *>(args->args[2]);
|
|
|
|
if (key_length > MAX_KEYRING_UDF_KEY_TEXT_LENGTH) {
|
|
sprintf(message, "%s%d",
|
|
"The key is to long. The max length of the key is ",
|
|
MAX_KEYRING_UDF_KEY_TEXT_LENGTH);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (to_validate & VALIDATE_KEY &&
|
|
(args->args[2] == NULL || args->arg_type[2] != STRING_RESULT)) {
|
|
strcpy(message,
|
|
"Mismatch encountered. A string argument is expected "
|
|
"for key.");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool keyring_udf_func_init(
|
|
UDF_INIT *initid, UDF_ARGS *args, char *message, int to_validate,
|
|
const boost::optional<size_t> max_lenth_to_return,
|
|
const size_t size_of_memory_to_allocate) {
|
|
initid->ptr = NULL;
|
|
uint expected_arg_count = get_args_count_from_validation_request(to_validate);
|
|
|
|
if (validate(args, expected_arg_count, to_validate, message)) return true;
|
|
|
|
if (max_lenth_to_return)
|
|
initid->max_length = *max_lenth_to_return; // if no max_length_to_return
|
|
// passed to the function it
|
|
// means that max_length stays
|
|
// default
|
|
initid->maybe_null = 1;
|
|
|
|
if (size_of_memory_to_allocate != 0) {
|
|
initid->ptr = new (std::nothrow) char[size_of_memory_to_allocate];
|
|
if (initid->ptr == NULL)
|
|
return true;
|
|
else
|
|
memset(initid->ptr, 0, size_of_memory_to_allocate);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
bool keyring_key_store_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
|
|
return keyring_udf_func_init(
|
|
initid, args, message,
|
|
(VALIDATE_KEY_ID | VALIDATE_KEY_TYPE | VALIDATE_KEY), 1, 0);
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
void keyring_key_store_deinit(UDF_INIT *) {}
|
|
|
|
/**
|
|
Implementation of the UDF:
|
|
INT keyring_key_store(STRING key_id, STRING key_type, STRING key)
|
|
@return 1 on success, NULL and error on failure
|
|
*/
|
|
PLUGIN_EXPORT
|
|
long long keyring_key_store(UDF_INIT *, UDF_ARGS *args, unsigned char *,
|
|
unsigned char *error) {
|
|
std::string current_user;
|
|
|
|
if (get_current_user(¤t_user)) {
|
|
*error = 1;
|
|
return 0;
|
|
}
|
|
|
|
if (my_key_store(args->args[0], args->args[1], current_user.c_str(),
|
|
args->args[2], strlen(args->args[2]))) {
|
|
my_error(ER_KEYRING_UDF_KEYRING_SERVICE_ERROR, MYF(0), "keyring_key_store");
|
|
*error = 1;
|
|
return 0;
|
|
}
|
|
|
|
// For the UDF 1 == success, 0 == failure.
|
|
return 1;
|
|
}
|
|
|
|
static bool fetch(const char *function_name, char *key_id, char **a_key,
|
|
char **a_key_type, size_t *a_key_len) {
|
|
std::string current_user;
|
|
if (get_current_user(¤t_user)) return true;
|
|
|
|
char *key_type = NULL, *key = NULL;
|
|
size_t key_len = 0;
|
|
|
|
if (my_key_fetch(key_id, &key_type, current_user.c_str(),
|
|
reinterpret_cast<void **>(&key), &key_len)) {
|
|
my_error(ER_KEYRING_UDF_KEYRING_SERVICE_ERROR, MYF(0), function_name);
|
|
|
|
if (key != NULL) my_free(key);
|
|
if (key_type != NULL) my_free(key_type);
|
|
return true;
|
|
}
|
|
|
|
DBUG_ASSERT((key == NULL && key_len == 0) ||
|
|
(key != NULL && key_len <= MAX_KEYRING_UDF_KEY_TEXT_LENGTH &&
|
|
key_type != NULL &&
|
|
strlen(key_type) <= KEYRING_UDF_KEY_TYPE_LENGTH));
|
|
|
|
if (a_key != NULL)
|
|
*a_key = key;
|
|
else
|
|
my_free(key);
|
|
if (a_key_type != NULL)
|
|
*a_key_type = key_type;
|
|
else
|
|
my_free(key_type);
|
|
if (a_key_len != NULL) *a_key_len = key_len;
|
|
|
|
return false;
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
bool keyring_key_fetch_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
|
|
return keyring_udf_func_init(initid, args, message, VALIDATE_KEY_ID,
|
|
MAX_KEYRING_UDF_KEY_TEXT_LENGTH,
|
|
MAX_KEYRING_UDF_KEY_TEXT_LENGTH);
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
void keyring_key_fetch_deinit(UDF_INIT *initid) {
|
|
if (initid->ptr) {
|
|
delete[] initid->ptr;
|
|
initid->ptr = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Implementation of the UDF:
|
|
STRING keyring_key_fetch(STRING key_id)
|
|
@return key on success, NULL if key does not exist, NULL and error on failure
|
|
*/
|
|
PLUGIN_EXPORT
|
|
char *keyring_key_fetch(UDF_INIT *initid, UDF_ARGS *args, char *,
|
|
unsigned long *length, unsigned char *is_null,
|
|
unsigned char *error) {
|
|
char *key = NULL;
|
|
size_t key_len = 0;
|
|
|
|
if (fetch("keyring_key_fetch", args->args[0], &key, NULL, &key_len)) {
|
|
if (key != NULL) my_free(key);
|
|
*error = 1;
|
|
return NULL;
|
|
}
|
|
|
|
if (key != NULL) {
|
|
memcpy(initid->ptr, key, key_len);
|
|
my_free(key);
|
|
} else
|
|
*is_null = 1;
|
|
|
|
*length = key_len;
|
|
*error = 0;
|
|
return initid->ptr;
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
bool keyring_key_type_fetch_init(UDF_INIT *initid, UDF_ARGS *args,
|
|
char *message) {
|
|
return keyring_udf_func_init(initid, args, message, VALIDATE_KEY_ID,
|
|
KEYRING_UDF_KEY_TYPE_LENGTH,
|
|
KEYRING_UDF_KEY_TYPE_LENGTH);
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
void keyring_key_type_fetch_deinit(UDF_INIT *initid) {
|
|
if (initid->ptr) {
|
|
delete[] initid->ptr;
|
|
initid->ptr = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Implementation of the UDF:
|
|
STRING keyring_key_type_fetch(STRING key_id)
|
|
@return key's type on success, NULL if key does not exist, NULL and error on
|
|
failure
|
|
*/
|
|
PLUGIN_EXPORT
|
|
char *keyring_key_type_fetch(UDF_INIT *initid, UDF_ARGS *args, char *,
|
|
unsigned long *length, unsigned char *is_null,
|
|
unsigned char *error) {
|
|
char *key_type = NULL;
|
|
if (fetch("keyring_key_type_fetch", args->args[0], NULL, &key_type, NULL)) {
|
|
if (key_type != NULL) my_free(key_type);
|
|
*error = 1;
|
|
return NULL;
|
|
}
|
|
|
|
if (key_type != NULL) {
|
|
memcpy(initid->ptr, key_type, KEYRING_UDF_KEY_TYPE_LENGTH);
|
|
*length = KEYRING_UDF_KEY_TYPE_LENGTH;
|
|
my_free(key_type);
|
|
} else {
|
|
*is_null = 1;
|
|
*length = 0;
|
|
}
|
|
|
|
*error = 0;
|
|
return initid->ptr;
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
bool keyring_key_length_fetch_init(UDF_INIT *initid, UDF_ARGS *args,
|
|
char *message) {
|
|
return keyring_udf_func_init(initid, args, message, VALIDATE_KEY_ID,
|
|
boost::none, 0);
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
void keyring_key_length_fetch_deinit(UDF_INIT *initid) {
|
|
if (initid->ptr) {
|
|
delete[] initid->ptr;
|
|
initid->ptr = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Implementation of the UDF:
|
|
INT keyring_key_length_fetch(STRING key_id)
|
|
@return key's length on success, NULL if key does not exist, NULL and error on
|
|
failure
|
|
*/
|
|
PLUGIN_EXPORT
|
|
long long keyring_key_length_fetch(UDF_INIT *, UDF_ARGS *args,
|
|
unsigned char *is_null,
|
|
unsigned char *error) {
|
|
size_t key_len = 0;
|
|
char *key = NULL;
|
|
|
|
*error =
|
|
fetch("keyring_key_length_fetch", args->args[0], &key, NULL, &key_len);
|
|
|
|
if (*error == 0 && key == NULL) *is_null = 1;
|
|
|
|
if (key != NULL) my_free(key);
|
|
|
|
// For the UDF 0 == failure.
|
|
return (*error) ? 0 : key_len;
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
bool keyring_key_remove_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
|
|
return keyring_udf_func_init(initid, args, message, VALIDATE_KEY_ID, 1, 0);
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
void keyring_key_remove_deinit(UDF_INIT *) {}
|
|
|
|
/**
|
|
Implementation of the UDF:
|
|
INT keyring_key_remove(STRING key_id)
|
|
@return 1 on success, NULL on failure
|
|
*/
|
|
PLUGIN_EXPORT
|
|
long long keyring_key_remove(UDF_INIT *, UDF_ARGS *args, unsigned char *,
|
|
unsigned char *error) {
|
|
std::string current_user;
|
|
if (get_current_user(¤t_user)) {
|
|
*error = 1;
|
|
return 0;
|
|
}
|
|
if (my_key_remove(args->args[0], current_user.c_str())) {
|
|
my_error(ER_KEYRING_UDF_KEYRING_SERVICE_ERROR, MYF(0),
|
|
"keyring_key_remove");
|
|
*error = 1;
|
|
return 0;
|
|
}
|
|
*error = 0;
|
|
return 1;
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
bool keyring_key_generate_init(UDF_INIT *initid, UDF_ARGS *args,
|
|
char *message) {
|
|
return keyring_udf_func_init(
|
|
initid, args, message,
|
|
(VALIDATE_KEY_ID | VALIDATE_KEY_TYPE | VALIDATE_KEY_LENGTH), 1, 0);
|
|
}
|
|
|
|
PLUGIN_EXPORT
|
|
void keyring_key_generate_deinit(UDF_INIT *) {}
|
|
|
|
/**
|
|
Implementation of the UDF:
|
|
STRING keyring_key_generate(STRING key_id, STRING key_type, INTEGER
|
|
key_length)
|
|
@return 1 on success, NULL and error on failure
|
|
*/
|
|
PLUGIN_EXPORT
|
|
long long keyring_key_generate(UDF_INIT *, UDF_ARGS *args, unsigned char *,
|
|
unsigned char *error) {
|
|
std::string current_user;
|
|
if (get_current_user(¤t_user)) return 0;
|
|
|
|
long long key_length = *reinterpret_cast<long long *>(args->args[2]);
|
|
|
|
if (my_key_generate(args->args[0], args->args[1], current_user.c_str(),
|
|
key_length)) {
|
|
my_error(ER_KEYRING_UDF_KEYRING_SERVICE_ERROR, MYF(0),
|
|
"keyring_key_generate");
|
|
*error = 1;
|
|
// For the UDF 1 == success, 0 == failure.
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|