Server IP : 104.21.38.3 / Your IP : 172.70.208.81 Web Server : Apache System : Linux krdc-ubuntu-s-2vcpu-4gb-amd-blr1-01.localdomain 5.15.0-142-generic #152-Ubuntu SMP Mon May 19 10:54:31 UTC 2025 x86_64 User : www ( 1000) PHP Version : 7.4.33 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /www/server/mysql/src/plugin/keyring/ |
Upload File : |
/* Copyright (c) 2016, 2023, Oracle and/or its affiliates. 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_global.h> #include <mysql/psi/mysql_file.h> #include "buffered_file_io.h" #include "file_io.h" namespace keyring { extern PSI_memory_key key_memory_KEYRING; const my_off_t EOF_TAG_SIZE= 3; #ifdef HAVE_PSI_INTERFACE PSI_file_key keyring_file_data_key; PSI_file_key keyring_backup_file_data_key; static PSI_file_info all_keyring_files[]= { { &keyring_file_data_key, "keyring_file_data", 0}, { &keyring_backup_file_data_key, "keyring_backup_file_data", 0} }; void keyring_init_psi_file_keys(void) { const char *category = "keyring_file"; int count; count= array_elements(all_keyring_files); mysql_file_register(category, all_keyring_files, count); } #endif std::string*Buffered_file_io::get_backup_filename() { if(backup_filename.empty() == FALSE) return &backup_filename; backup_filename.append(keyring_filename); backup_filename.append(".backup"); return &backup_filename; } my_bool Buffered_file_io::open_backup_file(File *backup_file) { *backup_file= file_io.open(keyring_backup_file_data_key, get_backup_filename()->c_str(), O_RDONLY, MYF(0)); if (likely(*backup_file < 0)) return TRUE; return FALSE; } my_bool Buffered_file_io::is_file_tag_correct(File file) { uchar tag[EOF_TAG_SIZE+1]; if (unlikely(file_io.seek(file, 0, MY_SEEK_END, MYF(MY_WME)) == MY_FILEPOS_ERROR || file_io.tell(file, MYF(MY_WME)) < EOF_TAG_SIZE) || file_io.seek(file, -static_cast<int>(EOF_TAG_SIZE), MY_SEEK_END, MYF(MY_WME)) == MY_FILEPOS_ERROR || file_io.read(file, tag, EOF_TAG_SIZE, MYF(MY_WME)) != EOF_TAG_SIZE || file_io.seek(file, 0, MY_SEEK_SET, MYF(MY_WME)) == MY_FILEPOS_ERROR) return FALSE; // File does not contain tag tag[3]='\0'; return eofTAG == reinterpret_cast<char*>(tag); } my_bool Buffered_file_io::is_file_version_correct(File file) { boost::movelib::unique_ptr<uchar[]> version(new uchar[file_version.length()+1]); version.get()[file_version.length()]= '\0'; if (unlikely(file_io.seek(file, 0, MY_SEEK_SET, MYF(MY_WME)) == MY_FILEPOS_ERROR || file_io.read(file, version.get(), file_version.length(), MYF(MY_WME)) != file_version.length() || file_version != reinterpret_cast<char*>(version.get()) || file_io.seek(file, 0, MY_SEEK_SET, MYF(MY_WME)) == MY_FILEPOS_ERROR)) { logger->log(MY_ERROR_LEVEL, "Incorrect Keyring file version"); return FALSE; } return TRUE; } my_bool Buffered_file_io::check_if_keyring_file_can_be_opened_or_created() { // Check if the file exists int file_exist= !my_access(this->keyring_filename.c_str(), F_OK); // try creating file or opening existing File file= file_io.open(keyring_file_data_key, this->keyring_filename.c_str(), file_exist && keyring_open_mode ? O_RDONLY : O_RDWR | O_CREAT, MYF(MY_WME)); if (file < 0 || file_io.seek(file, 0, MY_SEEK_END, MYF(MY_WME)) == MY_FILEPOS_ERROR) return TRUE; my_off_t file_size= file_io.tell(file, MYF(MY_WME)); if ((file_size == ((my_off_t) - 1)) || file_io.close(file, MYF(MY_WME)) < 0) return TRUE; if (file_size == 0 && file_io.remove(this->keyring_filename.c_str(), MYF(MY_WME))) //remove empty file return TRUE; return FALSE; } my_bool Buffered_file_io::check_file_structure(File file, size_t file_size) { return file_size < ((size_t)EOF_TAG_SIZE + file_version.length()) || is_file_tag_correct(file) == FALSE || is_file_version_correct(file) == FALSE; } my_bool Buffered_file_io::check_keyring_file_stat(File file) { if (file >= 0 && saved_keyring_stat.is_initialized == TRUE) { static MY_STAT keyring_file_stat; memset(&keyring_file_stat, 0, sizeof(MY_STAT)); if (file_io.fstat(file, &keyring_file_stat, MYF(MY_WME))) return TRUE; if (saved_keyring_stat != keyring_file_stat) { logger->log(MY_ERROR_LEVEL, "Keyring file has been changed outside the " "server."); return TRUE; } return FALSE; } //if keyring_file does not exist it means saved_keyring_stat cannot //be initialized - i.e. we are initializing keyring_file return saved_keyring_stat.is_initialized == TRUE; } my_bool Buffered_file_io::load_file_into_buffer(File file, Buffer *buffer) { if (file_io.seek(file, 0, MY_SEEK_END, MYF(MY_WME)) == MY_FILEPOS_ERROR) return TRUE; my_off_t file_size= file_io.tell(file, MYF(MY_WME)); if (file_size == ((my_off_t) - 1)) return TRUE; if (file_size == 0) return FALSE; //it is OK if file is empty if (check_file_structure(file, file_size)) return TRUE; size_t input_buffer_size= file_size - EOF_TAG_SIZE - file_version.length(); //result has to be positive if (input_buffer_size % sizeof(size_t) != 0) return TRUE; //buffer size in the keyring file must be multiplication of size_t if (file_io.seek(file, file_version.length(), MY_SEEK_SET, MYF(MY_WME)) == MY_FILEPOS_ERROR) //skip file version return TRUE; if (likely(input_buffer_size > 0)) { buffer->reserve(input_buffer_size); if (file_io.read(file, buffer->data, input_buffer_size, MYF(MY_WME)) != input_buffer_size) return TRUE; } memory_needed_for_buffer= buffer->size; return FALSE; } /*! Recovers from backup if backup file exists if backup is malformed - remove it, else if backup is good restore keyring file from it. */ my_bool Buffered_file_io::recreate_keyring_from_backup_if_backup_exists() { Buffer buffer; File backup_file; if (open_backup_file(&backup_file)) return FALSE; //no backup file to recover from if (load_file_into_buffer(backup_file, &buffer)) { logger->log(MY_WARNING_LEVEL, "Found malformed keyring backup file - " "removing it"); file_io.close(backup_file, MYF(0)); // if backup file was successfully removed then we have one keyring file return remove_backup(MYF(MY_WME)); } File keyring_file= file_io.open(keyring_file_data_key, this->keyring_filename.c_str(), O_RDWR | O_CREAT, MYF(MY_WME)); if (keyring_file < 0 || flush_buffer_to_storage(&buffer, keyring_file) || file_io.close(backup_file, MYF(MY_WME)) < 0 || file_io.close(keyring_file, MYF(MY_WME)) < 0) { logger->log(MY_ERROR_LEVEL, "Error while restoring keyring from backup file" " cannot overwrite keyring with backup"); return TRUE; } return remove_backup(MYF(MY_WME)); } my_bool Buffered_file_io::init(std::string *keyring_filename) { assert(keyring_filename->empty() == FALSE); #ifdef HAVE_PSI_INTERFACE keyring_init_psi_file_keys(); #endif this->keyring_filename= *keyring_filename; if (recreate_keyring_from_backup_if_backup_exists() || check_if_keyring_file_can_be_opened_or_created()) return TRUE; File keyring_file = file_io.open(keyring_file_data_key, this->keyring_filename.c_str(), O_RDONLY, MYF(0)); return (keyring_file >= 0 && (read_keyring_stat(keyring_file) || file_io.close(keyring_file, MYF(MY_WME)) < 0)); } my_bool Buffered_file_io::flush_buffer_to_file(Buffer *buffer, File file) { if (file_io.write(file, reinterpret_cast<const uchar*>(file_version.c_str()), file_version.length(), MYF(MY_WME)) == file_version.length() && file_io.write(file, buffer->data, buffer->size, MYF(MY_WME)) == buffer->size && file_io.write(file, reinterpret_cast<const uchar*>(eofTAG.c_str()), eofTAG.length(), MYF(MY_WME)) == eofTAG.length()) return FALSE; logger->log(MY_ERROR_LEVEL, "Error while flushing in-memory keyring into " "keyring file"); return TRUE; } my_bool Buffered_file_io::flush_to_backup(ISerialized_object *serialized_object) { //First open backup file then check keyring file. This way we make sure that //media, where keyring file is written, is not replaced with some other media //before backup file is written. In case media was changed backup file handler //becomes invalid File backup_file= file_io.open(keyring_backup_file_data_key, get_backup_filename()->c_str(), O_WRONLY | O_TRUNC | O_CREAT, MYF(MY_WME)); File keyring_file= file_io.open(keyring_file_data_key, this->keyring_filename.c_str(), O_RDONLY, MYF(0)); if (backup_file < 0) { if (keyring_file >= 0) file_io.close(keyring_file, MYF(MY_WME)); return TRUE; } if (check_keyring_file_stat(keyring_file) || (keyring_file >= 0 && file_io.close(keyring_file, MYF(MY_WME)) < 0)) { if (keyring_file >= 0) file_io.close(keyring_file, MYF(MY_WME)); file_io.close(backup_file, MYF(MY_WME)); remove_backup(MYF(MY_WME)); return TRUE; } Buffer *buffer= dynamic_cast<Buffer*>(serialized_object); assert(buffer != NULL); return buffer == NULL || flush_buffer_to_file(buffer, backup_file) || file_io.close(backup_file, MYF(MY_WME)) < 0; } my_bool Buffered_file_io::remove_backup(myf myFlags) { return file_io.remove(get_backup_filename()->c_str(), myFlags); } my_bool Buffered_file_io::flush_buffer_to_storage(Buffer *buffer, File file) { return file_io.truncate(file, MYF(MY_WME)) || file_io.seek(file, 0, MY_SEEK_SET, MYF(MY_WME)) != 0 || flush_buffer_to_file(buffer, file); } my_bool Buffered_file_io::read_keyring_stat(File file) { file_io.sync(file, MYF(0)); if (file_io.fstat(file, &saved_keyring_stat, MYF(MY_WME)) < 0) return TRUE; saved_keyring_stat.is_initialized= TRUE; return FALSE; } my_bool Buffered_file_io::flush_to_storage(ISerialized_object *serialized_object) { Buffer *buffer= dynamic_cast<Buffer*>(serialized_object); assert(buffer != NULL); assert(serialized_object->get_key_operation() != NONE); File keyring_file= file_io.open(keyring_file_data_key, this->keyring_filename.c_str(), O_CREAT | O_RDWR, MYF(MY_WME)); if (keyring_file < 0 || check_keyring_file_stat(keyring_file) || flush_buffer_to_storage(buffer, keyring_file) || read_keyring_stat(keyring_file)) { file_io.close(keyring_file,MYF(MY_WME)); return TRUE; } if (file_io.close(keyring_file, MYF(MY_WME)) < 0 || remove_backup(MYF(MY_WME))) return TRUE; memory_needed_for_buffer= buffer->size; return FALSE; } ISerializer* Buffered_file_io::get_serializer() { hash_to_buffer_serializer.set_memory_needed_for_buffer(memory_needed_for_buffer); return &hash_to_buffer_serializer; } my_bool Buffered_file_io::get_serialized_object(ISerialized_object **serialized_object) { // Check if the file exists int file_exist= !my_access(keyring_filename.c_str(), F_OK); // try creating file or opening existing File file= file_io.open(keyring_file_data_key, keyring_filename.c_str(), file_exist && keyring_open_mode ? O_RDONLY : O_RDWR | O_CREAT, MYF(MY_WME)); *serialized_object= NULL; if (file < 0) //nothing to read return TRUE; Buffer *buffer= new Buffer; if (check_keyring_file_stat(file) || load_file_into_buffer(file, buffer) || read_keyring_stat(file)) { file_io.close(file, MYF(MY_WME)); delete buffer; return TRUE; } if (file_io.close(file, MYF(MY_WME)) < 0) { delete buffer; return TRUE; } if (buffer->size == 0) //empty keyring file { delete buffer; buffer= NULL; } *serialized_object= buffer; return FALSE; } my_bool Buffered_file_io::has_next_serialized_object() { return FALSE; } } //namespace keyring