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