/* 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 #include #include // 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(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 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(&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(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; }