512 lines
13 KiB
C++
512 lines
13 KiB
C++
/* Copyright (c) 2016, 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 */
|
|
|
|
#define MYSQL_SERVER
|
|
#include <my_global.h>
|
|
#include <boost/optional/optional.hpp>
|
|
#include <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 my_bool is_keyring_udf_initialized= FALSE;
|
|
|
|
static int keyring_udf_init(void *p)
|
|
{
|
|
DBUG_ENTER("keyring_udf_init");
|
|
is_keyring_udf_initialized= TRUE;
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
static int keyring_udf_deinit(void *p)
|
|
{
|
|
DBUG_ENTER("keyring_udf_deinit");
|
|
is_keyring_udf_initialized= FALSE;
|
|
DBUG_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 */
|
|
keyring_udf_deinit, /* Plugin Deinit */
|
|
0x0100 /* 1.0 */,
|
|
NULL, /* status variables */
|
|
NULL, /* system variables */
|
|
NULL, /* config options */
|
|
0, /* flags */
|
|
}
|
|
mysql_declare_plugin_end;
|
|
|
|
static my_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
|
|
};
|
|
|
|
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 my_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;
|
|
}
|
|
|
|
my_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
|
|
my_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 *initid)
|
|
{}
|
|
|
|
/**
|
|
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 *initid, UDF_ARGS *args, char *is_null,
|
|
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 my_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
|
|
my_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 *result,
|
|
unsigned long *length, char *is_null, 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
|
|
my_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 *result,
|
|
unsigned long *length, char *is_null, 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
|
|
my_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 *initid, UDF_ARGS *args, char *is_null,
|
|
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
|
|
my_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 *initid)
|
|
{}
|
|
|
|
/**
|
|
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 *initid, UDF_ARGS *args, char *is_null,
|
|
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
|
|
my_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 *initid)
|
|
{}
|
|
|
|
/**
|
|
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 *initid, UDF_ARGS *args, char *is_null,
|
|
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;
|
|
}
|