1 /* Copyright (c) 2016, 2021, Oracle and/or its affiliates.
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 <my_global.h>
24 #include <mysql/plugin_keyring.h>
25 #include <my_rnd.h>
26 #include "keyring.h"
27 #include "buffered_file_io.h"
28
29 #ifdef _WIN32
30 #define MYSQL_DEFAULT_KEYRINGFILE MYSQL_KEYRINGDIR"\\keyring"
31 #else
32 #define MYSQL_DEFAULT_KEYRINGFILE MYSQL_KEYRINGDIR"/keyring"
33 #endif
34
35 using keyring::Buffered_file_io;
36 using keyring::Keys_container;
37 using keyring::Keys_iterator;
38 using keyring::Logger;
39
40 mysql_rwlock_t LOCK_keyring;
41
check_keyring_file_data(MYSQL_THD thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * save,st_mysql_value * value)42 int check_keyring_file_data(MYSQL_THD thd MY_ATTRIBUTE((unused)),
43 struct st_mysql_sys_var *var MY_ATTRIBUTE((unused)),
44 void *save, st_mysql_value *value)
45 {
46 char buff[FN_REFLEN+1];
47 const char *keyring_filename;
48 int len = sizeof(buff);
49 boost::movelib::unique_ptr<IKeys_container> new_keys(new Keys_container(logger.get()));
50
51 (*(const char **) save)= NULL;
52 keyring_filename= value->val_str(value, buff, &len);
53 mysql_rwlock_wrlock(&LOCK_keyring);
54 if (create_keyring_dir_if_does_not_exist(keyring_filename))
55 {
56 mysql_rwlock_unlock(&LOCK_keyring);
57 logger->log(MY_ERROR_LEVEL, "keyring_file_data cannot be set to new value"
58 " as the keyring file cannot be created/accessed in the provided path");
59 return 1;
60 }
61 try
62 {
63 IKeyring_io *keyring_io(new Buffered_file_io(logger.get()));
64 if (new_keys->init(keyring_io, keyring_filename))
65 {
66 mysql_rwlock_unlock(&LOCK_keyring);
67 return 1;
68 }
69 *reinterpret_cast<IKeys_container **>(save)= new_keys.get();
70 new_keys.release();
71 mysql_rwlock_unlock(&LOCK_keyring);
72 }
73 catch (...)
74 {
75 mysql_rwlock_unlock(&LOCK_keyring);
76 return 1;
77 }
78 return(0);
79 }
80
81 static char *keyring_file_data_value= NULL;
82 static MYSQL_SYSVAR_STR(
83 data, /* name */
84 keyring_file_data_value, /* value */
85 PLUGIN_VAR_RQCMDARG, /* flags */
86 "The path to the keyring file. Must be specified", /* comment */
87 check_keyring_file_data, /* check() */
88 update_keyring_file_data, /* update() */
89 MYSQL_DEFAULT_KEYRINGFILE /* default */
90 );
91 static MYSQL_SYSVAR_BOOL(open_mode, keyring_open_mode,
92 PLUGIN_VAR_INVISIBLE | PLUGIN_VAR_RQCMDARG,
93 "Mode in which keyring file should be opened", NULL,
94 NULL, TRUE);
95
96 static struct st_mysql_sys_var *keyring_file_system_variables[]= {
97 MYSQL_SYSVAR(data),
98 MYSQL_SYSVAR(open_mode),
99 NULL
100 };
101
keyring_init(MYSQL_PLUGIN plugin_info)102 static int keyring_init(MYSQL_PLUGIN plugin_info)
103 {
104 try
105 {
106 #ifdef HAVE_PSI_INTERFACE
107 keyring_init_psi_keys();
108 #endif
109
110 DBUG_EXECUTE_IF("simulate_keyring_init_error", return TRUE;);
111
112 if (init_keyring_locks())
113 return TRUE;
114
115 logger.reset(new Logger(plugin_info));
116 if (create_keyring_dir_if_does_not_exist(keyring_file_data_value))
117 {
118 logger->log(MY_ERROR_LEVEL, "Could not create keyring directory "
119 "The keyring_file will stay unusable until correct path to the keyring "
120 "directory gets provided");
121 return TRUE;
122 }
123 keys.reset(new Keys_container(logger.get()));
124 IKeyring_io *keyring_io= new Buffered_file_io(logger.get());
125 if (keys->init(keyring_io, keyring_file_data_value))
126 {
127 is_keys_container_initialized = FALSE;
128 logger->log(MY_ERROR_LEVEL, "keyring_file initialization failure. Please check"
129 " if the keyring_file_data points to readable keyring file or keyring file"
130 " can be created in the specified location. "
131 "The keyring_file will stay unusable until correct path to the keyring file "
132 "gets provided");
133 return TRUE;
134 }
135 is_keys_container_initialized = TRUE;
136 return FALSE;
137 }
138 catch (...)
139 {
140 if (logger != NULL)
141 logger->log(MY_ERROR_LEVEL, "keyring_file initialization failure due to internal"
142 " exception inside the plugin");
143 return TRUE;
144 }
145 }
146
keyring_deinit(void * arg MY_ATTRIBUTE ((unused)))147 int keyring_deinit(void *arg MY_ATTRIBUTE((unused)))
148 {
149 //not taking a lock here as the calls to keyring_deinit are serialized by
150 //the plugin framework
151 keys.reset();
152 logger.reset();
153 keyring_file_data.reset();
154 mysql_rwlock_destroy(&LOCK_keyring);
155 return 0;
156 }
157
mysql_key_fetch(const char * key_id,char ** key_type,const char * user_id,void ** key,size_t * key_len)158 my_bool mysql_key_fetch(const char *key_id, char **key_type, const char *user_id,
159 void **key, size_t *key_len)
160 {
161 return mysql_key_fetch<keyring::Key>(key_id, key_type, user_id, key, key_len,
162 "keyring_file");
163 }
164
mysql_key_store(const char * key_id,const char * key_type,const char * user_id,const void * key,size_t key_len)165 my_bool mysql_key_store(const char *key_id, const char *key_type,
166 const char *user_id, const void *key, size_t key_len)
167 {
168 return mysql_key_store<keyring::Key>(key_id, key_type, user_id, key, key_len,
169 "keyring_file");
170 }
171
mysql_key_remove(const char * key_id,const char * user_id)172 my_bool mysql_key_remove(const char *key_id, const char *user_id)
173 {
174 return mysql_key_remove<keyring::Key>(key_id, user_id, "keyring_file");
175 }
176
177
mysql_key_generate(const char * key_id,const char * key_type,const char * user_id,size_t key_len)178 my_bool mysql_key_generate(const char *key_id, const char *key_type,
179 const char *user_id, size_t key_len)
180 {
181 try
182 {
183 boost::movelib::unique_ptr<IKey> key_candidate(new keyring::Key(key_id, key_type, user_id, NULL, 0));
184
185 boost::movelib::unique_ptr<uchar[]> key(new uchar[key_len]);
186 if (key.get() == NULL)
187 return TRUE;
188 memset(key.get(), 0, key_len);
189 if (is_keys_container_initialized == FALSE || check_key_for_writing(key_candidate.get(), "generating") ||
190 my_rand_buffer(key.get(), key_len))
191 return TRUE;
192
193 return mysql_key_store(key_id, key_type, user_id, key.get(), key_len) == TRUE;
194 }
195 catch (...)
196 {
197 if (logger != NULL)
198 logger->log(MY_ERROR_LEVEL, "Failed to generate a key due to internal exception inside keyring_file plugin");
199 return TRUE;
200 }
201 }
202
mysql_key_iterator_init(void ** key_iterator)203 static void mysql_key_iterator_init(void **key_iterator)
204 {
205 *key_iterator= new Keys_iterator(logger.get());
206 mysql_key_iterator_init<keyring::Key>(static_cast<Keys_iterator*>(*key_iterator),
207 "keyring_file");
208 }
209
mysql_key_iterator_deinit(void * key_iterator)210 static void mysql_key_iterator_deinit(void *key_iterator)
211 {
212 mysql_key_iterator_deinit<keyring::Key>(static_cast<Keys_iterator*>(key_iterator),
213 "keyring_file");
214 delete static_cast<Keys_iterator*>(key_iterator);
215 }
216
mysql_key_iterator_get_key(void * key_iterator,char * key_id,char * user_id)217 static bool mysql_key_iterator_get_key(void *key_iterator,
218 char *key_id, char *user_id)
219 {
220 return mysql_key_iterator_get_key<keyring::Key>(static_cast<Keys_iterator*>(key_iterator),
221 key_id, user_id, "keyring_file");
222 }
223
224 /* Plugin type-specific descriptor */
225 static struct st_mysql_keyring keyring_descriptor=
226 {
227 MYSQL_KEYRING_INTERFACE_VERSION,
228 mysql_key_store,
229 mysql_key_fetch,
230 mysql_key_remove,
231 mysql_key_generate,
232 mysql_key_iterator_init,
233 mysql_key_iterator_deinit,
234 mysql_key_iterator_get_key
235 };
236
mysql_declare_plugin(keyring_file)237 mysql_declare_plugin(keyring_file)
238 {
239 MYSQL_KEYRING_PLUGIN, /* type */
240 &keyring_descriptor, /* descriptor */
241 "keyring_file", /* name */
242 "Oracle Corporation", /* author */
243 "store/fetch authentication data to/from a flat file", /* description */
244 PLUGIN_LICENSE_GPL,
245 keyring_init, /* init function (when loaded) */
246 keyring_deinit, /* deinit function (when unloaded) */
247 0x0100, /* version */
248 NULL, /* status variables */
249 keyring_file_system_variables, /* system variables */
250 NULL,
251 0,
252 }
253 mysql_declare_plugin_end;
254