1 /* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "plugin/keyring/file_io.h"
24
25 #include "my_config.h"
26
27 #include <errno.h>
28 #include <mysql/psi/mysql_file.h>
29 #include <stdarg.h>
30 #include <sys/types.h>
31 #include <sstream>
32 #include <utility>
33
34 #include "my_dbug.h"
35 #include "mysqld_error.h"
36 #include "mysys_err.h"
37 #include "sql/current_thd.h"
38 #include "sql/mysqld.h"
39 #include "sql/sql_error.h"
40
41 namespace keyring {
42
is_super_user()43 bool is_super_user() {
44 THD *thd = current_thd;
45 MYSQL_SECURITY_CONTEXT sec_ctx;
46 my_svc_bool has_super_privilege = false;
47
48 DBUG_ASSERT(thd != nullptr);
49
50 if (thd == nullptr || thd_get_security_context(thd, &sec_ctx) ||
51 security_context_get_option(sec_ctx, "privilege_super",
52 &has_super_privilege))
53 return false;
54
55 return has_super_privilege;
56 }
57
open(PSI_file_key file_data_key MY_ATTRIBUTE ((unused)),const char * filename,int flags,myf myFlags)58 File File_io::open(PSI_file_key file_data_key MY_ATTRIBUTE((unused)),
59 const char *filename, int flags, myf myFlags) {
60 File file = mysql_file_open(file_data_key, filename, flags, MYF(0));
61 if (file < 0 && (myFlags & MY_WME)) {
62 char error_buffer[MYSYS_STRERROR_SIZE];
63 uint error_message_number = EE_FILENOTFOUND;
64 if (my_errno() == EMFILE) error_message_number = EE_OUT_OF_FILERESOURCES;
65 my_warning(error_message_number, filename, my_errno(),
66 my_strerror(error_buffer, sizeof(error_buffer), my_errno()));
67 }
68 return file;
69 }
70
close(File file,myf myFlags)71 int File_io::close(File file, myf myFlags) {
72 int result = mysql_file_close(file, MYF(0));
73 if (result && (myFlags & MY_WME)) {
74 char error_buffer[MYSYS_STRERROR_SIZE];
75 my_warning(EE_BADCLOSE, my_filename(file), my_errno(),
76 my_strerror(error_buffer, sizeof(error_buffer), my_errno()));
77 }
78 return result;
79 }
80
read(File file,uchar * buffer,size_t count,myf myFlags)81 size_t File_io::read(File file, uchar *buffer, size_t count, myf myFlags) {
82 size_t bytes_read = mysql_file_read(file, buffer, count, MYF(0));
83
84 if (bytes_read != count && (myFlags & MY_WME)) {
85 char error_buffer[MYSYS_STRERROR_SIZE];
86 my_warning(EE_READ, my_filename(file), my_errno(),
87 my_strerror(error_buffer, sizeof(error_buffer), my_errno()));
88 }
89 return bytes_read;
90 }
91
write(File file,const uchar * buffer,size_t count,myf myFlags)92 size_t File_io::write(File file, const uchar *buffer, size_t count,
93 myf myFlags) {
94 size_t bytes_written = mysql_file_write(file, buffer, count, MYF(0));
95
96 if (bytes_written != count && (myFlags & (MY_WME))) {
97 char error_buffer[MYSYS_STRERROR_SIZE];
98 my_warning(EE_WRITE, my_filename(file), my_errno(),
99 my_strerror(error_buffer, sizeof(error_buffer), my_errno()));
100 }
101 return bytes_written;
102 }
103
seek(File file,my_off_t pos,int whence,myf myFlags)104 my_off_t File_io::seek(File file, my_off_t pos, int whence, myf myFlags) {
105 my_off_t moved_to_position = mysql_file_seek(file, pos, whence, MYF(0));
106
107 if (moved_to_position == MY_FILEPOS_ERROR && (myFlags & MY_WME)) {
108 char error_buffer[MYSYS_STRERROR_SIZE];
109 my_warning(EE_CANT_SEEK, my_filename(file), my_errno(),
110 my_strerror(error_buffer, sizeof(error_buffer), my_errno()));
111 }
112 return moved_to_position;
113 }
114
tell(File file,myf myFlags)115 my_off_t File_io::tell(File file, myf myFlags) {
116 my_off_t position = mysql_file_tell(file, MYF(0));
117
118 if ((position == ((my_off_t)-1)) && (myFlags & MY_WME)) {
119 char error_buffer[MYSYS_STRERROR_SIZE];
120 my_warning(EE_CANT_SEEK, my_filename(file), my_errno(),
121 my_strerror(error_buffer, sizeof(error_buffer), my_errno()));
122 }
123 return position;
124 }
125
sync(File file,myf myFlags)126 int File_io::sync(File file, myf myFlags) {
127 int result = my_sync(file, MYF(0));
128
129 if (result && (myFlags & MY_WME)) {
130 char error_buffer[MYSYS_STRERROR_SIZE];
131 my_warning(EE_SYNC, my_filename(file), my_errno(),
132 my_strerror(error_buffer, sizeof(error_buffer), my_errno()));
133 }
134 return result;
135 }
136
fstat(File file,MY_STAT * stat_area,myf myFlags)137 int File_io::fstat(File file, MY_STAT *stat_area, myf myFlags) {
138 int result = my_fstat(file, stat_area);
139
140 if (result && (myFlags & MY_WME)) {
141 std::stringstream error_message;
142 error_message << "Error while reading stat for " << my_filename(file)
143 << ". Please check if file " << my_filename(file)
144 << " was not removed. OS returned this error: "
145 << strerror(errno);
146 if (current_thd != nullptr && is_super_user())
147 push_warning(current_thd, Sql_condition::SL_WARNING, errno,
148 error_message.str().c_str());
149 logger->log(ERROR_LEVEL, ER_KEYRING_FAILED_TO_GET_FILE_STAT,
150 my_filename(file), my_filename(file), strerror(errno));
151 }
152 return result;
153 }
154
remove(const char * filename,myf myFlags)155 bool File_io::remove(const char *filename, myf myFlags) {
156 if (::remove(filename) != 0 && (myFlags & MY_WME)) {
157 std::stringstream error_message;
158 error_message << "Could not remove file " << filename
159 << " OS retuned this error: " << strerror(errno);
160 if (current_thd != nullptr && is_super_user())
161 push_warning(current_thd, Sql_condition::SL_WARNING, errno,
162 error_message.str().c_str());
163 logger->log(ERROR_LEVEL, ER_KEYRING_FAILED_TO_REMOVE_FILE, filename,
164 strerror(errno));
165 return true;
166 }
167 return false;
168 }
169
truncate(File file,myf myFlags)170 bool File_io::truncate(File file, myf myFlags) {
171 #ifdef _WIN32
172 LARGE_INTEGER length;
173 length.QuadPart = 0;
174 HANDLE hFile = my_get_osfhandle(file);
175
176 if ((hFile == INVALID_HANDLE_VALUE ||
177 !SetFilePointerEx(hFile, length, NULL, FILE_BEGIN) ||
178 !SetEndOfFile(hFile)) &&
179 (myFlags & MY_WME)) {
180 my_osmaperr(GetLastError());
181 set_my_errno(errno);
182 // char error_buffer[MYSYS_STRERROR_SIZE];
183 // my_warning(EE_CANT_SEEK, my_filename(file), my_errno(),
184 // my_strerror(error_buffer, sizeof(error_buffer), my_errno()));
185 // return true;
186 // }
187 #elif defined(HAVE_FTRUNCATE)
188 if (ftruncate(file, (off_t)0) && (myFlags & MY_WME)) {
189 #else
190 DBUG_ASSERT(0);
191 #endif
192 std::stringstream error_message;
193 error_message << "Could not truncate file " << my_filename(file)
194 << ". OS retuned this error: " << strerror(errno);
195 if (current_thd != nullptr && is_super_user())
196 push_warning(current_thd, Sql_condition::SL_WARNING, errno,
197 error_message.str().c_str());
198 logger->log(ERROR_LEVEL, ER_KEYRING_FAILED_TO_TRUNCATE_FILE,
199 my_filename(file), strerror(errno));
200 return true;
201 }
202 //#else
203 // DBUG_ASSERT(0);
204 //#endif
205 return false;
206 } // namespace keyring
207
208 void File_io::my_warning(int nr, ...) {
209 va_list args;
210 const char *format;
211
212 if (!(format = my_get_err_msg(nr))) {
213 std::stringstream error_message;
214 error_message << "Unknown error " << nr;
215 if (current_thd != nullptr && is_super_user())
216 push_warning(current_thd, Sql_condition::SL_WARNING, nr,
217 error_message.str().c_str());
218 logger->log(ERROR_LEVEL, ER_KEYRING_UNKNOWN_ERROR, nr);
219 } else {
220 char warning[MYSQL_ERRMSG_SIZE];
221
222 va_start(args, nr);
223 vsnprintf(warning, sizeof(warning), format, args);
224 va_end(args);
225 if (current_thd != nullptr && is_super_user())
226 push_warning(current_thd, Sql_condition::SL_WARNING, nr, warning);
227 logger->log(ERROR_LEVEL, ER_KEYRING_FILE_IO_ERROR, warning);
228 }
229 }
230
231 } // namespace keyring
232