1 /* Copyright (c) 2000, 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 "sql_base.h" /* close_mysql_tables */
24 #include "sql_parse.h" /* check_access */
25 #include "log.h" /* sql_print_warning, query_logger */
26 #include <sql_common.h> /* mpvio_info */
27 #include "sql_connect.h" /* thd_init_client_charset */
28 /* get_or_create_user_conn */
29 /* check_for_max_user_connections */
30 /* release_user_connection */
31 #include "hostname.h" /* Host_errors, inc_host_errors */
32 #include "password.h" // my_make_scrambled_password
33 #include "sql_db.h" /* mysql_change_db */
34 #include "connection_handler_manager.h"
35 #include "crypt_genhash_impl.h" /* generate_user_salt */
36 #include <mysql/plugin_validate_password.h> /* validate_password plugin */
37 #include <mysql/service_my_plugin_log.h>
38 #include "sys_vars.h"
39 #include <fstream> /* std::fstream */
40 #include <string> /* std::string */
41 #include <algorithm> /* for_each */
42 #include <stdexcept> /* Exception handling */
43 #include <vector> /* std::vector */
44 #include <stdint.h>
45
46 #if defined(HAVE_OPENSSL)
47 #include <openssl/rsa.h>
48 #include <openssl/pem.h>
49 #include <openssl/err.h>
50 #include <openssl/x509v3.h>
51 #endif /* HAVE OPENSSL */
52
53 #include "auth_internal.h"
54 #include "sql_auth_cache.h"
55 #include "sql_authentication.h"
56 #include "tztime.h"
57 #include "sql_time.h"
58 #include <mutex_lock.h>
59
60 /****************************************************************************
61 AUTHENTICATION CODE
62 including initial connect handshake, invoking appropriate plugins,
63 client-server plugin negotiation, COM_CHANGE_USER, and native
64 MySQL authentication plugins.
65 ****************************************************************************/
66
67 LEX_CSTRING native_password_plugin_name= {
68 C_STRING_WITH_LEN("mysql_native_password")
69 };
70
71 LEX_CSTRING sha256_password_plugin_name= {
72 C_STRING_WITH_LEN("sha256_password")
73 };
74
75 LEX_CSTRING validate_password_plugin_name= {
76 C_STRING_WITH_LEN("validate_password")
77 };
78
79 LEX_CSTRING default_auth_plugin_name;
80
81 plugin_ref native_password_plugin;
82
83 my_bool disconnect_on_expired_password= TRUE;
84
85 /** Size of the header fields of an authentication packet. */
86 #define AUTH_PACKET_HEADER_SIZE_PROTO_41 32
87 #define AUTH_PACKET_HEADER_SIZE_PROTO_40 5
88
89 #if defined(HAVE_OPENSSL)
90 #define MAX_CIPHER_LENGTH 1024
91 #define SHA256_PASSWORD_MAX_PASSWORD_LENGTH MAX_PLAINTEXT_LENGTH
92 #define AUTH_DEFAULT_RSA_PRIVATE_KEY "private_key.pem"
93 #define AUTH_DEFAULT_RSA_PUBLIC_KEY "public_key.pem"
94
95 #define DEFAULT_SSL_CLIENT_CERT "client-cert.pem"
96 #define DEFAULT_SSL_CLIENT_KEY "client-key.pem"
97
98 #define MAX_CN_NAME_LENGTH 64
99
100 my_bool opt_auto_generate_certs= TRUE;
101
102 char *auth_rsa_private_key_path;
103 char *auth_rsa_public_key_path;
104 my_bool auth_rsa_auto_generate_rsa_keys= TRUE;
105
106 static bool do_auto_rsa_keys_generation();
107 static Rsa_authentication_keys g_rsa_keys;
108
109 #endif /* HAVE_OPENSSL */
110
111 bool
init_client_charset(uint cs_number)112 Thd_charset_adapter::init_client_charset(uint cs_number)
113 {
114 if (thd_init_client_charset(thd, cs_number))
115 return true;
116 thd->update_charset();
117 return thd->is_error();
118 }
119
120
121 const CHARSET_INFO *
charset()122 Thd_charset_adapter::charset()
123 {
124 return thd->charset();
125 }
126
127 #if defined(HAVE_OPENSSL)
128
129 /**
130 @brief Set key file path
131
132 @param key[in] Points to either auth_rsa_private_key_path or
133 auth_rsa_public_key_path.
134 @param key_file_path[out] Stores value of actual key file path.
135
136 */
137 void
get_key_file_path(char * key,String * key_file_path)138 Rsa_authentication_keys::get_key_file_path(char *key, String *key_file_path)
139 {
140 /*
141 If a fully qualified path is entered use that, else assume the keys are
142 stored in the data directory.
143 */
144 if (strchr(key, FN_LIBCHAR) != NULL
145 #ifdef _WIN32
146 || strchr(key, FN_LIBCHAR2) != NULL
147 #endif
148 )
149 key_file_path->set_quick(key, strlen(key), system_charset_info);
150 else
151 {
152 key_file_path->append(mysql_real_data_home, strlen(mysql_real_data_home));
153 if ((*key_file_path)[key_file_path->length()] != FN_LIBCHAR)
154 key_file_path->append(FN_LIBCHAR);
155 key_file_path->append(key);
156 }
157 }
158
159
160 /**
161 @brief Read a key file and store its value in RSA structure
162
163 @param key_ptr[out] Address of pointer to RSA. This is set to
164 point to a non null value if key is correctly
165 read.
166 @param is_priv_key[in] Whether we are reading private key or public
167 key.
168 @param key_text_buffer[out] To store key file content of public key.
169
170 @return Error status
171 @retval false Success : Either both keys are read or none
172 are.
173 @retval true Failure : An appropriate error is raised.
174 */
175 bool
read_key_file(RSA ** key_ptr,bool is_priv_key,char ** key_text_buffer)176 Rsa_authentication_keys::read_key_file(RSA **key_ptr,
177 bool is_priv_key,
178 char **key_text_buffer)
179 {
180 String key_file_path;
181 char *key;
182 const char *key_type;
183 FILE *key_file= NULL;
184
185 key= is_priv_key ? auth_rsa_private_key_path : auth_rsa_public_key_path;
186 key_type= is_priv_key ? "private" : "public";
187 *key_ptr= NULL;
188
189 get_key_file_path(key, &key_file_path);
190
191 /*
192 Check for existance of private key/public key file.
193 */
194 if ((key_file= fopen(key_file_path.c_ptr(), "r")) == NULL)
195 {
196 sql_print_warning("RSA %s key file not found: %s."
197 " Some authentication plugins will not work.",
198 key_type, key_file_path.c_ptr());
199 }
200 else
201 {
202 *key_ptr= is_priv_key ? PEM_read_RSAPrivateKey(key_file, 0, 0, 0) :
203 PEM_read_RSA_PUBKEY(key_file, 0, 0, 0);
204
205 if (!(*key_ptr))
206 {
207 char error_buf[MYSQL_ERRMSG_SIZE];
208 ERR_error_string_n(ERR_get_error(), error_buf, MYSQL_ERRMSG_SIZE);
209 sql_print_error("Failure to parse RSA %s key (file exists): %s:"
210 " %s", key_type, key_file_path.c_ptr(), error_buf);
211
212 /*
213 Call ERR_clear_error() just in case there are more than 1 entry in the
214 OpenSSL thread's error queue.
215 */
216 ERR_clear_error();
217
218 return true;
219 }
220
221 /* For public key, read key file content into a char buffer. */
222 bool read_error= false;
223 if (!is_priv_key)
224 {
225 int filesize;
226 fseek(key_file, 0, SEEK_END);
227 filesize= ftell(key_file);
228 fseek(key_file, 0, SEEK_SET);
229 *key_text_buffer= new char[filesize+1];
230 int items_read= fread(*key_text_buffer, filesize, 1, key_file);
231 read_error= items_read != 1;
232 if (read_error)
233 {
234 char errbuf[MYSQL_ERRMSG_SIZE];
235 sql_print_error("Failure to read key file: %s",
236 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, my_errno()));
237 }
238 (*key_text_buffer)[filesize]= '\0';
239 }
240 fclose(key_file);
241 return read_error;
242 }
243 return false;
244 }
245
246
Rsa_authentication_keys()247 Rsa_authentication_keys::Rsa_authentication_keys()
248 {
249 m_cipher_len= 0;
250 m_private_key= 0;
251 m_public_key= 0;
252 m_pem_public_key= 0;
253 }
254
255
256 void
free_memory()257 Rsa_authentication_keys::free_memory()
258 {
259 if (m_private_key)
260 RSA_free(m_private_key);
261
262 if (m_public_key)
263 {
264 RSA_free(m_public_key);
265 m_cipher_len= 0;
266 }
267
268 if (m_pem_public_key)
269 delete [] m_pem_public_key;
270 }
271
272
273 void *
allocate_pem_buffer(size_t buffer_len)274 Rsa_authentication_keys::allocate_pem_buffer(size_t buffer_len)
275 {
276 m_pem_public_key= new char[buffer_len];
277 return m_pem_public_key;
278 }
279
280
281 int
get_cipher_length()282 Rsa_authentication_keys::get_cipher_length()
283 {
284 return (m_cipher_len= RSA_size(m_public_key));
285 }
286
287
288 /**
289 @brief Read RSA private key and public key from file and store them
290 in m_private_key and m_public_key. Also, read public key in
291 text format and store it in m_pem_public_key.
292
293 @return Error status
294 @retval false Success : Either both keys are read or none are.
295 @retval true Failure : An appropriate error is raised.
296 */
297 bool
read_rsa_keys()298 Rsa_authentication_keys::read_rsa_keys()
299 {
300 RSA *rsa_private_key_ptr= NULL;
301 RSA *rsa_public_key_ptr= NULL;
302 char *pub_key_buff= NULL;
303
304 if ((strlen(auth_rsa_private_key_path) == 0) &&
305 (strlen(auth_rsa_public_key_path) == 0))
306 {
307 sql_print_information("RSA key files not found."
308 " Some authentication plugins will not work.");
309 return false;
310 }
311
312 /*
313 Read private key in RSA format.
314 */
315 if (read_key_file(&rsa_private_key_ptr, true, NULL))
316 return true;
317
318 /*
319 Read public key in RSA format.
320 */
321 if (read_key_file(&rsa_public_key_ptr, false, &pub_key_buff))
322 {
323 if (rsa_private_key_ptr)
324 RSA_free(rsa_private_key_ptr);
325 return true;
326 }
327
328 /*
329 If both key files are read successfully then assign values to following
330 members of the class
331 1. m_pem_public_key
332 2. m_private_key
333 3. m_public_key
334
335 Else clean up.
336 */
337 if (rsa_private_key_ptr && rsa_public_key_ptr)
338 {
339 size_t buff_len= strlen(pub_key_buff);
340 char *pem_file_buffer= (char *)allocate_pem_buffer(buff_len + 1);
341 strncpy(pem_file_buffer, pub_key_buff, buff_len);
342 pem_file_buffer[buff_len]= '\0';
343
344 m_private_key= rsa_private_key_ptr;
345 m_public_key= rsa_public_key_ptr;
346
347 delete [] pub_key_buff;
348 }
349 else
350 {
351 if (rsa_private_key_ptr)
352 RSA_free(rsa_private_key_ptr);
353
354 if (rsa_public_key_ptr)
355 {
356 delete [] pub_key_buff;
357 RSA_free(rsa_public_key_ptr);
358 }
359 }
360 return false;
361 }
362
363 #endif /* HAVE_OPENSSL */
364
365 /**
366 Initialize default authentication plugin based on command line options or
367 configuration file settings.
368
369 @param plugin_name Name of the plugin
370 @param plugin_name_length Length of the string
371 */
372
set_default_auth_plugin(char * plugin_name,size_t plugin_name_length)373 int set_default_auth_plugin(char *plugin_name, size_t plugin_name_length)
374 {
375 default_auth_plugin_name.str= plugin_name;
376 default_auth_plugin_name.length= plugin_name_length;
377
378 optimize_plugin_compare_by_pointer(&default_auth_plugin_name);
379
380 #if defined(HAVE_OPENSSL)
381 if (default_auth_plugin_name.str == sha256_password_plugin_name.str)
382 {
383 /*
384 Adjust default password algorithm to fit the default authentication
385 method.
386 */
387 global_system_variables.old_passwords= 2;
388 }
389 else
390 #endif /* HAVE_OPENSSL */
391 if (default_auth_plugin_name.str != native_password_plugin_name.str)
392 return 1;
393
394 return 0;
395 }
396
397
optimize_plugin_compare_by_pointer(LEX_CSTRING * plugin_name)398 void optimize_plugin_compare_by_pointer(LEX_CSTRING *plugin_name)
399 {
400 #if defined(HAVE_OPENSSL)
401 if (my_strcasecmp(system_charset_info, sha256_password_plugin_name.str,
402 plugin_name->str) == 0)
403 {
404 plugin_name->str= sha256_password_plugin_name.str;
405 plugin_name->length= sha256_password_plugin_name.length;
406 }
407 else
408 #endif
409 if (my_strcasecmp(system_charset_info, native_password_plugin_name.str,
410 plugin_name->str) == 0)
411 {
412 plugin_name->str= native_password_plugin_name.str;
413 plugin_name->length= native_password_plugin_name.length;
414 }
415 }
416
417
auth_plugin_is_built_in(const char * plugin_name)418 bool auth_plugin_is_built_in(const char *plugin_name)
419 {
420 return (plugin_name == native_password_plugin_name.str
421 #if defined(HAVE_OPENSSL)
422 || plugin_name == sha256_password_plugin_name.str
423 #endif
424 );
425 }
426
427
428 /**
429 Only the plugins that are known to use the mysql.user table
430 to store their passwords support password expiration atm.
431 TODO: create a service and extend the plugin API to support
432 password expiration for external plugins.
433
434 @retval false expiration not supported
435 @retval true expiration supported
436 */
auth_plugin_supports_expiration(const char * plugin_name)437 bool auth_plugin_supports_expiration(const char *plugin_name)
438 {
439 return (!plugin_name || !*plugin_name ||
440 plugin_name == native_password_plugin_name.str
441 #if defined(HAVE_OPENSSL)
442 || plugin_name == sha256_password_plugin_name.str
443 #endif
444 );
445 }
446
447
448 /* few defines to have less ifdef's in the code below */
449 #ifdef EMBEDDED_LIBRARY
450 #undef HAVE_OPENSSL
451 #ifdef NO_EMBEDDED_ACCESS_CHECKS
452 #define initialized 0
453 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
454 #endif /* EMBEDDED_LIBRARY */
455 #ifndef HAVE_OPENSSL
456 #define ssl_acceptor_fd 0
457 #define sslaccept(A,B,C) 1
458 #endif /* HAVE_OPENSSL */
459
460 /**
461 a helper function to report an access denied error in all the proper places
462 */
login_failed_error(MPVIO_EXT * mpvio,int passwd_used)463 static void login_failed_error(MPVIO_EXT *mpvio, int passwd_used)
464 {
465 THD *thd= current_thd;
466
467 if (thd->is_error())
468 sql_print_information("%s", thd->get_stmt_da()->message_text());
469
470 else if (passwd_used == 2)
471 {
472 my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
473 mpvio->auth_info.user_name,
474 mpvio->auth_info.host_or_ip);
475 query_logger.general_log_print(thd, COM_CONNECT,
476 ER(ER_ACCESS_DENIED_NO_PASSWORD_ERROR),
477 mpvio->auth_info.user_name,
478 mpvio->auth_info.host_or_ip);
479 /*
480 Log access denied messages to the error log when log-warnings = 2
481 so that the overhead of the general query log is not required to track
482 failed connections.
483 */
484 sql_print_information(ER(ER_ACCESS_DENIED_NO_PASSWORD_ERROR),
485 mpvio->auth_info.user_name,
486 mpvio->auth_info.host_or_ip);
487 }
488 else
489 {
490 my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
491 mpvio->auth_info.user_name,
492 mpvio->auth_info.host_or_ip,
493 passwd_used ? ER(ER_YES) : ER(ER_NO));
494 query_logger.general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
495 mpvio->auth_info.user_name,
496 mpvio->auth_info.host_or_ip,
497 passwd_used ? ER(ER_YES) : ER(ER_NO));
498 /*
499 Log access denied messages to the error log when log-warnings = 2
500 so that the overhead of the general query log is not required to track
501 failed connections.
502 */
503 sql_print_information(ER(ER_ACCESS_DENIED_ERROR),
504 mpvio->auth_info.user_name,
505 mpvio->auth_info.host_or_ip,
506 passwd_used ? ER(ER_YES) : ER(ER_NO));
507 }
508 }
509
510
511 /**
512 sends a server handshake initialization packet, the very first packet
513 after the connection was established
514
515 Packet format:
516
517 Bytes Content
518 ----- ----
519 1 protocol version (always 10)
520 n server version string, \0-terminated
521 4 thread id
522 8 first 8 bytes of the plugin provided data (scramble)
523 1 \0 byte, terminating the first part of a scramble
524 2 server capabilities (two lower bytes)
525 1 server character set
526 2 server status
527 2 server capabilities (two upper bytes)
528 1 length of the scramble
529 10 reserved, always 0
530 n rest of the plugin provided data (at least 12 bytes)
531 1 \0 byte, terminating the second part of a scramble
532
533 @retval 0 ok
534 @retval 1 error
535 */
send_server_handshake_packet(MPVIO_EXT * mpvio,const char * data,uint data_len)536 static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
537 const char *data, uint data_len)
538 {
539 assert(mpvio->status == MPVIO_EXT::FAILURE);
540 assert(data_len <= 255);
541 Protocol_classic *protocol= mpvio->protocol;
542
543 char *buff= (char *) my_alloca(1 + SERVER_VERSION_LENGTH + data_len + 64);
544 char scramble_buf[SCRAMBLE_LENGTH];
545 char *end= buff;
546
547 DBUG_ENTER("send_server_handshake_packet");
548 *end++= protocol_version;
549
550 protocol->set_client_capabilities(CLIENT_BASIC_FLAGS);
551
552 if (opt_using_transactions)
553 protocol->add_client_capability(CLIENT_TRANSACTIONS);
554
555 protocol->add_client_capability(CAN_CLIENT_COMPRESS);
556
557 if (ssl_acceptor_fd)
558 {
559 protocol->add_client_capability(CLIENT_SSL);
560 protocol->add_client_capability(CLIENT_SSL_VERIFY_SERVER_CERT);
561 }
562
563 if (data_len)
564 {
565 mpvio->cached_server_packet.pkt= (char*) memdup_root(mpvio->mem_root,
566 data, data_len);
567 mpvio->cached_server_packet.pkt_len= data_len;
568 }
569
570 if (data_len < SCRAMBLE_LENGTH)
571 {
572 if (data_len)
573 {
574 /*
575 the first packet *must* have at least 20 bytes of a scramble.
576 if a plugin provided less, we pad it to 20 with zeros
577 */
578 memcpy(scramble_buf, data, data_len);
579 memset(scramble_buf + data_len, 0, SCRAMBLE_LENGTH - data_len);
580 data= scramble_buf;
581 }
582 else
583 {
584 /*
585 if the default plugin does not provide the data for the scramble at
586 all, we generate a scramble internally anyway, just in case the
587 user account (that will be known only later) uses a
588 native_password_plugin (which needs a scramble). If we don't send a
589 scramble now - wasting 20 bytes in the packet -
590 native_password_plugin will have to send it in a separate packet,
591 adding one more round trip.
592 */
593 generate_user_salt(mpvio->scramble, SCRAMBLE_LENGTH + 1);
594 data= mpvio->scramble;
595 }
596 data_len= SCRAMBLE_LENGTH;
597 }
598
599 end= my_stpnmov(end, server_version, SERVER_VERSION_LENGTH) + 1;
600
601 assert(sizeof(my_thread_id) == 4);
602 int4store((uchar*) end, mpvio->thread_id);
603 end+= 4;
604
605 /*
606 Old clients does not understand long scrambles, but can ignore packet
607 tail: that's why first part of the scramble is placed here, and second
608 part at the end of packet.
609 */
610 end= (char*) memcpy(end, data, AUTH_PLUGIN_DATA_PART_1_LENGTH);
611 end+= AUTH_PLUGIN_DATA_PART_1_LENGTH;
612 *end++= 0;
613
614 int2store(end, static_cast<uint16>(protocol->get_client_capabilities()));
615 /* write server characteristics: up to 16 bytes allowed */
616 end[2]= (char) default_charset_info->number;
617 int2store(end + 3, mpvio->server_status[0]);
618 int2store(end + 5, protocol->get_client_capabilities() >> 16);
619 end[7]= data_len;
620 DBUG_EXECUTE_IF("poison_srv_handshake_scramble_len", end[7]= -100;);
621 DBUG_EXECUTE_IF("increase_srv_handshake_scramble_len", end[7]= 50;);
622 memset(end + 8, 0, 10);
623 end+= 18;
624 /* write scramble tail */
625 end= (char*) memcpy(end, data + AUTH_PLUGIN_DATA_PART_1_LENGTH,
626 data_len - AUTH_PLUGIN_DATA_PART_1_LENGTH);
627 end+= data_len - AUTH_PLUGIN_DATA_PART_1_LENGTH;
628 end= strmake(end, plugin_name(mpvio->plugin)->str,
629 plugin_name(mpvio->plugin)->length);
630
631 int res= protocol->write((uchar*) buff, (size_t) (end - buff + 1)) ||
632 protocol->flush_net();
633 DBUG_RETURN (res);
634 }
635
636
637 /**
638 sends a "change plugin" packet, requesting a client to restart authentication
639 using a different authentication plugin
640
641 Packet format:
642
643 Bytes Content
644 ----- ----
645 1 byte with the value 254
646 n client plugin to use, \0-terminated
647 n plugin provided data
648
649 @retval 0 ok
650 @retval 1 error
651 */
send_plugin_request_packet(MPVIO_EXT * mpvio,const uchar * data,uint data_len)652 static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
653 const uchar *data, uint data_len)
654 {
655 assert(mpvio->packets_written == 1);
656 assert(mpvio->packets_read == 1);
657 static uchar switch_plugin_request_buf[]= { 254 };
658
659 DBUG_ENTER("send_plugin_request_packet");
660 mpvio->status= MPVIO_EXT::FAILURE; // the status is no longer RESTART
661
662 std::string client_auth_plugin(
663 ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))
664 ->client_auth_plugin);
665
666 assert(client_auth_plugin.c_str());
667
668 DBUG_EXECUTE_IF("invalidate_client_auth_plugin", {
669 client_auth_plugin.clear();
670 client_auth_plugin = std::string("..") + std::string(FN_DIRSEP) +
671 std::string("..") + std::string(FN_DIRSEP) +
672 std::string("mysql_native_password");
673 });
674 /*
675 If we're dealing with an older client we can't just send a change plugin
676 packet to re-initiate the authentication handshake, because the client
677 won't understand it. The good thing is that we don't need to : the old client
678 expects us to just check the user credentials here, which we can do by just reading
679 the cached data that are placed there by parse_com_change_user_packet()
680 In this case we just do nothing and behave as if normal authentication
681 should continue.
682 */
683 if (!(mpvio->protocol->has_client_capability(CLIENT_PLUGIN_AUTH)))
684 {
685 DBUG_PRINT("info", ("old client sent a COM_CHANGE_USER"));
686 assert(mpvio->cached_client_reply.pkt);
687 /* get the status back so the read can process the cached result */
688 mpvio->status= MPVIO_EXT::RESTART;
689 DBUG_RETURN(0);
690 }
691
692 DBUG_PRINT("info", ("requesting client to use the %s plugin",
693 client_auth_plugin.c_str()));
694 DBUG_RETURN(net_write_command(mpvio->protocol->get_net(),
695 switch_plugin_request_buf[0],
696 (uchar*) client_auth_plugin.c_str(),
697 client_auth_plugin.size() + 1,
698 (uchar*) data, data_len));
699 }
700
701
702
703 #ifndef NO_EMBEDDED_ACCESS_CHECKS
704
705
706 /* Return true if there is no users that can match the given host */
707
acl_check_host(const char * host,const char * ip)708 bool acl_check_host(const char *host, const char *ip)
709 {
710 mysql_mutex_lock(&acl_cache->lock);
711 if (allow_all_hosts)
712 {
713
714 mysql_mutex_unlock(&acl_cache->lock);
715 return 0;
716 }
717
718 if ((host && my_hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) ||
719 (ip && my_hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip))))
720 {
721 mysql_mutex_unlock(&acl_cache->lock);
722 return 0; // Found host
723 }
724 for (ACL_HOST_AND_IP *acl= acl_wild_hosts->begin();
725 acl != acl_wild_hosts->end(); ++acl)
726 {
727 if (acl->compare_hostname(host, ip))
728 {
729 mysql_mutex_unlock(&acl_cache->lock);
730 return 0; // Host ok
731 }
732 }
733 mysql_mutex_unlock(&acl_cache->lock);
734 if (ip != NULL)
735 {
736 /* Increment HOST_CACHE.COUNT_HOST_ACL_ERRORS. */
737 Host_errors errors;
738 errors.m_host_acl= 1;
739 inc_host_errors(ip, &errors);
740 }
741 return 1; // Host is not allowed
742 }
743
744
745 /**
746 When authentication is attempted using an unknown username a dummy user
747 account with no authentication capabilites is assigned to the connection.
748 This is done increase the cost of enumerating user accounts based on
749 authentication protocol.
750 */
751
decoy_user(const LEX_STRING & username,MEM_ROOT * mem)752 ACL_USER *decoy_user(const LEX_STRING &username,
753 MEM_ROOT *mem)
754 {
755 ACL_USER *user= (ACL_USER *) alloc_root(mem, sizeof(ACL_USER));
756 user->can_authenticate= false;
757 user->user= strdup_root(mem, username.str);
758 user->user[username.length]= '\0';
759 user->auth_string= empty_lex_str;
760 user->ssl_cipher= empty_c_string;
761 user->x509_issuer= empty_c_string;
762 user->x509_subject= empty_c_string;
763 user->salt_len= 0;
764 user->password_last_changed.time_type= MYSQL_TIMESTAMP_ERROR;
765 user->password_lifetime= 0;
766 user->use_default_password_lifetime= true;
767 user->account_locked= false;
768
769 /*
770 For now the common default account is used. Improvements might involve
771 mapping a consistent hash of a username to a range of plugins.
772 */
773 user->plugin= default_auth_plugin_name;
774 return user;
775 }
776
777
778 /**
779 Finds acl entry in user database for authentication purposes.
780
781 Finds a user and copies it into mpvio. Reports an authentication
782 failure if a user is not found.
783
784 @note find_acl_user is not the same, because it doesn't take into
785 account the case when user is not empty, but acl_user->user is empty
786
787 @retval 0 found
788 @retval 1 not found
789 */
find_mpvio_user(MPVIO_EXT * mpvio)790 static bool find_mpvio_user(MPVIO_EXT *mpvio)
791 {
792 DBUG_ENTER("find_mpvio_user");
793 DBUG_PRINT("info", ("entry: %s", mpvio->auth_info.user_name));
794 assert(mpvio->acl_user == 0);
795 mysql_mutex_lock(&acl_cache->lock);
796 for (ACL_USER *acl_user_tmp= acl_users->begin();
797 acl_user_tmp != acl_users->end(); ++acl_user_tmp)
798 {
799 if ((!acl_user_tmp->user ||
800 !strcmp(mpvio->auth_info.user_name, acl_user_tmp->user)) &&
801 acl_user_tmp->host.compare_hostname(mpvio->host, mpvio->ip))
802 {
803 mpvio->acl_user= acl_user_tmp->copy(mpvio->mem_root);
804
805 /*
806 When setting mpvio->acl_user_plugin we can save memory allocation if
807 this is a built in plugin.
808 */
809 if (auth_plugin_is_built_in(acl_user_tmp->plugin.str))
810 mpvio->acl_user_plugin= mpvio->acl_user->plugin;
811 else
812 make_lex_string_root(mpvio->mem_root,
813 &mpvio->acl_user_plugin,
814 acl_user_tmp->plugin.str,
815 acl_user_tmp->plugin.length, 0);
816 break;
817 }
818 }
819 mysql_mutex_unlock(&acl_cache->lock);
820
821 if (!mpvio->acl_user)
822 {
823 /*
824 Pretend the user exists; let the plugin decide how to handle
825 bad credentials.
826 */
827 LEX_STRING usr= { mpvio->auth_info.user_name,
828 mpvio->auth_info.user_name_length };
829 mpvio->acl_user= decoy_user(usr, mpvio->mem_root);
830 mpvio->acl_user_plugin= mpvio->acl_user->plugin;
831 }
832
833 if (my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
834 native_password_plugin_name.str) != 0 &&
835 !(mpvio->protocol->has_client_capability(CLIENT_PLUGIN_AUTH)))
836 {
837 /* user account requires non-default plugin and the client is too old */
838 assert(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
839 native_password_plugin_name.str));
840 my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
841 query_logger.general_log_print(current_thd, COM_CONNECT,
842 ER(ER_NOT_SUPPORTED_AUTH_MODE));
843 DBUG_RETURN (1);
844 }
845
846 mpvio->auth_info.auth_string= mpvio->acl_user->auth_string.str;
847 mpvio->auth_info.auth_string_length=
848 (unsigned long) mpvio->acl_user->auth_string.length;
849 strmake(mpvio->auth_info.authenticated_as, mpvio->acl_user->user ?
850 mpvio->acl_user->user : "", USERNAME_LENGTH);
851 DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s"
852 ", plugin=%s",
853 mpvio->auth_info.user_name,
854 mpvio->auth_info.auth_string,
855 mpvio->auth_info.authenticated_as,
856 mpvio->acl_user->plugin.str));
857 DBUG_RETURN(0);
858 }
859
860
861 static bool
read_client_connect_attrs(char ** ptr,size_t * max_bytes_available,const CHARSET_INFO * from_cs)862 read_client_connect_attrs(char **ptr, size_t *max_bytes_available,
863 const CHARSET_INFO *from_cs)
864 {
865 size_t length, length_length;
866 char *ptr_save;
867 /* not enough bytes to hold the length */
868 if (*max_bytes_available < 1)
869 return true;
870
871 /* read the length */
872 ptr_save= *ptr;
873 length= static_cast<size_t>(net_field_length_ll((uchar **) ptr));
874 length_length= *ptr - ptr_save;
875 if (*max_bytes_available < length_length)
876 return true;
877
878 *max_bytes_available-= length_length;
879
880 /* length says there're more data than can fit into the packet */
881 if (length > *max_bytes_available)
882 return true;
883
884 /* impose an artificial length limit of 64k */
885 if (length > 65535)
886 return true;
887
888 #ifdef HAVE_PSI_THREAD_INTERFACE
889 if (PSI_THREAD_CALL(set_thread_connect_attrs)(*ptr, length, from_cs))
890 sql_print_warning("Connection attributes of length %lu were truncated",
891 (unsigned long) length);
892 #endif /* HAVE_PSI_THREAD_INTERFACE */
893 return false;
894 }
895
896
acl_check_ssl(THD * thd,const ACL_USER * acl_user)897 static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user)
898 {
899 #if defined(HAVE_OPENSSL)
900 Vio *vio= thd->get_protocol_classic()->get_vio();
901 SSL *ssl= (SSL*) vio->ssl_arg;
902 X509 *cert;
903 #endif /* HAVE_OPENSSL */
904
905 /*
906 At this point we know that user is allowed to connect
907 from given host by given username/password pair. Now
908 we check if SSL is required, if user is using SSL and
909 if X509 certificate attributes are OK
910 */
911 switch (acl_user->ssl_type) {
912 case SSL_TYPE_NOT_SPECIFIED: // Impossible
913 case SSL_TYPE_NONE: // SSL is not required
914 return 0;
915 #if defined(HAVE_OPENSSL)
916 case SSL_TYPE_ANY: // Any kind of SSL is ok
917 return vio_type(vio) != VIO_TYPE_SSL;
918 case SSL_TYPE_X509: /* Client should have any valid certificate. */
919 /*
920 Connections with non-valid certificates are dropped already
921 in sslaccept() anyway, so we do not check validity here.
922
923 We need to check for absence of SSL because without SSL
924 we should reject connection.
925 */
926 if (vio_type(vio) == VIO_TYPE_SSL &&
927 SSL_get_verify_result(ssl) == X509_V_OK &&
928 (cert= SSL_get_peer_certificate(ssl)))
929 {
930 X509_free(cert);
931 return 0;
932 }
933 return 1;
934 case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
935 /* If a cipher name is specified, we compare it to actual cipher in use. */
936 if (vio_type(vio) != VIO_TYPE_SSL ||
937 SSL_get_verify_result(ssl) != X509_V_OK)
938 return 1;
939 if (acl_user->ssl_cipher)
940 {
941 DBUG_PRINT("info", ("comparing ciphers: '%s' and '%s'",
942 acl_user->ssl_cipher, SSL_get_cipher(ssl)));
943 if (strcmp(acl_user->ssl_cipher, SSL_get_cipher(ssl)))
944 {
945 sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'",
946 acl_user->ssl_cipher, SSL_get_cipher(ssl));
947 return 1;
948 }
949 }
950 /* Prepare certificate (if exists) */
951 if (!(cert= SSL_get_peer_certificate(ssl)))
952 return 1;
953 /* If X509 issuer is specified, we check it... */
954 if (acl_user->x509_issuer)
955 {
956 char *ptr= X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
957 DBUG_PRINT("info", ("comparing issuers: '%s' and '%s'",
958 acl_user->x509_issuer, ptr));
959 if (strcmp(acl_user->x509_issuer, ptr))
960 {
961 sql_print_information("X509 issuer mismatch: should be '%s' "
962 "but is '%s'", acl_user->x509_issuer, ptr);
963 OPENSSL_free(ptr);
964 X509_free(cert);
965 return 1;
966 }
967 OPENSSL_free(ptr);
968 }
969 /* X509 subject is specified, we check it .. */
970 if (acl_user->x509_subject)
971 {
972 char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
973 DBUG_PRINT("info", ("comparing subjects: '%s' and '%s'",
974 acl_user->x509_subject, ptr));
975 if (strcmp(acl_user->x509_subject, ptr))
976 {
977 sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
978 acl_user->x509_subject, ptr);
979 OPENSSL_free(ptr);
980 X509_free(cert);
981 return 1;
982 }
983 OPENSSL_free(ptr);
984 }
985 X509_free(cert);
986 return 0;
987 #else /* HAVE_OPENSSL */
988 default:
989 /*
990 If we don't have SSL but SSL is required for this user the
991 authentication should fail.
992 */
993 return 1;
994 #endif /* HAVE_OPENSSL */
995 }
996 return 1;
997 }
998
999
1000 /**
1001
1002 Check if server has valid public key/private key
1003 pair for RSA communication.
1004
1005 @return
1006 @retval false RSA support is available
1007 @retval true RSA support is not available
1008 */
rsa_auth_status()1009 bool rsa_auth_status()
1010 {
1011 #if !defined(HAVE_OPENSSL)
1012 return false;
1013 #else
1014 return (!g_rsa_keys.get_private_key() || !g_rsa_keys.get_public_key());
1015 #endif /* !HAVE_OPENSSL */
1016 }
1017
1018
1019 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
1020
1021
1022 /* the packet format is described in send_change_user_packet() */
parse_com_change_user_packet(MPVIO_EXT * mpvio,size_t packet_length)1023 static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, size_t packet_length)
1024 {
1025 Protocol_classic *protocol = mpvio->protocol;
1026 char *user= (char*) protocol->get_net()->read_pos;
1027 char *end= user + packet_length;
1028 /* Safe because there is always a trailing \0 at the end of the packet */
1029 char *passwd= strend(user) + 1;
1030 size_t user_len= passwd - user - 1;
1031 char *db= passwd;
1032 char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
1033 char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
1034 uint dummy_errors;
1035
1036 DBUG_ENTER ("parse_com_change_user_packet");
1037 if (passwd >= end)
1038 {
1039 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1040 DBUG_RETURN (1);
1041 }
1042
1043 /*
1044 Clients send the size (1 byte) + string (not null-terminated).
1045
1046 Cast *passwd to an unsigned char, so that it doesn't extend the sign for
1047 *passwd > 127 and become 2**32-127+ after casting to uint.
1048 */
1049 size_t passwd_len= (uchar) (*passwd++);
1050
1051 db+= passwd_len + 1;
1052 /*
1053 Database name is always NUL-terminated, so in case of empty database
1054 the packet must contain at least the trailing '\0'.
1055 */
1056 if (db >= end)
1057 {
1058 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1059 DBUG_RETURN (1);
1060 }
1061
1062 size_t db_len= strlen(db);
1063
1064 char *ptr= db + db_len + 1;
1065
1066 if (ptr + 1 < end)
1067 {
1068 if (mpvio->charset_adapter->init_client_charset(uint2korr(ptr)))
1069 DBUG_RETURN(1);
1070 // skip over the charset's 2 bytes
1071 ptr += 2;
1072 }
1073
1074 /* Convert database and user names to utf8 */
1075 db_len= copy_and_convert(db_buff, sizeof(db_buff) - 1, system_charset_info,
1076 db, db_len, mpvio->charset_adapter->charset(),
1077 &dummy_errors);
1078 db_buff[db_len]= 0;
1079
1080 user_len= copy_and_convert(user_buff, sizeof(user_buff) - 1,
1081 system_charset_info, user, user_len,
1082 mpvio->charset_adapter->charset(),
1083 &dummy_errors);
1084 user_buff[user_len]= 0;
1085
1086 /* we should not free mpvio->user here: it's saved by dispatch_command() */
1087 if (!(mpvio->auth_info.user_name= my_strndup(key_memory_MPVIO_EXT_auth_info,
1088 user_buff, user_len, MYF(MY_WME))))
1089 DBUG_RETURN(1);
1090 mpvio->auth_info.user_name_length= user_len;
1091
1092 if (make_lex_string_root(mpvio->mem_root,
1093 &mpvio->db, db_buff, db_len, 0) == 0)
1094 DBUG_RETURN(1); /* The error is set by make_lex_string(). */
1095
1096 if (!initialized)
1097 {
1098 // if mysqld's been started with --skip-grant-tables option
1099 strmake(mpvio->auth_info.authenticated_as,
1100 mpvio->auth_info.user_name, USERNAME_LENGTH);
1101
1102 mpvio->status= MPVIO_EXT::SUCCESS;
1103 DBUG_RETURN(0);
1104 }
1105
1106 #ifndef NO_EMBEDDED_ACCESS_CHECKS
1107 if (find_mpvio_user(mpvio))
1108 {
1109 DBUG_RETURN(1);
1110 }
1111
1112 const char *client_plugin;
1113 if (protocol->has_client_capability(CLIENT_PLUGIN_AUTH))
1114 {
1115 client_plugin= ptr;
1116 if (client_plugin >= end)
1117 {
1118 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1119 DBUG_RETURN(1);
1120 }
1121 // Skip over the client plugin
1122 ptr += strlen(client_plugin) + 1;
1123
1124 }
1125 else
1126 client_plugin= native_password_plugin_name.str;
1127
1128 if (ptr > end)
1129 {
1130 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1131 DBUG_RETURN (1);
1132 }
1133 size_t bytes_remaining_in_packet= end - ptr;
1134
1135 if (protocol->has_client_capability(CLIENT_CONNECT_ATTRS) &&
1136 read_client_connect_attrs(&ptr, &bytes_remaining_in_packet,
1137 mpvio->charset_adapter->charset()))
1138 DBUG_RETURN(MY_TEST(packet_error));
1139
1140 DBUG_PRINT("info", ("client_plugin=%s, restart", client_plugin));
1141 /*
1142 Remember the data part of the packet, to present it to plugin in
1143 read_packet()
1144 */
1145 mpvio->cached_client_reply.pkt= passwd;
1146 mpvio->cached_client_reply.pkt_len= passwd_len;
1147 mpvio->cached_client_reply.plugin= client_plugin;
1148 mpvio->status= MPVIO_EXT::RESTART;
1149 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
1150
1151 DBUG_RETURN (0);
1152 }
1153
1154
1155 #ifndef EMBEDDED_LIBRARY
1156
1157 /** Get a string according to the protocol of the underlying buffer. */
1158 typedef char * (*get_proto_string_func_t) (char **, size_t *, size_t *);
1159
1160 /**
1161 Get a string formatted according to the 4.1 version of the MySQL protocol.
1162
1163 @param buffer[in, out] Pointer to the user-supplied buffer to be scanned.
1164 @param max_bytes_available[in, out] Limit the bytes to scan.
1165 @param string_length[out] The number of characters scanned not including
1166 the null character.
1167
1168 @remark Strings are always null character terminated in this version of the
1169 protocol.
1170
1171 @remark The string_length does not include the terminating null character.
1172 However, after the call, the buffer is increased by string_length+1
1173 bytes, beyond the null character if there still available bytes to
1174 scan.
1175
1176 @return pointer to beginning of the string scanned.
1177 @retval NULL The buffer content is malformed
1178 */
1179
1180 static
get_41_protocol_string(char ** buffer,size_t * max_bytes_available,size_t * string_length)1181 char *get_41_protocol_string(char **buffer,
1182 size_t *max_bytes_available,
1183 size_t *string_length)
1184 {
1185 char *str= (char *)memchr(*buffer, '\0', *max_bytes_available);
1186
1187 if (str == NULL)
1188 return NULL;
1189
1190 *string_length= (size_t)(str - *buffer);
1191 *max_bytes_available-= *string_length + 1;
1192 str= *buffer;
1193 *buffer += *string_length + 1;
1194
1195 return str;
1196 }
1197
1198
1199 /**
1200 Get a string formatted according to the 4.0 version of the MySQL protocol.
1201
1202 @param buffer[in, out] Pointer to the user-supplied buffer to be scanned.
1203 @param max_bytes_available[in, out] Limit the bytes to scan.
1204 @param string_length[out] The number of characters scanned not including
1205 the null character.
1206
1207 @remark If there are not enough bytes left after the current position of
1208 the buffer to satisfy the current string, the string is considered
1209 to be empty and a pointer to empty_c_string is returned.
1210
1211 @remark A string at the end of the packet is not null terminated.
1212
1213 @return Pointer to beginning of the string scanned, or a pointer to a empty
1214 string.
1215 */
1216 static
get_40_protocol_string(char ** buffer,size_t * max_bytes_available,size_t * string_length)1217 char *get_40_protocol_string(char **buffer,
1218 size_t *max_bytes_available,
1219 size_t *string_length)
1220 {
1221 char *str;
1222 size_t len;
1223
1224 /* No bytes to scan left, treat string as empty. */
1225 if ((*max_bytes_available) == 0)
1226 {
1227 *string_length= 0;
1228 return empty_c_string;
1229 }
1230
1231 str= (char *) memchr(*buffer, '\0', *max_bytes_available);
1232
1233 /*
1234 If the string was not null terminated by the client,
1235 the remainder of the packet is the string. Otherwise,
1236 advance the buffer past the end of the null terminated
1237 string.
1238 */
1239 if (str == NULL)
1240 len= *string_length= *max_bytes_available;
1241 else
1242 len= (*string_length= (size_t)(str - *buffer)) + 1;
1243
1244 str= *buffer;
1245 *buffer+= len;
1246 *max_bytes_available-= len;
1247
1248 return str;
1249 }
1250
1251 /**
1252 Get a length encoded string from a user-supplied buffer.
1253
1254 @param buffer[in, out] The buffer to scan; updates position after scan.
1255 @param max_bytes_available[in, out] Limit the number of bytes to scan
1256 @param string_length[out] Number of characters scanned
1257
1258 @remark In case the length is zero, then the total size of the string is
1259 considered to be 1 byte; the size byte.
1260
1261 @return pointer to first byte after the header in buffer.
1262 @retval NULL The buffer content is malformed
1263 */
1264
1265 static
get_56_lenc_string(char ** buffer,size_t * max_bytes_available,size_t * string_length)1266 char *get_56_lenc_string(char **buffer,
1267 size_t *max_bytes_available,
1268 size_t *string_length)
1269 {
1270 static char empty_string[1]= { '\0' };
1271 char *begin= *buffer;
1272 uchar *pos= (uchar *)begin;
1273 size_t required_length= 9;
1274
1275
1276 if (*max_bytes_available == 0)
1277 return NULL;
1278
1279 /*
1280 If the length encoded string has the length 0
1281 the total size of the string is only one byte long (the size byte)
1282 */
1283 if (*begin == 0)
1284 {
1285 *string_length= 0;
1286 --*max_bytes_available;
1287 ++*buffer;
1288 /*
1289 Return a pointer to the \0 character so the return value will be
1290 an empty string.
1291 */
1292 return empty_string;
1293 }
1294
1295 /* Make sure we have enough bytes available for net_field_length_ll */
1296 DBUG_EXECUTE_IF("buffer_too_short_3",
1297 *pos= 252; *max_bytes_available= 2;
1298 );
1299 DBUG_EXECUTE_IF("buffer_too_short_4",
1300 *pos= 253; *max_bytes_available= 3;
1301 );
1302 DBUG_EXECUTE_IF("buffer_too_short_9",
1303 *pos= 254; *max_bytes_available= 8;
1304 );
1305
1306 if (*pos <= 251)
1307 required_length= 1;
1308 if (*pos == 252)
1309 required_length= 3;
1310 if (*pos == 253)
1311 required_length= 4;
1312
1313 if (*max_bytes_available < required_length)
1314 return NULL;
1315
1316 *string_length= (size_t)net_field_length_ll((uchar **)buffer);
1317
1318 DBUG_EXECUTE_IF("sha256_password_scramble_too_long",
1319 *string_length= SIZE_T_MAX;
1320 );
1321
1322 size_t len_len= (size_t)(*buffer - begin);
1323
1324 assert((*max_bytes_available >= len_len) &&
1325 (len_len == required_length));
1326
1327 if (*string_length > *max_bytes_available - len_len)
1328 return NULL;
1329
1330 *max_bytes_available -= *string_length;
1331 *max_bytes_available -= len_len;
1332 *buffer += *string_length;
1333 return (char *)(begin + len_len);
1334 }
1335
1336
1337 /**
1338 Get a length encoded string from a user-supplied buffer.
1339
1340 @param buffer[in, out] The buffer to scan; updates position after scan.
1341 @param max_bytes_available[in, out] Limit the number of bytes to scan
1342 @param string_length[out] Number of characters scanned
1343
1344 @remark In case the length is zero, then the total size of the string is
1345 considered to be 1 byte; the size byte.
1346
1347 @note the maximum size of the string is 255 because the header is always
1348 1 byte.
1349 @return pointer to first byte after the header in buffer.
1350 @retval NULL The buffer content is malformed
1351 */
1352
1353 static
get_41_lenc_string(char ** buffer,size_t * max_bytes_available,size_t * string_length)1354 char *get_41_lenc_string(char **buffer,
1355 size_t *max_bytes_available,
1356 size_t *string_length)
1357 {
1358 if (*max_bytes_available == 0)
1359 return NULL;
1360
1361 /* Do double cast to prevent overflow from signed / unsigned conversion */
1362 size_t str_len= (size_t)(unsigned char)**buffer;
1363
1364 /*
1365 If the length encoded string has the length 0
1366 the total size of the string is only one byte long (the size byte)
1367 */
1368 if (str_len == 0)
1369 {
1370 ++*buffer;
1371 *string_length= 0;
1372 /*
1373 Return a pointer to the 0 character so the return value will be
1374 an empty string.
1375 */
1376 return *buffer-1;
1377 }
1378
1379 if (str_len >= *max_bytes_available)
1380 return NULL;
1381
1382 char *str= *buffer+1;
1383 *string_length= str_len;
1384 *max_bytes_available-= *string_length + 1;
1385 *buffer+= *string_length + 1;
1386 return str;
1387 }
1388 #endif /* EMBEDDED LIBRARY */
1389
1390
1391 /* the packet format is described in send_client_reply_packet() */
parse_client_handshake_packet(MPVIO_EXT * mpvio,uchar ** buff,size_t pkt_len)1392 static size_t parse_client_handshake_packet(MPVIO_EXT *mpvio,
1393 uchar **buff, size_t pkt_len)
1394 {
1395 #ifndef EMBEDDED_LIBRARY
1396 Protocol_classic *protocol = mpvio->protocol;
1397 char *end;
1398 bool packet_has_required_size= false;
1399 assert(mpvio->status == MPVIO_EXT::FAILURE);
1400
1401 uint charset_code= 0;
1402 end= (char *)protocol->get_net()->read_pos;
1403 /*
1404 In order to safely scan a head for '\0' string terminators
1405 we must keep track of how many bytes remain in the allocated
1406 buffer or we might read past the end of the buffer.
1407 */
1408 size_t bytes_remaining_in_packet= pkt_len;
1409
1410 /*
1411 Peek ahead on the client capability packet and determine which version of
1412 the protocol should be used.
1413 */
1414 if (bytes_remaining_in_packet < 2)
1415 return packet_error;
1416
1417 protocol->set_client_capabilities(uint2korr(end));
1418
1419 /*
1420 JConnector only sends server capabilities before starting SSL
1421 negotiation. The below code is patch for this.
1422 */
1423 if (bytes_remaining_in_packet == 4 &&
1424 protocol->has_client_capability(CLIENT_SSL))
1425 {
1426 protocol->set_client_capabilities(uint4korr(end));
1427 mpvio->max_client_packet_length= 0xfffff;
1428 charset_code= global_system_variables.character_set_client->number;
1429 goto skip_to_ssl;
1430 }
1431
1432 if (protocol->has_client_capability(CLIENT_PROTOCOL_41))
1433 packet_has_required_size= bytes_remaining_in_packet >=
1434 AUTH_PACKET_HEADER_SIZE_PROTO_41;
1435 else
1436 packet_has_required_size= bytes_remaining_in_packet >=
1437 AUTH_PACKET_HEADER_SIZE_PROTO_40;
1438
1439 if (!packet_has_required_size)
1440 return packet_error;
1441
1442 if (protocol->has_client_capability(CLIENT_PROTOCOL_41))
1443 {
1444 protocol->set_client_capabilities(uint4korr(end));
1445 mpvio->max_client_packet_length= uint4korr(end + 4);
1446 charset_code= (uint)(uchar)*(end + 8);
1447 /*
1448 Skip 23 remaining filler bytes which have no particular meaning.
1449 */
1450 end+= AUTH_PACKET_HEADER_SIZE_PROTO_41;
1451 bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_PROTO_41;
1452 }
1453 else
1454 {
1455 protocol->set_client_capabilities(uint2korr(end));
1456 mpvio->max_client_packet_length= uint3korr(end + 2);
1457 end+= AUTH_PACKET_HEADER_SIZE_PROTO_40;
1458 bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_PROTO_40;
1459 /**
1460 Old clients didn't have their own charset. Instead the assumption
1461 was that they used what ever the server used.
1462 */
1463 charset_code= global_system_variables.character_set_client->number;
1464 }
1465
1466 skip_to_ssl:
1467 #if defined(HAVE_OPENSSL)
1468 DBUG_PRINT("info", ("client capabilities: %lu",
1469 protocol->get_client_capabilities()));
1470
1471 /*
1472 If client requested SSL then we must stop parsing, try to switch to SSL,
1473 and wait for the client to send a new handshake packet.
1474 The client isn't expected to send any more bytes until SSL is initialized.
1475 */
1476 if (protocol->has_client_capability(CLIENT_SSL))
1477 {
1478 unsigned long errptr;
1479 #if !defined(NDEBUG)
1480 uint ssl_charset_code= 0;
1481 #endif
1482
1483 /* Do the SSL layering. */
1484 if (!ssl_acceptor_fd)
1485 return packet_error;
1486
1487 DBUG_PRINT("info", ("IO layer change in progress..."));
1488 if (sslaccept(ssl_acceptor_fd, protocol->get_vio(),
1489 protocol->get_net()->read_timeout, &errptr))
1490 {
1491 DBUG_PRINT("error", ("Failed to accept new SSL connection"));
1492 return packet_error;
1493 }
1494
1495 DBUG_PRINT("info", ("Reading user information over SSL layer"));
1496 int rc= protocol->read_packet();
1497 pkt_len= protocol->get_packet_length();
1498 if (rc)
1499 {
1500 DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
1501 static_cast<ulong>(pkt_len)));
1502 return packet_error;
1503 }
1504 /* mark vio as encrypted */
1505 mpvio->vio_is_encrypted= 1;
1506
1507 /*
1508 A new packet was read and the statistics reflecting the remaining bytes
1509 in the packet must be updated.
1510 */
1511 bytes_remaining_in_packet= pkt_len;
1512
1513 /*
1514 After the SSL handshake is performed the client resends the handshake
1515 packet but because of legacy reasons we chose not to parse the packet
1516 fields a second time and instead only assert the length of the packet.
1517 */
1518 if (protocol->has_client_capability(CLIENT_PROTOCOL_41))
1519 {
1520 packet_has_required_size= bytes_remaining_in_packet >=
1521 AUTH_PACKET_HEADER_SIZE_PROTO_41;
1522 #if !defined(NDEBUG)
1523 ssl_charset_code=
1524 (uint)(uchar)*((char *)protocol->get_net()->read_pos + 8);
1525 DBUG_PRINT("info", ("client_character_set: %u", ssl_charset_code));
1526 #endif
1527 end= (char *)protocol->get_net()->read_pos
1528 + AUTH_PACKET_HEADER_SIZE_PROTO_41;
1529 bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_41;
1530 }
1531 else
1532 {
1533 packet_has_required_size= bytes_remaining_in_packet >=
1534 AUTH_PACKET_HEADER_SIZE_PROTO_40;
1535 end= (char *)protocol->get_net()->read_pos
1536 + AUTH_PACKET_HEADER_SIZE_PROTO_40;
1537 bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40;
1538 #if !defined(NDEBUG)
1539 /**
1540 Old clients didn't have their own charset. Instead the assumption
1541 was that they used what ever the server used.
1542 */
1543 ssl_charset_code= global_system_variables.character_set_client->number;
1544 #endif
1545 }
1546 assert(charset_code == ssl_charset_code);
1547 if (!packet_has_required_size)
1548 return packet_error;
1549 }
1550 #endif /* HAVE_OPENSSL */
1551
1552 DBUG_PRINT("info", ("client_character_set: %u", charset_code));
1553 if (mpvio->charset_adapter->init_client_charset(charset_code))
1554 return packet_error;
1555
1556 if ((protocol->has_client_capability(CLIENT_TRANSACTIONS)) &&
1557 opt_using_transactions)
1558 protocol->get_net()->return_status= mpvio->server_status;
1559
1560 /*
1561 The 4.0 and 4.1 versions of the protocol differ on how strings
1562 are terminated. In the 4.0 version, if a string is at the end
1563 of the packet, the string is not null terminated. Do not assume
1564 that the returned string is always null terminated.
1565 */
1566 get_proto_string_func_t get_string;
1567
1568 if (protocol->has_client_capability(CLIENT_PROTOCOL_41))
1569 get_string= get_41_protocol_string;
1570 else
1571 get_string= get_40_protocol_string;
1572
1573 /*
1574 When the ability to change default plugin require that the initial password
1575 field can be of arbitrary size. However, the 41 client-server protocol limits
1576 the length of the auth-data-field sent from client to server to 255 bytes
1577 (CLIENT_SECURE_CONNECTION). The solution is to change the type of the field
1578 to a true length encoded string and indicate the protocol change with a new
1579 client capability flag: CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA.
1580 */
1581 get_proto_string_func_t get_length_encoded_string;
1582
1583 if (protocol->has_client_capability(CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA))
1584 get_length_encoded_string= get_56_lenc_string;
1585 else
1586 get_length_encoded_string= get_41_lenc_string;
1587
1588 /*
1589 In order to safely scan a head for '\0' string terminators
1590 we must keep track of how many bytes remain in the allocated
1591 buffer or we might read past the end of the buffer.
1592 */
1593 bytes_remaining_in_packet=
1594 pkt_len - (end - (char *)protocol->get_net()->read_pos);
1595
1596 size_t user_len;
1597 char *user= get_string(&end, &bytes_remaining_in_packet, &user_len);
1598 if (user == NULL)
1599 return packet_error;
1600
1601 /*
1602 Old clients send a null-terminated string as password; new clients send
1603 the size (1 byte) + string (not null-terminated). Hence in case of empty
1604 password both send '\0'.
1605 */
1606 size_t passwd_len= 0;
1607 char *passwd= NULL;
1608
1609 passwd= get_length_encoded_string(&end, &bytes_remaining_in_packet,
1610 &passwd_len);
1611 if (passwd == NULL)
1612 return packet_error;
1613
1614 size_t db_len= 0;
1615 char *db= NULL;
1616
1617 if (protocol->has_client_capability(CLIENT_CONNECT_WITH_DB))
1618 {
1619 db= get_string(&end, &bytes_remaining_in_packet, &db_len);
1620 if (db == NULL)
1621 return packet_error;
1622 }
1623
1624 /*
1625 Set the default for the password supplied flag for non-existing users
1626 as the default plugin (native passsword authentication) would do it
1627 for compatibility reasons.
1628 */
1629 if (passwd_len)
1630 mpvio->auth_info.password_used= PASSWORD_USED_YES;
1631
1632 size_t client_plugin_len= 0;
1633 const char *client_plugin= get_string(&end, &bytes_remaining_in_packet,
1634 &client_plugin_len);
1635 if (client_plugin == NULL)
1636 client_plugin= &empty_c_string[0];
1637
1638 if ((protocol->has_client_capability(CLIENT_CONNECT_ATTRS)) &&
1639 read_client_connect_attrs(&end, &bytes_remaining_in_packet,
1640 mpvio->charset_adapter->charset()))
1641 return packet_error;
1642
1643 char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
1644 char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
1645 uint dummy_errors;
1646
1647
1648 /*
1649 Copy and convert the user and database names to the character set used
1650 by the server. Since 4.1 all database names are stored in UTF-8. Also,
1651 ensure that the names are properly null-terminated as this is relied
1652 upon later.
1653 */
1654 if (db)
1655 {
1656 db_len= copy_and_convert(db_buff, sizeof(db_buff) - 1, system_charset_info,
1657 db, db_len, mpvio->charset_adapter->charset(),
1658 &dummy_errors);
1659 db_buff[db_len]= '\0';
1660 db= db_buff;
1661 }
1662
1663 user_len= copy_and_convert(user_buff, sizeof(user_buff) - 1,
1664 system_charset_info, user, user_len,
1665 mpvio->charset_adapter->charset(),
1666 &dummy_errors);
1667 user_buff[user_len]= '\0';
1668 user= user_buff;
1669
1670 /* If username starts and ends in "'", chop them off */
1671 if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
1672 {
1673 user[user_len - 1]= 0;
1674 user++;
1675 user_len-= 2;
1676 }
1677
1678 if (make_lex_string_root(mpvio->mem_root,
1679 &mpvio->db, db, db_len, 0) == 0)
1680 return packet_error; /* The error is set by make_lex_string(). */
1681 if (mpvio->auth_info.user_name)
1682 my_free(mpvio->auth_info.user_name);
1683 if (!(mpvio->auth_info.user_name= my_strndup(key_memory_MPVIO_EXT_auth_info,
1684 user, user_len, MYF(MY_WME))))
1685 return packet_error; /* The error is set by my_strdup(). */
1686 mpvio->auth_info.user_name_length= user_len;
1687
1688 if (!initialized)
1689 {
1690 // if mysqld's been started with --skip-grant-tables option
1691 mpvio->status= MPVIO_EXT::SUCCESS;
1692 return packet_error;
1693 }
1694
1695 if (find_mpvio_user(mpvio))
1696 return packet_error;
1697
1698 if (!(protocol->has_client_capability(CLIENT_PLUGIN_AUTH)))
1699 {
1700 /* An old client is connecting */
1701 client_plugin= native_password_plugin_name.str;
1702 }
1703
1704 /*
1705 if the acl_user needs a different plugin to authenticate
1706 (specified in GRANT ... AUTHENTICATED VIA plugin_name ..)
1707 we need to restart the authentication in the server.
1708 But perhaps the client has already used the correct plugin -
1709 in that case the authentication on the client may not need to be
1710 restarted and a server auth plugin will read the data that the client
1711 has just send. Cache them to return in the next server_mpvio_read_packet().
1712 */
1713 if (my_strcasecmp(system_charset_info, mpvio->acl_user_plugin.str,
1714 plugin_name(mpvio->plugin)->str) != 0)
1715 {
1716 mpvio->cached_client_reply.pkt= passwd;
1717 mpvio->cached_client_reply.pkt_len= passwd_len;
1718 mpvio->cached_client_reply.plugin= client_plugin;
1719 mpvio->status= MPVIO_EXT::RESTART;
1720 return packet_error;
1721 }
1722
1723 /*
1724 ok, we don't need to restart the authentication on the server.
1725 but if the client used the wrong plugin, we need to restart
1726 the authentication on the client. Do it here, the server plugin
1727 doesn't need to know.
1728 */
1729 const char *client_auth_plugin=
1730 ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
1731
1732 if (client_auth_plugin &&
1733 my_strcasecmp(system_charset_info, client_plugin, client_auth_plugin))
1734 {
1735 mpvio->cached_client_reply.plugin= client_plugin;
1736 if (send_plugin_request_packet(mpvio,
1737 (uchar*) mpvio->cached_server_packet.pkt,
1738 mpvio->cached_server_packet.pkt_len))
1739 return packet_error;
1740
1741 mpvio->protocol->read_packet();
1742 passwd_len= protocol->get_packet_length();
1743 passwd= (char *)protocol->get_net()->read_pos;
1744 }
1745
1746 *buff= (uchar *) passwd;
1747 return passwd_len;
1748 #else
1749 return 0;
1750 #endif /* EMBEDDED_LIBRARY */
1751 }
1752
1753
1754 /**
1755 Make sure that when sending plugin supplied data to the client they
1756 are not considered a special out-of-band command, like e.g.
1757 \255 (error) or \254 (change user request packet) or \0 (OK).
1758 To avoid this the server will send all plugin data packets "wrapped"
1759 in a command \1.
1760 Note that the client will continue sending its replies unrwapped.
1761 */
1762
1763 static inline int
wrap_plguin_data_into_proper_command(NET * net,const uchar * packet,int packet_len)1764 wrap_plguin_data_into_proper_command(NET *net,
1765 const uchar *packet, int packet_len)
1766 {
1767 return net_write_command(net, 1, (uchar *) "", 0, packet, packet_len);
1768 }
1769
1770 /*
1771 Note: The following functions are declared inside extern "C" because
1772 they are used to initialize C structure MPVIO (see
1773 server_mpvio_initialize()).
1774 */
1775
1776 extern "C" {
1777
1778 /**
1779 vio->write_packet() callback method for server authentication plugins
1780
1781 This function is called by a server authentication plugin, when it wants
1782 to send data to the client.
1783
1784 It transparently wraps the data into a handshake packet,
1785 and handles plugin negotiation with the client. If necessary,
1786 it escapes the plugin data, if it starts with a mysql protocol packet byte.
1787 */
server_mpvio_write_packet(MYSQL_PLUGIN_VIO * param,const uchar * packet,int packet_len)1788 static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
1789 const uchar *packet, int packet_len)
1790 {
1791 MPVIO_EXT *mpvio= (MPVIO_EXT *) param;
1792 int res;
1793 Protocol_classic *protocol = mpvio->protocol;
1794
1795 DBUG_ENTER("server_mpvio_write_packet");
1796 /*
1797 Reset cached_client_reply if not an old client doing mysql_change_user,
1798 as this is where the password from COM_CHANGE_USER is stored.
1799 */
1800 if (!((!(protocol->has_client_capability(CLIENT_PLUGIN_AUTH))) &&
1801 mpvio->status == MPVIO_EXT::RESTART &&
1802 mpvio->cached_client_reply.plugin ==
1803 ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin
1804 ))
1805 mpvio->cached_client_reply.pkt= 0;
1806 /* for the 1st packet we wrap plugin data into the handshake packet */
1807 if (mpvio->packets_written == 0)
1808 res= send_server_handshake_packet(mpvio, (char*) packet, packet_len);
1809 else if (mpvio->status == MPVIO_EXT::RESTART)
1810 res= send_plugin_request_packet(mpvio, packet, packet_len);
1811 else
1812 res= wrap_plguin_data_into_proper_command(protocol->get_net(),
1813 packet, packet_len);
1814 mpvio->packets_written++;
1815 DBUG_RETURN(res);
1816 }
1817
1818 /**
1819 vio->read_packet() callback method for server authentication plugins
1820
1821 This function is called by a server authentication plugin, when it wants
1822 to read data from the client.
1823
1824 It transparently extracts the client plugin data, if embedded into
1825 a client authentication handshake packet, and handles plugin negotiation
1826 with the client, if necessary.
1827
1828 RETURN
1829 -1 Protocol failure
1830 >= 0 Success and also the packet length
1831 */
server_mpvio_read_packet(MYSQL_PLUGIN_VIO * param,uchar ** buf)1832 static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
1833 {
1834 MPVIO_EXT *mpvio= (MPVIO_EXT *) param;
1835 Protocol_classic *protocol = mpvio->protocol;
1836 size_t pkt_len;
1837
1838 DBUG_ENTER("server_mpvio_read_packet");
1839 if (mpvio->packets_written == 0)
1840 {
1841 /*
1842 plugin wants to read the data without sending anything first.
1843 send an empty packet to force a server handshake packet to be sent
1844 */
1845 if (mpvio->write_packet(mpvio, 0, 0))
1846 pkt_len= packet_error;
1847 else
1848 {
1849 protocol->read_packet();
1850 pkt_len= protocol->get_packet_length();
1851 }
1852 }
1853 else if (mpvio->cached_client_reply.pkt)
1854 {
1855 assert(mpvio->status == MPVIO_EXT::RESTART);
1856 assert(mpvio->packets_read > 0);
1857 /*
1858 if the have the data cached from the last server_mpvio_read_packet
1859 (which can be the case if it's a restarted authentication)
1860 and a client has used the correct plugin, then we can return the
1861 cached data straight away and avoid one round trip.
1862 */
1863 const char *client_auth_plugin=
1864 ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
1865 if (client_auth_plugin == 0 ||
1866 my_strcasecmp(system_charset_info, mpvio->cached_client_reply.plugin,
1867 client_auth_plugin) == 0)
1868 {
1869 mpvio->status= MPVIO_EXT::FAILURE;
1870 *buf= (uchar*) mpvio->cached_client_reply.pkt;
1871 mpvio->cached_client_reply.pkt= 0;
1872 mpvio->packets_read++;
1873 DBUG_RETURN ((int) mpvio->cached_client_reply.pkt_len);
1874 }
1875
1876 /* older clients don't support change of client plugin request */
1877 if (!(protocol->has_client_capability(CLIENT_PLUGIN_AUTH)))
1878 {
1879 mpvio->status= MPVIO_EXT::FAILURE;
1880 pkt_len= packet_error;
1881 goto err;
1882 }
1883
1884 /*
1885 But if the client has used the wrong plugin, the cached data are
1886 useless. Furthermore, we have to send a "change plugin" request
1887 to the client.
1888 */
1889 if (mpvio->write_packet(mpvio, 0, 0))
1890 pkt_len= packet_error;
1891 else
1892 {
1893 protocol->read_packet();
1894 pkt_len= protocol->get_packet_length();
1895 }
1896 }
1897 else
1898 {
1899 protocol->read_packet();
1900 pkt_len= protocol->get_packet_length();
1901 }
1902 DBUG_EXECUTE_IF("simulate_packet_error", pkt_len = packet_error;);
1903 if (pkt_len == packet_error)
1904 goto err;
1905
1906 mpvio->packets_read++;
1907
1908 /*
1909 the 1st packet has the plugin data wrapped into the client authentication
1910 handshake packet
1911 */
1912 if (mpvio->packets_read == 1)
1913 {
1914 pkt_len= parse_client_handshake_packet(mpvio, buf, pkt_len);
1915 if (pkt_len == packet_error)
1916 goto err;
1917 }
1918 else
1919 *buf= protocol->get_net()->read_pos;
1920
1921 DBUG_RETURN((int)pkt_len);
1922
1923 err:
1924 if (mpvio->status == MPVIO_EXT::FAILURE)
1925 {
1926 my_error(ER_HANDSHAKE_ERROR, MYF(0));
1927 }
1928 DBUG_RETURN(-1);
1929 }
1930
1931 /**
1932 fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
1933 connection
1934 */
server_mpvio_info(MYSQL_PLUGIN_VIO * vio,MYSQL_PLUGIN_VIO_INFO * info)1935 static void server_mpvio_info(MYSQL_PLUGIN_VIO *vio,
1936 MYSQL_PLUGIN_VIO_INFO *info)
1937 {
1938 MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
1939 mpvio_info(mpvio->protocol->get_net()->vio, info);
1940 }
1941
1942 } // extern "C"
1943
do_auth_once(THD * thd,const LEX_CSTRING & auth_plugin_name,MPVIO_EXT * mpvio)1944 static int do_auth_once(THD *thd, const LEX_CSTRING &auth_plugin_name,
1945 MPVIO_EXT *mpvio)
1946 {
1947 DBUG_ENTER("do_auth_once");
1948 int res= CR_OK, old_status= MPVIO_EXT::FAILURE;
1949 bool unlock_plugin= false;
1950 plugin_ref plugin= NULL;
1951
1952 if (auth_plugin_name.str == native_password_plugin_name.str)
1953 plugin= native_password_plugin;
1954 #ifndef EMBEDDED_LIBRARY
1955 else
1956 {
1957 if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
1958 MYSQL_AUTHENTICATION_PLUGIN)))
1959 unlock_plugin= true;
1960 }
1961 #endif /* EMBEDDED_LIBRARY */
1962
1963
1964 mpvio->plugin= plugin;
1965 old_status= mpvio->status;
1966
1967 if (plugin)
1968 {
1969 st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
1970 res= auth->authenticate_user(mpvio, &mpvio->auth_info);
1971
1972 if (unlock_plugin)
1973 plugin_unlock(thd, plugin);
1974 }
1975 else
1976 {
1977 /* Server cannot load the required plugin. */
1978 Host_errors errors;
1979 errors.m_no_auth_plugin= 1;
1980 inc_host_errors(mpvio->ip, &errors);
1981 my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), auth_plugin_name.str);
1982 res= CR_ERROR;
1983 }
1984
1985 /*
1986 If the status was MPVIO_EXT::RESTART before the authenticate_user() call
1987 it can never be MPVIO_EXT::RESTART after the call, because any call
1988 to write_packet() or read_packet() will reset the status.
1989
1990 But (!) if a plugin never called a read_packet() or write_packet(), the
1991 status will stay unchanged. We'll fix it, by resetting the status here.
1992 */
1993 if (old_status == MPVIO_EXT::RESTART && mpvio->status == MPVIO_EXT::RESTART)
1994 mpvio->status= MPVIO_EXT::FAILURE; // reset to the default
1995
1996 DBUG_RETURN(res);
1997 }
1998
1999
2000 static void
server_mpvio_initialize(THD * thd,MPVIO_EXT * mpvio,Thd_charset_adapter * charset_adapter)2001 server_mpvio_initialize(THD *thd, MPVIO_EXT *mpvio,
2002 Thd_charset_adapter *charset_adapter)
2003 {
2004 LEX_CSTRING sctx_host_or_ip= thd->security_context()->host_or_ip();
2005
2006 memset(mpvio, 0, sizeof(MPVIO_EXT));
2007 mpvio->read_packet= server_mpvio_read_packet;
2008 mpvio->write_packet= server_mpvio_write_packet;
2009 mpvio->info= server_mpvio_info;
2010 mpvio->auth_info.user_name= NULL;
2011 mpvio->auth_info.user_name_length= 0;
2012 mpvio->auth_info.host_or_ip= sctx_host_or_ip.str;
2013 mpvio->auth_info.host_or_ip_length= sctx_host_or_ip.length;
2014
2015 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
2016 Vio *vio= thd->get_protocol_classic()->get_vio();
2017 if (vio->ssl_arg)
2018 mpvio->vio_is_encrypted= 1;
2019 else
2020 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
2021 mpvio->vio_is_encrypted= 0;
2022 mpvio->status= MPVIO_EXT::FAILURE;
2023 mpvio->mem_root= thd->mem_root;
2024 mpvio->scramble= thd->scramble;
2025 mpvio->rand= &thd->rand;
2026 mpvio->thread_id= thd->thread_id();
2027 mpvio->server_status= &thd->server_status;
2028 mpvio->protocol= thd->get_protocol_classic();
2029 mpvio->ip= (char *) thd->security_context()->ip().str;
2030 mpvio->host= (char *) thd->security_context()->host().str;
2031 mpvio->charset_adapter= charset_adapter;
2032 }
2033
2034
2035
2036 static void
server_mpvio_update_thd(THD * thd,MPVIO_EXT * mpvio)2037 server_mpvio_update_thd(THD *thd, MPVIO_EXT *mpvio)
2038 {
2039 thd->max_client_packet_length= mpvio->max_client_packet_length;
2040 if (mpvio->protocol->has_client_capability(CLIENT_INTERACTIVE))
2041 thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
2042 thd->security_context()->assign_user(
2043 mpvio->auth_info.user_name,
2044 (mpvio->auth_info.user_name ? strlen(mpvio->auth_info.user_name) : 0));
2045 if (mpvio->auth_info.user_name)
2046 my_free(mpvio->auth_info.user_name);
2047 LEX_CSTRING sctx_user= thd->security_context()->user();
2048 mpvio->auth_info.user_name= (char *) sctx_user.str;
2049 mpvio->auth_info.user_name_length= sctx_user.length;
2050 if (thd->get_protocol()->has_client_capability(CLIENT_IGNORE_SPACE))
2051 thd->variables.sql_mode|= MODE_IGNORE_SPACE;
2052 }
2053
2054 /**
2055 Calculate the timestamp difference for password expiry
2056
2057 @param thd thread handle
2058 @param acl_user ACL_USER handle
2059
2060 @retval 0 password is valid
2061 @retval 1 password has expired
2062 */
2063 bool
check_password_lifetime(THD * thd,const ACL_USER * acl_user)2064 check_password_lifetime(THD *thd, const ACL_USER *acl_user)
2065 {
2066
2067 bool password_time_expired= false;
2068
2069 if (likely(acl_user != NULL) && !acl_user->password_expired &&
2070 acl_user->password_last_changed.time_type != MYSQL_TIMESTAMP_ERROR
2071 && auth_plugin_is_built_in(acl_user->plugin.str)
2072 && (acl_user->use_default_password_lifetime ||
2073 acl_user->password_lifetime))
2074 {
2075 MYSQL_TIME cur_time, password_change_by;
2076 Interval interval;
2077
2078 thd->set_time();
2079 thd->variables.time_zone->gmt_sec_to_TIME(&cur_time,
2080 static_cast<my_time_t>(thd->query_start()));
2081 password_change_by= acl_user->password_last_changed;
2082 memset(&interval, 0, sizeof(interval));
2083
2084 if (!acl_user->use_default_password_lifetime)
2085 interval.day= acl_user->password_lifetime;
2086 else
2087 {
2088 Mutex_lock lock(&LOCK_default_password_lifetime);
2089 interval.day= default_password_lifetime;
2090 }
2091 if (interval.day)
2092 {
2093 if (!date_add_interval(&password_change_by, INTERVAL_DAY, interval))
2094 password_time_expired= my_time_compare(&password_change_by,
2095 &cur_time) >=0 ? false: true;
2096 else
2097 {
2098 assert(FALSE);
2099 /* Make the compiler happy. */
2100 }
2101 }
2102 }
2103 DBUG_EXECUTE_IF("force_password_interval_expire",
2104 {
2105 if (!acl_user->use_default_password_lifetime &&
2106 acl_user->password_lifetime)
2107 password_time_expired= true;
2108 });
2109 DBUG_EXECUTE_IF("force_password_interval_expire_for_time_type",
2110 {
2111 if (acl_user->password_last_changed.time_type !=
2112 MYSQL_TIMESTAMP_ERROR)
2113 password_time_expired= true;
2114 });
2115 return password_time_expired;
2116 }
2117
2118 /**
2119 Logging connection for the general query log, extracted from
2120 acl_authenticate() as it's reused at different times based on
2121 whether proxy users are checked.
2122
2123 @param user authentication user name
2124 @param host authentication user host or IP address
2125 @param auth_as privilege user name
2126 @param db default database
2127 @param thd thread handle
2128 @param command type of command(connect or change user)
2129 */
2130 void
acl_log_connect(const char * user,const char * host,const char * auth_as,const char * db,THD * thd,enum enum_server_command command)2131 acl_log_connect(const char *user,
2132 const char *host,
2133 const char *auth_as,
2134 const char *db,
2135 THD *thd,
2136 enum enum_server_command command)
2137 {
2138 const char *vio_name_str= NULL;
2139 int len= 0;
2140 get_vio_type_name(thd->get_vio_type(), & vio_name_str, & len);
2141
2142 if (strcmp(auth_as, user) && (PROXY_FLAG != *auth_as))
2143 {
2144 query_logger.general_log_print(thd, command, "%s@%s as %s on %s using %s",
2145 user,
2146 host,
2147 auth_as,
2148 db ? db : (char*) "",
2149 vio_name_str);
2150 }
2151 else
2152 {
2153 query_logger.general_log_print(thd, command, "%s@%s on %s using %s",
2154 user,
2155 host,
2156 db ? db : (char*) "",
2157 vio_name_str);
2158 }
2159 }
2160
2161 /*
2162 Assign priv_user and priv_host fields of the Security_context.
2163
2164 @param sctx Security context, which priv_user and priv_host fields are
2165 updated.
2166 @param user Authenticated user data.
2167 */
2168 inline void
assign_priv_user_host(Security_context * sctx,ACL_USER * user)2169 assign_priv_user_host(Security_context *sctx, ACL_USER *user)
2170 {
2171 sctx->assign_priv_user(user->user, user->user ? strlen(user->user) : 0);
2172 sctx->assign_priv_host(user->host.get_host(), user->host.get_host_len());
2173 }
2174
2175 /**
2176 Perform the handshake, authorize the client and update thd sctx variables.
2177
2178 @param thd thread handle
2179 @param command the command to be executed, it can be either a
2180 COM_CHANGE_USER or COM_CONNECT (if
2181 it's a new connection)
2182
2183 @retval 0 success, thd is updated.
2184 @retval 1 error
2185 */
2186 int
acl_authenticate(THD * thd,enum_server_command command)2187 acl_authenticate(THD *thd, enum_server_command command)
2188 {
2189 int res= CR_OK;
2190 MPVIO_EXT mpvio;
2191 LEX_CSTRING auth_plugin_name= default_auth_plugin_name;
2192 Thd_charset_adapter charset_adapter(thd);
2193
2194 DBUG_ENTER("acl_authenticate");
2195 compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
2196 assert(command == COM_CONNECT || command == COM_CHANGE_USER);
2197
2198 server_mpvio_initialize(thd, &mpvio, &charset_adapter);
2199 /*
2200 Clear thd->db as it points to something, that will be freed when
2201 connection is closed. We don't want to accidentally free a wrong
2202 pointer if connect failed.
2203 */
2204 thd->reset_db(NULL_CSTR);
2205
2206 auth_plugin_name= default_auth_plugin_name;
2207 /* acl_authenticate() takes the data from net->read_pos */
2208 thd->get_protocol_classic()->get_net()->read_pos=
2209 thd->get_protocol_classic()->get_raw_packet();
2210 DBUG_PRINT("info", ("com_change_user_pkt_len=%lu",
2211 mpvio.protocol->get_packet_length()));
2212
2213 if (command == COM_CHANGE_USER)
2214 {
2215 mpvio.packets_written++; // pretend that a server handshake packet was sent
2216 mpvio.packets_read++; // take COM_CHANGE_USER packet into account
2217
2218 /* Clear variables that are allocated */
2219 thd->set_user_connect(NULL);
2220
2221 if (parse_com_change_user_packet(&mpvio,
2222 mpvio.protocol->get_packet_length()))
2223 {
2224 login_failed_error(&mpvio, mpvio.auth_info.password_used);
2225 server_mpvio_update_thd(thd, &mpvio);
2226 DBUG_RETURN(1);
2227 }
2228
2229 assert(mpvio.status == MPVIO_EXT::RESTART ||
2230 mpvio.status == MPVIO_EXT::SUCCESS);
2231 }
2232 else
2233 {
2234 /* mark the thd as having no scramble yet */
2235 mpvio.scramble[SCRAMBLE_LENGTH]= 1;
2236
2237 /*
2238 perform the first authentication attempt, with the default plugin.
2239 This sends the server handshake packet, reads the client reply
2240 with a user name, and performs the authentication if everyone has used
2241 the correct plugin.
2242 */
2243
2244 res= do_auth_once(thd, auth_plugin_name, &mpvio);
2245 }
2246
2247 /*
2248 retry the authentication, if - after receiving the user name -
2249 we found that we need to switch to a non-default plugin
2250 */
2251 if (mpvio.status == MPVIO_EXT::RESTART)
2252 {
2253 assert(mpvio.acl_user);
2254 assert(command == COM_CHANGE_USER ||
2255 my_strcasecmp(system_charset_info, auth_plugin_name.str,
2256 mpvio.acl_user->plugin.str));
2257 auth_plugin_name= mpvio.acl_user->plugin;
2258 res= do_auth_once(thd, auth_plugin_name, &mpvio);
2259 if (res <= CR_OK)
2260 {
2261 if (auth_plugin_name.str == native_password_plugin_name.str)
2262 thd->variables.old_passwords= 0;
2263 if (auth_plugin_name.str == sha256_password_plugin_name.str)
2264 thd->variables.old_passwords= 2;
2265 }
2266 }
2267
2268 server_mpvio_update_thd(thd, &mpvio);
2269 #ifdef HAVE_PSI_THREAD_INTERFACE
2270 PSI_THREAD_CALL(set_connection_type)(thd->get_vio_type());
2271 #endif /* HAVE_PSI_THREAD_INTERFACE */
2272
2273 Security_context *sctx= thd->security_context();
2274 const ACL_USER *acl_user= mpvio.acl_user;
2275 bool proxy_check= check_proxy_users && !*mpvio.auth_info.authenticated_as;
2276
2277 DBUG_PRINT("info", ("proxy_check=%s", proxy_check ? "true" : "false"));
2278
2279 thd->password= mpvio.auth_info.password_used; // remember for error messages
2280
2281 // reset authenticated_as because flag value received, but server
2282 // proxy mapping is disabled:
2283 if ((!check_proxy_users) && acl_user && !*mpvio.auth_info.authenticated_as)
2284 {
2285 DBUG_PRINT("info", ("setting authenticated_as to %s as check_proxy_user is OFF.",
2286 mpvio.auth_info.user_name));
2287 strcpy(mpvio.auth_info.authenticated_as, acl_user->user ? acl_user->user : "");
2288 }
2289 /*
2290 Log the command here so that the user can check the log
2291 for the tried logins and also to detect break-in attempts.
2292
2293 if sctx->user is unset it's protocol failure, bad packet.
2294 */
2295 if (mpvio.auth_info.user_name && !proxy_check)
2296 {
2297 acl_log_connect(mpvio.auth_info.user_name, mpvio.auth_info.host_or_ip,
2298 mpvio.auth_info.authenticated_as, mpvio.db.str, thd, command);
2299 }
2300 if (res == CR_OK &&
2301 (!mpvio.can_authenticate() || thd->is_error()))
2302 {
2303 res= CR_ERROR;
2304 }
2305
2306 /*
2307 Assign account user/host data to the current THD. This information is used
2308 when the authentication fails after this point and we call audit api
2309 notification event. Client user/host connects to the existing account is
2310 easily distinguished from other connects.
2311 */
2312 if (mpvio.can_authenticate())
2313 assign_priv_user_host(sctx, const_cast<ACL_USER *>(acl_user));
2314
2315 if (res > CR_OK && mpvio.status != MPVIO_EXT::SUCCESS)
2316 {
2317 Host_errors errors;
2318 assert(mpvio.status == MPVIO_EXT::FAILURE);
2319 switch (res)
2320 {
2321 case CR_AUTH_PLUGIN_ERROR:
2322 errors.m_auth_plugin= 1;
2323 break;
2324 case CR_AUTH_HANDSHAKE:
2325 errors.m_handshake= 1;
2326 break;
2327 case CR_AUTH_USER_CREDENTIALS:
2328 errors.m_authentication= 1;
2329 break;
2330 case CR_ERROR:
2331 default:
2332 /* Unknown of unspecified auth plugin error. */
2333 errors.m_auth_plugin= 1;
2334 break;
2335 }
2336 inc_host_errors(mpvio.ip, &errors);
2337 if (mpvio.auth_info.user_name && proxy_check)
2338 {
2339 acl_log_connect(mpvio.auth_info.user_name, mpvio.auth_info.host_or_ip,
2340 mpvio.auth_info.authenticated_as, mpvio.db.str, thd, command);
2341 }
2342 login_failed_error(&mpvio, mpvio.auth_info.password_used);
2343 DBUG_RETURN (1);
2344 }
2345
2346 sctx->assign_proxy_user("", 0);
2347
2348 if (initialized) // if not --skip-grant-tables
2349 {
2350 #ifndef NO_EMBEDDED_ACCESS_CHECKS
2351 bool is_proxy_user= FALSE;
2352 bool password_time_expired= false;
2353 const char *auth_user = acl_user->user ? acl_user->user : "";
2354 ACL_PROXY_USER *proxy_user;
2355 /* check if the user is allowed to proxy as another user */
2356 mysql_mutex_lock(&acl_cache->lock);
2357 proxy_user= acl_find_proxy_user(auth_user, sctx->host().str, sctx->ip().str,
2358 mpvio.auth_info.authenticated_as,
2359 &is_proxy_user);
2360 mysql_mutex_unlock(&acl_cache->lock);
2361 if (mpvio.auth_info.user_name && proxy_check)
2362 {
2363 acl_log_connect(mpvio.auth_info.user_name, mpvio.auth_info.host_or_ip,
2364 mpvio.auth_info.authenticated_as, mpvio.db.str, thd, command);
2365 }
2366
2367 if (thd->is_error())
2368 DBUG_RETURN(1);
2369
2370 if (is_proxy_user)
2371 {
2372 ACL_USER *acl_proxy_user;
2373 char proxy_user_buf[USERNAME_LENGTH + MAX_HOSTNAME + 5];
2374
2375 /* we need to find the proxy user, but there was none */
2376 if (!proxy_user)
2377 {
2378 Host_errors errors;
2379 errors.m_proxy_user= 1;
2380 inc_host_errors(mpvio.ip, &errors);
2381 login_failed_error(&mpvio, mpvio.auth_info.password_used);
2382 DBUG_RETURN(1);
2383 }
2384
2385 my_snprintf(proxy_user_buf, sizeof(proxy_user_buf) - 1,
2386 "'%s'@'%s'", auth_user, acl_user->host.get_host());
2387 sctx->assign_proxy_user(proxy_user_buf, strlen(proxy_user_buf));
2388
2389 /* we're proxying : find the proxy user definition */
2390 mysql_mutex_lock(&acl_cache->lock);
2391 acl_proxy_user= find_acl_user(proxy_user->get_proxied_host(),
2392 mpvio.auth_info.authenticated_as, TRUE);
2393 if (!acl_proxy_user)
2394 {
2395 Host_errors errors;
2396 errors.m_proxy_user_acl= 1;
2397 inc_host_errors(mpvio.ip, &errors);
2398 login_failed_error(&mpvio, mpvio.auth_info.password_used);
2399 mysql_mutex_unlock(&acl_cache->lock);
2400 DBUG_RETURN(1);
2401 }
2402 acl_user= acl_proxy_user->copy(thd->mem_root);
2403 DBUG_PRINT("info", ("User %s is a PROXY and will assume a PROXIED"
2404 " identity %s", auth_user, acl_user->user));
2405 mysql_mutex_unlock(&acl_cache->lock);
2406 }
2407 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
2408
2409 sctx->set_master_access(acl_user->access);
2410 assign_priv_user_host(sctx, const_cast<ACL_USER *>(acl_user));
2411
2412 if (!(sctx->check_access(SUPER_ACL)) && !thd->is_error())
2413 {
2414 mysql_mutex_lock(&LOCK_offline_mode);
2415 bool tmp_offline_mode= MY_TEST(offline_mode);
2416 mysql_mutex_unlock(&LOCK_offline_mode);
2417
2418 if (tmp_offline_mode)
2419 {
2420 my_error(ER_SERVER_OFFLINE_MODE, MYF(0));
2421 DBUG_RETURN(1);
2422 }
2423 }
2424
2425 #ifndef NO_EMBEDDED_ACCESS_CHECKS
2426 /*
2427 OK. Let's check the SSL. Historically it was checked after the password,
2428 as an additional layer, not instead of the password
2429 (in which case it would've been a plugin too).
2430 */
2431 if (acl_check_ssl(thd, acl_user))
2432 {
2433 Host_errors errors;
2434 errors.m_ssl= 1;
2435 inc_host_errors(mpvio.ip, &errors);
2436 login_failed_error(&mpvio, thd->password);
2437 DBUG_RETURN(1);
2438 }
2439
2440 /*
2441 Check whether the account has been locked.
2442 */
2443 if (unlikely(mpvio.acl_user->account_locked))
2444 {
2445 locked_account_connection_count++;
2446
2447 my_error(ER_ACCOUNT_HAS_BEEN_LOCKED, MYF(0),
2448 mpvio.acl_user->user, mpvio.auth_info.host_or_ip);
2449 sql_print_information(ER(ER_ACCOUNT_HAS_BEEN_LOCKED),
2450 mpvio.acl_user->user, mpvio.auth_info.host_or_ip);
2451 DBUG_RETURN(1);
2452 }
2453
2454 if (opt_require_secure_transport &&
2455 !is_secure_transport(thd->active_vio->type))
2456 {
2457 my_error(ER_SECURE_TRANSPORT_REQUIRED, MYF(0));
2458 DBUG_RETURN(1);
2459 }
2460
2461
2462 /* checking password_time_expire for connecting user */
2463 password_time_expired= check_password_lifetime(thd, mpvio.acl_user);
2464
2465 if (unlikely(mpvio.acl_user && (mpvio.acl_user->password_expired ||
2466 password_time_expired) &&
2467 !(mpvio.protocol->has_client_capability(
2468 CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS))
2469 && disconnect_on_expired_password))
2470 {
2471 /*
2472 Clients that don't signal password expiration support
2473 get a connect error.
2474 */
2475 Host_errors errors;
2476
2477 my_error(ER_MUST_CHANGE_PASSWORD_LOGIN, MYF(0));
2478 query_logger.general_log_print(thd, COM_CONNECT,
2479 ER(ER_MUST_CHANGE_PASSWORD_LOGIN));
2480 sql_print_information("%s", ER(ER_MUST_CHANGE_PASSWORD_LOGIN));
2481
2482 errors.m_authentication= 1;
2483 inc_host_errors(mpvio.ip, &errors);
2484 DBUG_RETURN(1);
2485 }
2486
2487 /* Don't allow the user to connect if he has done too many queries */
2488 if ((acl_user->user_resource.questions || acl_user->user_resource.updates ||
2489 acl_user->user_resource.conn_per_hour ||
2490 acl_user->user_resource.user_conn ||
2491 global_system_variables.max_user_connections) &&
2492 get_or_create_user_conn(thd,
2493 (opt_old_style_user_limits ? sctx->user().str :
2494 sctx->priv_user().str),
2495 (opt_old_style_user_limits ? sctx->host_or_ip().str :
2496 sctx->priv_host().str),
2497 &acl_user->user_resource))
2498 DBUG_RETURN(1); // The error is set by get_or_create_user_conn()
2499
2500 /*
2501 We are copying the connected user's password expired flag to the security
2502 context.
2503 This allows proxy user to execute queries even if proxied user password
2504 expires.
2505 */
2506 sctx->set_password_expired(mpvio.acl_user->password_expired ||
2507 password_time_expired);
2508 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
2509 }
2510 else
2511 sctx->skip_grants();
2512
2513 const USER_CONN *uc;
2514 if ((uc= thd->get_user_connect()) &&
2515 (uc->user_resources.conn_per_hour || uc->user_resources.user_conn ||
2516 global_system_variables.max_user_connections) &&
2517 check_for_max_user_connections(thd, uc))
2518 {
2519 DBUG_RETURN(1); // The error is set in check_for_max_user_connections()
2520 }
2521
2522 DBUG_PRINT("info",
2523 ("Capabilities: %lu packet_length: %ld Host: '%s' "
2524 "Login user: '%s' Priv_user: '%s' Using password: %s "
2525 "Access: %lu db: '%s'",
2526 thd->get_protocol()->get_client_capabilities(),
2527 thd->max_client_packet_length,
2528 sctx->host_or_ip().str, sctx->user().str, sctx->priv_user().str,
2529 thd->password ? "yes": "no",
2530 sctx->master_access(), mpvio.db.str));
2531
2532 if (command == COM_CONNECT &&
2533 !(thd->m_main_security_ctx.check_access(SUPER_ACL)))
2534 {
2535 #ifndef EMBEDDED_LIBRARY
2536 if (!Connection_handler_manager::get_instance()->valid_connection_count())
2537 { // too many connections
2538 release_user_connection(thd);
2539 my_error(ER_CON_COUNT_ERROR, MYF(0));
2540 DBUG_RETURN(1);
2541 }
2542 #endif // !EMBEDDED_LIBRARY
2543 }
2544
2545 /*
2546 This is the default access rights for the current database. It's
2547 set to 0 here because we don't have an active database yet (and we
2548 may not have an active database to set.
2549 */
2550 sctx->set_db_access(0);
2551
2552 /* Change a database if necessary */
2553 if (mpvio.db.length)
2554 {
2555 if (mysql_change_db(thd, to_lex_cstring(mpvio.db), false))
2556 {
2557 /* mysql_change_db() has pushed the error message. */
2558 release_user_connection(thd);
2559 Host_errors errors;
2560 errors.m_default_database= 1;
2561 inc_host_errors(mpvio.ip, &errors);
2562 login_failed_error(&mpvio, mpvio.auth_info.password_used);
2563 DBUG_RETURN(1);
2564 }
2565 }
2566
2567 if (mpvio.auth_info.external_user[0])
2568 sctx->assign_external_user(mpvio.auth_info.external_user,
2569 strlen(mpvio.auth_info.external_user));
2570
2571
2572 if (res == CR_OK_HANDSHAKE_COMPLETE)
2573 thd->get_stmt_da()->disable_status();
2574 else
2575 my_ok(thd);
2576
2577 #ifdef HAVE_PSI_THREAD_INTERFACE
2578 LEX_CSTRING main_sctx_user= thd->m_main_security_ctx.user();
2579 LEX_CSTRING main_sctx_host_or_ip= thd->m_main_security_ctx.host_or_ip();
2580 PSI_THREAD_CALL(set_thread_account)
2581 (main_sctx_user.str, main_sctx_user.length,
2582 main_sctx_host_or_ip.str, main_sctx_host_or_ip.length);
2583 #endif /* HAVE_PSI_THREAD_INTERFACE */
2584
2585 /* Ready to handle queries */
2586 DBUG_RETURN(0);
2587 }
2588
is_secure_transport(int vio_type)2589 bool is_secure_transport(int vio_type)
2590 {
2591 switch (vio_type)
2592 {
2593 case VIO_TYPE_SSL:
2594 case VIO_TYPE_SHARED_MEMORY:
2595 case VIO_TYPE_SOCKET:
2596 return TRUE;
2597 }
2598 return FALSE;
2599 }
2600
generate_native_password(char * outbuf,unsigned int * buflen,const char * inbuf,unsigned int inbuflen)2601 int generate_native_password(char *outbuf, unsigned int *buflen,
2602 const char *inbuf, unsigned int inbuflen)
2603 {
2604 if (my_validate_password_policy(inbuf, inbuflen))
2605 return 1;
2606 /* for empty passwords */
2607 if (inbuflen == 0)
2608 {
2609 *buflen= 0;
2610 return 0;
2611 }
2612 char *buffer= (char*)my_malloc(PSI_NOT_INSTRUMENTED,
2613 SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
2614 MYF(0));
2615 if (buffer == NULL)
2616 return 1;
2617 my_make_scrambled_password_sha1(buffer, inbuf, inbuflen);
2618 /*
2619 if buffer specified by server is smaller than the buffer given
2620 by plugin then return error
2621 */
2622 if (*buflen < strlen(buffer))
2623 {
2624 my_free(buffer);
2625 return 1;
2626 }
2627 *buflen= SCRAMBLED_PASSWORD_CHAR_LENGTH;
2628 memcpy(outbuf, buffer, *buflen);
2629 my_free(buffer);
2630 return 0;
2631 }
2632
validate_native_password_hash(char * const inbuf,unsigned int buflen)2633 int validate_native_password_hash(char* const inbuf, unsigned int buflen)
2634 {
2635 /* empty password is also valid */
2636 if ((buflen &&
2637 buflen == SCRAMBLED_PASSWORD_CHAR_LENGTH && inbuf[0] == '*') ||
2638 buflen == 0)
2639 return 0;
2640 return 1;
2641 }
2642
set_native_salt(const char * password,unsigned int password_len,unsigned char * salt,unsigned char * salt_len)2643 int set_native_salt(const char* password, unsigned int password_len,
2644 unsigned char* salt, unsigned char *salt_len)
2645 {
2646 /* for empty passwords salt_len is 0 */
2647 if (password_len == 0)
2648 *salt_len= 0;
2649 else
2650 {
2651 if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
2652 {
2653 get_salt_from_password(salt, password);
2654 *salt_len= SCRAMBLE_LENGTH;
2655 }
2656 }
2657 return 0;
2658 }
2659
2660 #if defined(HAVE_OPENSSL)
generate_sha256_password(char * outbuf,unsigned int * buflen,const char * inbuf,unsigned int inbuflen)2661 int generate_sha256_password(char *outbuf, unsigned int *buflen,
2662 const char *inbuf, unsigned int inbuflen)
2663 {
2664 if (inbuflen > SHA256_PASSWORD_MAX_PASSWORD_LENGTH ||
2665 my_validate_password_policy(inbuf, inbuflen))
2666 return 1;
2667 if (inbuflen == 0)
2668 {
2669 *buflen= 0;
2670 return 0;
2671 }
2672 char *buffer= (char*)my_malloc(PSI_NOT_INSTRUMENTED,
2673 CRYPT_MAX_PASSWORD_SIZE+1,
2674 MYF(0));
2675 if (buffer == NULL)
2676 return 1;
2677 my_make_scrambled_password(buffer, inbuf, inbuflen);
2678 memcpy(outbuf, buffer, CRYPT_MAX_PASSWORD_SIZE);
2679 /*
2680 if buffer specified by server is smaller than the buffer given
2681 by plugin then return error
2682 */
2683 if (*buflen < strlen(buffer))
2684 {
2685 my_free(buffer);
2686 return 1;
2687 }
2688 *buflen= strlen(buffer);
2689 my_free(buffer);
2690 return 0;
2691 }
2692
validate_sha256_password_hash(char * const inbuf,unsigned int buflen)2693 int validate_sha256_password_hash(char* const inbuf, unsigned int buflen)
2694 {
2695 if ((inbuf && inbuf[0] == '$' &&
2696 inbuf[1] == '5' && inbuf[2] == '$' &&
2697 buflen < CRYPT_MAX_PASSWORD_SIZE+1) ||
2698 buflen == 0)
2699 return 0;
2700 return 1;
2701 }
2702
set_sha256_salt(const char * password MY_ATTRIBUTE ((unused)),unsigned int password_len MY_ATTRIBUTE ((unused)),unsigned char * salt MY_ATTRIBUTE ((unused)),unsigned char * salt_len)2703 int set_sha256_salt(const char* password MY_ATTRIBUTE((unused)),
2704 unsigned int password_len MY_ATTRIBUTE((unused)),
2705 unsigned char* salt MY_ATTRIBUTE((unused)),
2706 unsigned char *salt_len)
2707 {
2708 *salt_len= 0;
2709 return 0;
2710 }
2711
2712 #endif
2713
2714
2715 /**
2716 MySQL Server Password Authentication Plugin
2717
2718 In the MySQL authentication protocol:
2719 1. the server sends the random scramble to the client
2720 2. client sends the encrypted password back to the server
2721 3. the server checks the password.
2722 */
native_password_authenticate(MYSQL_PLUGIN_VIO * vio,MYSQL_SERVER_AUTH_INFO * info)2723 static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
2724 MYSQL_SERVER_AUTH_INFO *info)
2725 {
2726 uchar *pkt;
2727 int pkt_len;
2728 MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
2729
2730 DBUG_ENTER("native_password_authenticate");
2731
2732 /* generate the scramble, or reuse the old one */
2733 if (mpvio->scramble[SCRAMBLE_LENGTH])
2734 generate_user_salt(mpvio->scramble, SCRAMBLE_LENGTH + 1);
2735
2736 /* send it to the client */
2737 if (mpvio->write_packet(mpvio, (uchar*) mpvio->scramble, SCRAMBLE_LENGTH + 1))
2738 DBUG_RETURN(CR_AUTH_HANDSHAKE);
2739
2740 /* reply and authenticate */
2741
2742 /*
2743 <digression>
2744 This is more complex than it looks.
2745
2746 The plugin (we) may be called right after the client was connected -
2747 and will need to send a scramble, read reply, authenticate.
2748
2749 Or the plugin may be called after another plugin has sent a scramble,
2750 and read the reply. If the client has used the correct client-plugin,
2751 we won't need to read anything here from the client, the client
2752 has already sent a reply with everything we need for authentication.
2753
2754 Or the plugin may be called after another plugin has sent a scramble,
2755 and read the reply, but the client has used the wrong client-plugin.
2756 We'll need to sent a "switch to another plugin" packet to the
2757 client and read the reply. "Use the short scramble" packet is a special
2758 case of "switch to another plugin" packet.
2759
2760 Or, perhaps, the plugin may be called after another plugin has
2761 done the handshake but did not send a useful scramble. We'll need
2762 to send a scramble (and perhaps a "switch to another plugin" packet)
2763 and read the reply.
2764
2765 Besides, a client may be an old one, that doesn't understand plugins.
2766 Or doesn't even understand 4.0 scramble.
2767
2768 And we want to keep the same protocol on the wire unless non-native
2769 plugins are involved.
2770
2771 Anyway, it still looks simple from a plugin point of view:
2772 "send the scramble, read the reply and authenticate"
2773 All the magic is transparently handled by the server.
2774 </digression>
2775 */
2776
2777 /* read the reply with the encrypted password */
2778 if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
2779 DBUG_RETURN(CR_AUTH_HANDSHAKE);
2780 DBUG_PRINT("info", ("reply read : pkt_len=%d", pkt_len));
2781
2782 #ifdef NO_EMBEDDED_ACCESS_CHECKS
2783 DBUG_RETURN(CR_OK);
2784 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
2785
2786 DBUG_EXECUTE_IF("native_password_bad_reply",
2787 {
2788 /* This should cause a HANDSHAKE ERROR */
2789 pkt_len= 12;
2790 }
2791 );
2792 if (mysql_native_password_proxy_users)
2793 {
2794 *info->authenticated_as= PROXY_FLAG;
2795 DBUG_PRINT("info", ("mysql_native_authentication_proxy_users is enabled, setting authenticated_as to NULL"));
2796 }
2797 if (pkt_len == 0) /* no password */
2798 DBUG_RETURN(mpvio->acl_user->salt_len != 0 ?
2799 CR_AUTH_USER_CREDENTIALS : CR_OK);
2800
2801 info->password_used= PASSWORD_USED_YES;
2802 if (pkt_len == SCRAMBLE_LENGTH)
2803 {
2804 if (!mpvio->acl_user->salt_len)
2805 DBUG_RETURN(CR_AUTH_USER_CREDENTIALS);
2806
2807 DBUG_RETURN(check_scramble(pkt, mpvio->scramble, mpvio->acl_user->salt) ?
2808 CR_AUTH_USER_CREDENTIALS : CR_OK);
2809 }
2810
2811 my_error(ER_HANDSHAKE_ERROR, MYF(0));
2812 DBUG_RETURN(CR_AUTH_HANDSHAKE);
2813 }
2814
2815 /**
2816 Interface for querying the MYSQL_PUBLIC_VIO about encryption state.
2817
2818 */
2819
my_vio_is_encrypted(MYSQL_PLUGIN_VIO * vio)2820 int my_vio_is_encrypted(MYSQL_PLUGIN_VIO *vio)
2821 {
2822 MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
2823 return (mpvio->vio_is_encrypted);
2824 }
2825
2826 #if defined(HAVE_OPENSSL)
2827
show_rsa_public_key(THD * thd,SHOW_VAR * var,char * buff)2828 int show_rsa_public_key(THD *thd, SHOW_VAR *var, char *buff)
2829 {
2830 var->type= SHOW_CHAR;
2831 var->value= const_cast<char *>(g_rsa_keys.get_public_key_as_pem());
2832
2833 return 0;
2834 }
2835
deinit_rsa_keys(void)2836 void deinit_rsa_keys(void)
2837 {
2838 g_rsa_keys.free_memory();
2839 }
2840
2841 // Wraps a FILE handle, to ensure we always close it when returning.
2842 class FileCloser
2843 {
2844 FILE *m_file;
2845 public:
FileCloser(FILE * to_be_closed)2846 FileCloser(FILE *to_be_closed) : m_file(to_be_closed) {}
~FileCloser()2847 ~FileCloser()
2848 {
2849 if (m_file != NULL)
2850 fclose(m_file);
2851 }
2852 };
2853
2854 /**
2855 Loads the RSA key pair from disk and store them in a global variable.
2856
2857 @see init_ssl()
2858
2859 @return Error code
2860 @retval false Success
2861 @retval true Error
2862 */
2863
init_rsa_keys(void)2864 bool init_rsa_keys(void)
2865 {
2866 return ((do_auto_rsa_keys_generation() == false) ||
2867 g_rsa_keys.read_rsa_keys());
2868 }
2869
2870 static MYSQL_PLUGIN plugin_info_ptr;
2871
init_sha256_password_handler(MYSQL_PLUGIN plugin_ref)2872 int init_sha256_password_handler(MYSQL_PLUGIN plugin_ref)
2873 {
2874 plugin_info_ptr= plugin_ref;
2875 return 0;
2876 }
2877
2878 /**
2879
2880 @param vio Virtual input-, output interface
2881 @param scramble - Scramble to be saved
2882
2883 Save the scramble in mpvio for future re-use.
2884 It is useful when we need to pass the scramble to another plugin.
2885 Especially in case when old 5.1 client with no CLIENT_PLUGIN_AUTH capability
2886 tries to connect to server with default-authentication-plugin set to
2887 sha256_password
2888
2889 */
2890
auth_save_scramble(MYSQL_PLUGIN_VIO * vio,const char * scramble)2891 void static inline auth_save_scramble(MYSQL_PLUGIN_VIO *vio, const char *scramble)
2892 {
2893 MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
2894 strncpy(mpvio->scramble, scramble, SCRAMBLE_LENGTH+1);
2895 }
2896
2897
2898 /**
2899
2900 @param vio Virtual input-, output interface
2901 @param info[out] Connection information
2902
2903 Authenticate the user by recieving a RSA or TLS encrypted password and
2904 calculate a hash digest which should correspond to the user record digest
2905
2906 RSA keys are assumed to be pre-generated and supplied when server starts. If
2907 the client hasn't got a public key it can request one.
2908
2909 TLS certificates and keys are assumed to be pre-generated and supplied when
2910 server starts.
2911
2912 */
2913
sha256_password_authenticate(MYSQL_PLUGIN_VIO * vio,MYSQL_SERVER_AUTH_INFO * info)2914 static int sha256_password_authenticate(MYSQL_PLUGIN_VIO *vio,
2915 MYSQL_SERVER_AUTH_INFO *info)
2916 {
2917 uchar *pkt;
2918 int pkt_len;
2919 char *user_salt_begin;
2920 char *user_salt_end;
2921 char scramble[SCRAMBLE_LENGTH + 1];
2922 char stage2[CRYPT_MAX_PASSWORD_SIZE + 1];
2923 String scramble_response_packet;
2924 int cipher_length= 0;
2925 unsigned char plain_text[MAX_CIPHER_LENGTH + 1];
2926 RSA *private_key= NULL;
2927 RSA *public_key= NULL;
2928
2929 DBUG_ENTER("sha256_password_authenticate");
2930
2931 generate_user_salt(scramble, SCRAMBLE_LENGTH + 1);
2932
2933 /*
2934 Note: The nonce is split into 8 + 12 bytes according to
2935 http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeV10
2936 Native authentication sent 20 bytes + '\0' character = 21 bytes.
2937 This plugin must do the same to stay consistent with historical behavior
2938 if it is set to operate as a default plugin.
2939 */
2940 if (vio->write_packet(vio, (unsigned char *) scramble, SCRAMBLE_LENGTH + 1))
2941 DBUG_RETURN(CR_ERROR);
2942
2943 /*
2944 Save the scramble so it could be used by native plugin in case
2945 the authentication on the server side needs to be restarted
2946 */
2947 auth_save_scramble(vio, scramble);
2948
2949 /*
2950 After the call to read_packet() the user name will appear in
2951 mpvio->acl_user and info will contain current data.
2952 */
2953 if ((pkt_len= vio->read_packet(vio, &pkt)) == -1)
2954 DBUG_RETURN(CR_ERROR);
2955
2956 /*
2957 If first packet is a 0 byte then the client isn't sending any password
2958 else the client will send a password.
2959
2960 The original intention was that the password is a string[NUL] but this
2961 never got enforced properly so now we have to accept that an empty packet
2962 is a blank password, thus the check for pkt_len == 0 has to be made too.
2963 */
2964 if ((pkt_len == 0 || pkt_len == 1) && *pkt == 0)
2965 {
2966 info->password_used= PASSWORD_USED_NO;
2967 /*
2968 Send OK signal; the authentication might still be rejected based on
2969 host mask.
2970 */
2971 if (info->auth_string_length == 0)
2972 {
2973 if (sha256_password_proxy_users)
2974 {
2975 *info->authenticated_as = PROXY_FLAG;
2976 DBUG_PRINT("info", ("sha256_password_proxy_users is enabled \
2977 , setting authenticated_as to NULL"));
2978 }
2979 DBUG_RETURN(CR_OK);
2980 }
2981 else
2982 DBUG_RETURN(CR_ERROR);
2983 }
2984 else
2985 info->password_used= PASSWORD_USED_YES;
2986
2987 if (!my_vio_is_encrypted(vio))
2988 {
2989 /*
2990 Since a password is being used it must be encrypted by RSA since no
2991 other encryption is being active.
2992 */
2993 private_key= g_rsa_keys.get_private_key();
2994 public_key= g_rsa_keys.get_public_key();
2995
2996 /*
2997 Without the keys encryption isn't possible.
2998 */
2999 if (private_key == NULL || public_key == NULL)
3000 {
3001 my_plugin_log_message(&plugin_info_ptr, MY_ERROR_LEVEL,
3002 "Authentication requires either RSA keys or SSL encryption");
3003 DBUG_RETURN(CR_ERROR);
3004 }
3005
3006
3007 if ((cipher_length= g_rsa_keys.get_cipher_length()) > MAX_CIPHER_LENGTH)
3008 {
3009 my_plugin_log_message(&plugin_info_ptr, MY_ERROR_LEVEL,
3010 "RSA key cipher length of %u is too long. Max value is %u.",
3011 g_rsa_keys.get_cipher_length(), MAX_CIPHER_LENGTH);
3012 DBUG_RETURN(CR_ERROR);
3013 }
3014
3015 /*
3016 Client sent a "public key request"-packet ?
3017 If the first packet is 1 then the client will require a public key before
3018 encrypting the password.
3019 */
3020 if (pkt_len == 1 && *pkt == 1)
3021 {
3022 uint pem_length= static_cast<uint>(strlen(g_rsa_keys.get_public_key_as_pem()));
3023 if (vio->write_packet(vio,
3024 (unsigned char *)g_rsa_keys.get_public_key_as_pem(),
3025 pem_length))
3026 DBUG_RETURN(CR_ERROR);
3027 /* Get the encrypted response from the client */
3028 if ((pkt_len= vio->read_packet(vio, &pkt)) == -1)
3029 DBUG_RETURN(CR_ERROR);
3030 }
3031
3032 /*
3033 The packet will contain the cipher used. The length of the packet
3034 must correspond to the expected cipher length.
3035 */
3036 if (pkt_len != cipher_length)
3037 DBUG_RETURN(CR_ERROR);
3038
3039 /* Decrypt password */
3040 RSA_private_decrypt(cipher_length, pkt, plain_text, private_key,
3041 RSA_PKCS1_OAEP_PADDING);
3042
3043 plain_text[cipher_length]= '\0'; // safety
3044 xor_string((char *) plain_text, cipher_length,
3045 (char *) scramble, SCRAMBLE_LENGTH);
3046
3047 /*
3048 Set packet pointers and length for the hash digest function below
3049 */
3050 pkt= plain_text;
3051 pkt_len= strlen((char *) plain_text) + 1; // include \0 intentionally.
3052
3053 if (pkt_len == 1)
3054 DBUG_RETURN(CR_ERROR);
3055 } // if(!my_vio_is_encrypter())
3056
3057 /* Don't process the password if it is longer than maximum limit */
3058 if (pkt_len > SHA256_PASSWORD_MAX_PASSWORD_LENGTH + 1)
3059 DBUG_RETURN(CR_ERROR);
3060
3061 /* A password was sent to an account without a password */
3062 if (info->auth_string_length == 0)
3063 DBUG_RETURN(CR_ERROR);
3064
3065 /*
3066 Fetch user authentication_string and extract the password salt
3067 */
3068 user_salt_begin= (char *) info->auth_string;
3069 user_salt_end= (char *) (info->auth_string + info->auth_string_length);
3070 if (extract_user_salt(&user_salt_begin, &user_salt_end) != CRYPT_SALT_LENGTH)
3071 {
3072 /* User salt is not correct */
3073 my_plugin_log_message(&plugin_info_ptr, MY_ERROR_LEVEL,
3074 "Password salt for user '%s' is corrupt.",
3075 info->user_name);
3076 DBUG_RETURN(CR_ERROR);
3077 }
3078
3079 /* Create hash digest */
3080 my_crypt_genhash(stage2,
3081 CRYPT_MAX_PASSWORD_SIZE,
3082 (char *) pkt,
3083 pkt_len-1,
3084 user_salt_begin,
3085 (const char **) 0);
3086
3087 /* Compare the newly created hash digest with the password record */
3088 int result= memcmp(info->auth_string,
3089 stage2,
3090 info->auth_string_length);
3091
3092 if (result == 0)
3093 {
3094 if (sha256_password_proxy_users)
3095 {
3096 *info->authenticated_as= PROXY_FLAG;
3097 DBUG_PRINT("info", ("mysql_native_authentication_proxy_users is enabled \
3098 , setting authenticated_as to NULL"));
3099 }
3100 DBUG_RETURN(CR_OK);
3101 }
3102
3103 DBUG_RETURN(CR_ERROR);
3104 }
3105
3106 static MYSQL_SYSVAR_STR(private_key_path, auth_rsa_private_key_path,
3107 PLUGIN_VAR_READONLY,
3108 "A fully qualified path to the private RSA key used for authentication",
3109 NULL, NULL, AUTH_DEFAULT_RSA_PRIVATE_KEY);
3110 static MYSQL_SYSVAR_STR(public_key_path, auth_rsa_public_key_path,
3111 PLUGIN_VAR_READONLY,
3112 "A fully qualified path to the public RSA key used for authentication",
3113 NULL, NULL, AUTH_DEFAULT_RSA_PUBLIC_KEY);
3114 static MYSQL_SYSVAR_BOOL(auto_generate_rsa_keys, auth_rsa_auto_generate_rsa_keys,
3115 PLUGIN_VAR_READONLY | PLUGIN_VAR_OPCMDARG,
3116 "Auto generate RSA keys at server startup if correpsonding "
3117 "system variables are not specified and key files are not present "
3118 "at the default location.",
3119 NULL, NULL, TRUE);
3120
3121 static struct st_mysql_sys_var* sha256_password_sysvars[]= {
3122 MYSQL_SYSVAR(private_key_path),
3123 MYSQL_SYSVAR(public_key_path),
3124 MYSQL_SYSVAR(auto_generate_rsa_keys),
3125 0
3126 };
3127
3128
3129 typedef std::string Sql_string_t;
3130
3131 /*
3132 Exception free resize
3133
3134 @param content [in/out] : string handle
3135 @param size [in] : New size
3136
3137
3138 @returns
3139 @retval false : Error
3140 @retval true : Successfully resized
3141 */
3142 static
resize_no_exception(Sql_string_t & content,size_t size)3143 bool resize_no_exception(Sql_string_t &content, size_t size)
3144 {
3145 try
3146 {
3147 content.resize(size);
3148 }
3149 catch (const std::length_error& le)
3150 {
3151 return false;
3152 }
3153 catch (std::bad_alloc& ba)
3154 {
3155 return false;
3156 }
3157 return true;
3158 }
3159
3160
3161 /**
3162
3163 FILE_IO : Wrapper around std::fstream
3164 1> Provides READ/WRITE handle to a file
3165 2> Records error on READ/WRITE operations
3166 3> Closes file before destruction
3167
3168 */
3169
3170 class File_IO
3171 {
3172 public:
File_IO(const File_IO & src)3173 File_IO(const File_IO& src)
3174 : m_file_name(src.file_name()),
3175 m_read(src.read_mode()),
3176 m_error_state(src.get_error())
3177 {
3178 m_file.open(m_file_name.c_str(),
3179 m_read ? std::ios::in :
3180 std::ios::out|std::ios::trunc);
3181 }
3182
operator =(const File_IO & src)3183 File_IO & operator=(const File_IO& src)
3184 {
3185 m_file_name= src.file_name();
3186 m_read= src.read_mode();
3187 m_file.open(m_file_name.c_str(),
3188 m_read ? std::ios::in :
3189 std::ios::out|std::ios::trunc);
3190
3191 return *this;
3192 }
3193
~File_IO()3194 ~File_IO()
3195 {
3196 close();
3197 }
3198
3199 /*
3200 Close an already open file.
3201 */
close()3202 void close()
3203 {
3204 if (m_file.is_open())
3205 m_file.close();
3206 }
3207
3208 /*
3209 Get name of the file. Used by copy constructor
3210 */
file_name() const3211 const Sql_string_t & file_name() const
3212 { return m_file_name; }
3213
3214 /*
3215 Get file IO mode. Used by copy constructor.
3216 */
read_mode() const3217 bool read_mode() const
3218 { return m_read; }
3219
3220 /*
3221 Get READ/WRITE error status.
3222 */
get_error() const3223 bool get_error() const
3224 { return m_error_state; }
3225
3226 /*
3227 Set error. Used by >> and << functions.
3228 */
set_error()3229 void set_error()
3230 { m_error_state= true; }
3231
reset_error()3232 void reset_error()
3233 { m_error_state= false; }
3234
3235 File_IO & operator>>(Sql_string_t &s);
3236 File_IO & operator<<(const Sql_string_t &output_string);
3237
3238 protected:
File_IO()3239 File_IO() {};
File_IO(const Sql_string_t filename,bool read)3240 File_IO(const Sql_string_t filename, bool read)
3241 : m_file_name(filename),
3242 m_read(read),
3243 m_error_state(false)
3244 {
3245 m_file.open(m_file_name.c_str(),
3246 m_read ? std::ios::in :
3247 std::ios::out|std::ios::trunc);
3248 }
3249 private:
3250 Sql_string_t m_file_name;
3251 bool m_read;
3252 bool m_error_state;
3253 std::fstream m_file;
3254 /* Only File_creator can create File_IO */
3255 friend class File_creator;
3256 };
3257
3258
3259 /*
3260 Read an open file.
3261
3262 @param op [in/out] : Handle to FILE_IO
3263 @param s [out] : String buffer
3264
3265 Assumption : Caller will free string buffer
3266
3267 returns File_IO reference. Optionally sets error.
3268 */
3269 File_IO &
operator >>(Sql_string_t & s)3270 File_IO::operator>>(Sql_string_t &s)
3271 {
3272 assert(read_mode() && m_file.is_open());
3273
3274 m_file.seekg(0, std::ios::end);
3275 if (resize_no_exception(s, m_file.tellg()) == false)
3276 set_error();
3277 else
3278 {
3279 m_file.seekg(0, std::ios::beg);
3280 m_file.read(&s[0], s.size());
3281 close();
3282 }
3283 return *this;
3284 }
3285
3286
3287 /*
3288 Write into an open file
3289
3290 @param op [in/out] : Handle to File_IO
3291 @parma output_string[in] : content to be written
3292
3293 Assumption : string must be non-empty.
3294
3295 @returns File_IO reference. Optionally sets error.
3296 */
3297 File_IO &
operator <<(const Sql_string_t & output_string)3298 File_IO::operator<<(const Sql_string_t &output_string)
3299 {
3300 assert(!read_mode() && m_file.is_open());
3301
3302 if (!output_string.size())
3303 set_error();
3304 else
3305 m_file << output_string;
3306
3307 close();
3308 return *this;
3309 }
3310
3311
3312 /*
3313 Helper class to create a File_IO handle.
3314 Can be extended in future to set more file specific properties.
3315 Frees allocated memory in destructor.
3316 */
3317 class File_creator
3318 {
3319 public:
File_creator()3320 File_creator() {};
3321
~File_creator()3322 ~File_creator()
3323 {
3324 for(std::vector<File_IO *>::iterator it= m_file_vector.begin();
3325 it != m_file_vector.end();
3326 ++it)
3327 delete(*it);
3328 }
3329
3330 /*
3331 Note : Do not free memory.
3332 */
operator ()(const Sql_string_t filename,bool read=false)3333 File_IO * operator()(const Sql_string_t filename, bool read=false)
3334 {
3335 File_IO * f= new File_IO(filename, read);
3336 m_file_vector.push_back(f);
3337 return f;
3338 }
3339
3340 private:
3341 std::vector<File_IO *> m_file_vector;
3342 };
3343
3344
3345 /*
3346 This class encapsulates OpenSSL specific details of RSA key generation.
3347 It provides interfaces to:
3348
3349 1> Get RSA structure
3350 2> Get EVP_PKEY structure
3351 3> Write Private/Public key into a string
3352 4> Free RSA/EVP_PKEY structures
3353 */
3354 class RSA_gen
3355 {
3356 public:
RSA_gen(uint32_t key_size=2048,uint32_t exponent=RSA_F4)3357 RSA_gen(uint32_t key_size= 2048, uint32_t exponent= RSA_F4)
3358 : m_key_size(key_size),
3359 m_exponent(exponent) {};
3360
~RSA_gen()3361 ~RSA_gen() {};
3362
3363 /**
3364 Passing key type is a violation against the principle of generic
3365 programming when this operator is used in an algorithm
3366 but it at the same time increases usefulness of this class when used
3367 stand alone.
3368 */
operator ()(void)3369 RSA *operator()(void)
3370 {
3371 /* generate RSA keys */
3372 RSA *rsa= RSA_new();
3373 if (!rsa)
3374 return NULL;
3375 BIGNUM *e= BN_new();
3376 if (!e)
3377 {
3378 RSA_free(rsa);
3379 return NULL;
3380 }
3381 if (!BN_set_word(e, m_exponent) ||
3382 !RSA_generate_key_ex(rsa, m_key_size, e, NULL))
3383 {
3384 RSA_free(rsa);
3385 BN_free(e);
3386 return NULL;
3387 }
3388 BN_free(e);
3389
3390 return rsa; // pass ownership
3391 }
3392
3393 private:
3394
3395 uint32_t m_key_size;
3396 uint32_t m_exponent;
3397 };
3398
3399
evp_pkey_generate(RSA * rsa)3400 EVP_PKEY *evp_pkey_generate(RSA *rsa)
3401 {
3402 if (rsa)
3403 {
3404 EVP_PKEY *pkey= EVP_PKEY_new();
3405 EVP_PKEY_assign_RSA(pkey, rsa);
3406 return pkey;
3407 }
3408 return NULL;
3409 }
3410
3411
3412 /*
3413 Write private key in a string buffer
3414
3415 @param rsa [in] : Handle to RSA structure where private key is stored
3416
3417 @returns Sql_string_t object with private key stored in it.
3418 */
3419 static
rsa_priv_key_write(RSA * rsa)3420 Sql_string_t rsa_priv_key_write(RSA *rsa)
3421 {
3422 assert(rsa);
3423 BIO *buf= BIO_new(BIO_s_mem());
3424 Sql_string_t read_buffer;
3425 if (PEM_write_bio_RSAPrivateKey(buf, rsa, NULL, NULL,
3426 0, NULL, NULL))
3427 {
3428 size_t len= BIO_pending(buf);
3429 if (resize_no_exception(read_buffer, len+1) == true)
3430 {
3431 BIO_read(buf, (void *)read_buffer.c_str(), len);
3432 read_buffer[len]='\0';
3433 }
3434 }
3435 BIO_free(buf);
3436 return read_buffer;
3437 }
3438
3439
3440 /*
3441 Write public key in a string buffer
3442
3443 @param rsa [in] : Handle to RSA structure where public key is stored
3444
3445 @returns Sql_string_t object with public key stored in it.
3446 */
3447 static
rsa_pub_key_write(RSA * rsa)3448 Sql_string_t rsa_pub_key_write(RSA *rsa)
3449 {
3450 assert(rsa);
3451 BIO *buf= BIO_new(BIO_s_mem());
3452 Sql_string_t read_buffer;
3453 if (PEM_write_bio_RSA_PUBKEY(buf, rsa))
3454 {
3455 size_t len= BIO_pending(buf);
3456 if (resize_no_exception(read_buffer, len+1) == true)
3457 {
3458 BIO_read(buf, (void *)read_buffer.c_str(), len);
3459 read_buffer[len]='\0';
3460 }
3461 }
3462 BIO_free(buf);
3463 return read_buffer;
3464 }
3465
3466
3467 /*
3468 This class encapsulates OpenSSL specific details of X509 certificate
3469 generation. It provides interfaces to:
3470
3471 1> Generate X509 certificate
3472 2> Read/Write X509 certificate from/to a string
3473 3> Read/Write Private key from/to a string
3474 4> Free X509/EVP_PKEY structures
3475 */
3476 class X509_gen
3477 {
3478 public:
operator ()(EVP_PKEY * pkey,const Sql_string_t cn,uint32_t serial,uint32_t notbefore,uint32_t notafter,bool self_sign=true,X509 * ca_x509=NULL,EVP_PKEY * ca_pkey=NULL)3479 X509 * operator()(EVP_PKEY *pkey,
3480 const Sql_string_t cn,
3481 uint32_t serial,
3482 uint32_t notbefore,
3483 uint32_t notafter,
3484 bool self_sign= true,
3485 X509 *ca_x509= NULL,
3486 EVP_PKEY *ca_pkey= NULL)
3487 {
3488 X509 *x509= X509_new();
3489 X509_EXTENSION *ext= 0;
3490 X509V3_CTX v3ctx;
3491 X509_NAME *name= 0;
3492
3493 assert(cn.length() <= MAX_CN_NAME_LENGTH);
3494 assert(serial != 0);
3495 assert(self_sign || (ca_x509 != NULL && ca_pkey != NULL));
3496 if (!x509)
3497 goto err;
3498
3499 /** Set certificate version */
3500 if (!X509_set_version(x509, 2))
3501 goto err;
3502
3503 /** Set serial number */
3504 if (!ASN1_INTEGER_set(X509_get_serialNumber(x509), serial))
3505 goto err;
3506
3507 /** Set certificate validity */
3508 if (!X509_gmtime_adj(X509_get_notBefore(x509), notbefore) ||
3509 !X509_gmtime_adj(X509_get_notAfter(x509), notafter))
3510 goto err;
3511
3512 /** Set public key */
3513 if (!X509_set_pubkey(x509, pkey))
3514 goto err;
3515
3516 /** Set CN value in subject */
3517 name= X509_get_subject_name(x509);
3518 if (!name)
3519 goto err;
3520
3521 if (!X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
3522 (const unsigned char *)cn.c_str(),
3523 -1, -1, 0))
3524 goto err;
3525
3526 /** Set Issuer */
3527 if (!X509_set_issuer_name(x509, self_sign ? name :
3528 X509_get_subject_name(ca_x509)))
3529 goto err;
3530
3531 /** Add X509v3 extensions */
3532 X509V3_set_ctx(&v3ctx, self_sign ? x509 : ca_x509, x509, NULL, NULL, 0);
3533
3534 /** Add CA:TRUE / CA:FALSE inforamation */
3535 if (!(ext= X509V3_EXT_conf_nid(NULL, &v3ctx, NID_basic_constraints,
3536 self_sign ?(char *)"critical,CA:TRUE" :
3537 (char *)"critical,CA:FALSE")))
3538 goto err;
3539 X509_add_ext(x509, ext, -1);
3540 X509_EXTENSION_free(ext);
3541
3542 /** Sign using SHA256 */
3543 if (!X509_sign(x509, self_sign ? pkey : ca_pkey, EVP_sha256()))
3544 goto err;
3545
3546 return x509;
3547 err:
3548 if (x509)
3549 X509_free(x509);
3550 return 0;
3551 }
3552 };
3553
3554
3555 /*
3556 Read a X509 certificate into X509 format
3557
3558 @param input_string [in] : Content of X509 certificate file.
3559
3560 @returns Handle to X509 structure.
3561
3562 Assumption : Caller will free X509 object
3563 */
3564 static
x509_cert_read(const Sql_string_t & input_string)3565 X509 * x509_cert_read(const Sql_string_t &input_string)
3566 {
3567 X509 * x509= NULL;
3568
3569 if (!input_string.size())
3570 return x509;
3571
3572 BIO *buf= BIO_new(BIO_s_mem());
3573 BIO_write(buf, input_string.c_str(), input_string.size());
3574 x509= PEM_read_bio_X509(buf, NULL, NULL, NULL);
3575 BIO_free(buf);
3576 return x509;
3577 }
3578
3579
3580 /*
3581 Write X509 certificate into a string
3582
3583 @param cert [in] : Certificate information in X509 format.
3584
3585 @returns certificate information in string format.
3586 */
3587 static
x509_cert_write(X509 * cert)3588 Sql_string_t x509_cert_write(X509 *cert)
3589 {
3590 assert(cert);
3591 BIO *buf= BIO_new(BIO_s_mem());
3592 Sql_string_t read_buffer;
3593 if (PEM_write_bio_X509(buf, cert))
3594 {
3595 size_t len= BIO_pending(buf);
3596 if (resize_no_exception(read_buffer, len+1) == true)
3597 {
3598 BIO_read(buf, (void *)read_buffer.c_str(), len);
3599 read_buffer[len]='\0';
3600 }
3601 }
3602 BIO_free(buf);
3603 return read_buffer;
3604 }
3605
3606
3607 /*
3608 Read Private key into EVP_PKEY structure
3609
3610 @param input_string [in] : Content of private key file.
3611
3612 @returns Handle to EVP_PKEY structure.
3613
3614 Assumption : Caller will free EVP_PKEY object
3615 */
3616 static
x509_key_read(const Sql_string_t & input_string)3617 EVP_PKEY * x509_key_read(const Sql_string_t &input_string)
3618 {
3619 EVP_PKEY *pkey= NULL;
3620 RSA *rsa= NULL;
3621
3622 if (!input_string.size())
3623 return pkey;
3624
3625 BIO *buf= BIO_new(BIO_s_mem());
3626 BIO_write(buf, input_string.c_str(), input_string.size());
3627 rsa= PEM_read_bio_RSAPrivateKey(buf, NULL, NULL, NULL);
3628 pkey= evp_pkey_generate(rsa);
3629 BIO_free(buf);
3630 return pkey;
3631 }
3632
3633
3634 /*
3635 Write X509 certificate into a string
3636
3637 @param pkey [in] : Private key information.
3638
3639 @returns private key information in string format.
3640 */
3641 static
x509_key_write(EVP_PKEY * pkey)3642 Sql_string_t x509_key_write(EVP_PKEY *pkey)
3643 {
3644 assert(pkey);
3645 BIO *buf= BIO_new(BIO_s_mem());
3646 RSA *rsa= EVP_PKEY_get1_RSA(pkey);
3647 Sql_string_t read_buffer;
3648 if (PEM_write_bio_RSAPrivateKey(buf, rsa, NULL, NULL,
3649 10, NULL, NULL))
3650 {
3651 size_t len= BIO_pending(buf);
3652 if (resize_no_exception(read_buffer, len+1) == true)
3653 {
3654 BIO_read(buf, (void *)read_buffer.c_str(), len);
3655 read_buffer[len]='\0';
3656 }
3657 }
3658 BIO_free(buf);
3659 RSA_free(rsa);
3660 return read_buffer;
3661 }
3662
3663
3664 /*
3665 Algorithm to create X509 certificate.
3666 Relies on:
3667 1> RSA key generator
3668 2> X509 certificate generator
3669 3> FILE reader/writer
3670
3671 Overwrites key/certificate files if already present.
3672
3673 @param rsa_gen [in] : RSA generator
3674 @param cn [in] : Common name field of X509 certificate.
3675 @param serial [in] : Certificate serial number
3676 @param cert_filename [in] : File name for X509 certificate
3677 @param key_filename [in] : File name for private key
3678 @param filecr [in] : File creator
3679 @param ca_key_file [in] : CA private key file
3680 @param ca_cert_file [in] : CA certificate file
3681
3682 @returns generation status
3683 @retval false : Error in key/certificate generation.
3684 @retval true : key/certificate files are generated successfully.
3685 */
3686
3687 template <typename RSA_generator_func, typename File_creation_func>
create_x509_certificate(RSA_generator_func & rsa_gen,const Sql_string_t cn,uint32_t serial,const Sql_string_t cert_filename,const Sql_string_t key_filename,File_creation_func & filecr,const Sql_string_t ca_key_file="",const Sql_string_t ca_cert_file="")3688 bool create_x509_certificate(RSA_generator_func &rsa_gen,
3689 const Sql_string_t cn,
3690 uint32_t serial,
3691 const Sql_string_t cert_filename,
3692 const Sql_string_t key_filename,
3693 File_creation_func &filecr,
3694 const Sql_string_t ca_key_file= "",
3695 const Sql_string_t ca_cert_file= "")
3696 {
3697 bool ret_val= true;
3698 bool self_sign= true;
3699 Sql_string_t ca_key_str;
3700 Sql_string_t ca_cert_str;
3701 RSA *rsa= NULL;
3702 EVP_PKEY *pkey= NULL;
3703 EVP_PKEY *ca_key= NULL;
3704 X509 *x509= NULL;
3705 X509 *ca_x509= NULL;
3706 File_IO *x509_key_file_ostream= NULL;
3707 File_IO *x509_cert_file_ostream= NULL;
3708 File_IO *x509_ca_key_file_istream= NULL;
3709 File_IO *x509_ca_cert_file_istream= NULL;
3710 X509_gen x509_gen;
3711 MY_MODE file_creation_mode= get_file_perm(USER_READ | USER_WRITE);
3712 MY_MODE saved_umask= umask(~(file_creation_mode));
3713
3714 x509_key_file_ostream= filecr(key_filename);
3715
3716 /* Generate private key for X509 certificate */
3717 rsa= rsa_gen();
3718 DBUG_EXECUTE_IF("null_rsa_error",
3719 {
3720 RSA_free(rsa);
3721 rsa= NULL;
3722 });
3723
3724 if (!rsa)
3725 {
3726 sql_print_error("Could not generate RSA private key "
3727 "required for X509 certificate.");
3728 ret_val= false;
3729 goto end;
3730 }
3731
3732 /* Obtain EVP_PKEY */
3733 pkey= evp_pkey_generate(rsa);
3734
3735 /* Write private key information to file and set file permission */
3736 (*x509_key_file_ostream) << x509_key_write(pkey);
3737 DBUG_EXECUTE_IF("key_file_write_error",
3738 {
3739 x509_key_file_ostream->set_error();
3740 });
3741 if (x509_key_file_ostream->get_error())
3742 {
3743 sql_print_error("Could not write key file: %s", key_filename.c_str());
3744 ret_val= false;
3745 goto end;
3746 }
3747
3748 if (MY_TEST(my_chmod(key_filename.c_str(),
3749 USER_READ|USER_WRITE, MYF(MY_FAE+MY_WME))))
3750 {
3751 sql_print_error("Could not set file permission for %s",
3752 key_filename.c_str());
3753 ret_val= false;
3754 goto end;
3755 }
3756
3757 /*
3758 Read CA key/certificate files in PEM format.
3759 */
3760 if (ca_key_file.size() && ca_cert_file.size())
3761 {
3762 x509_ca_key_file_istream= filecr(ca_key_file, true);
3763 x509_ca_cert_file_istream= filecr(ca_cert_file, true);
3764 (*x509_ca_key_file_istream) >> ca_key_str;
3765 ca_key= x509_key_read(ca_key_str);
3766 DBUG_EXECUTE_IF("ca_key_read_error",
3767 {
3768 EVP_PKEY_free(ca_key);
3769 ca_key= NULL;
3770 });
3771 if (!ca_key)
3772 {
3773 sql_print_error("Could not read CA key file: %s", ca_key_file.c_str());
3774 ret_val= false;
3775 goto end;
3776 }
3777
3778 (*x509_ca_cert_file_istream) >> ca_cert_str;
3779 ca_x509= x509_cert_read(ca_cert_str);
3780 DBUG_EXECUTE_IF("ca_cert_read_error",
3781 {
3782 X509_free(ca_x509);
3783 ca_x509= NULL;
3784 });
3785 if (!ca_x509)
3786 {
3787 sql_print_error("Could not read CA certificate file: %s", ca_cert_file.c_str());
3788 ret_val= false;
3789 goto end;
3790 }
3791
3792 self_sign= false;
3793 }
3794
3795 /* Create X509 certificate with validity of 10 year */
3796 x509= x509_gen(pkey, cn, serial, 0, 365L*24*60*60*10,
3797 self_sign, ca_x509, ca_key);
3798 DBUG_EXECUTE_IF("x509_cert_generation_error",
3799 {
3800 X509_free(x509);
3801 x509= NULL;
3802 });
3803 if (!x509)
3804 {
3805 sql_print_error("Could not generate X509 certificate.");
3806 ret_val= false;
3807 goto end;
3808 }
3809
3810 /* Write X509 certificate to file and set permission */
3811 x509_cert_file_ostream= filecr(cert_filename);
3812 (*x509_cert_file_ostream)<< x509_cert_write(x509);
3813 DBUG_EXECUTE_IF("cert_pub_key_write_error",
3814 {
3815 x509_cert_file_ostream->set_error();
3816 });
3817 if (x509_cert_file_ostream->get_error())
3818 {
3819 sql_print_error("Could not write certificate file: %s", cert_filename.c_str());
3820 ret_val= false;
3821 goto end;
3822 }
3823
3824 if (MY_TEST(my_chmod(cert_filename.c_str(),
3825 USER_READ|USER_WRITE|GROUP_READ|OTHERS_READ,
3826 MYF(MY_FAE+MY_WME))))
3827 {
3828 sql_print_error("Could not set file permission for %s",
3829 cert_filename.c_str());
3830 ret_val= false;
3831 goto end;
3832 }
3833
3834 end:
3835
3836 if (pkey)
3837 EVP_PKEY_free(pkey); /* Frees rsa too */
3838 if (ca_key)
3839 EVP_PKEY_free(ca_key);
3840 if (x509)
3841 X509_free(x509);
3842 if (ca_x509)
3843 X509_free(ca_x509);
3844
3845 umask(saved_umask);
3846 return ret_val;
3847 }
3848
3849
3850 /*
3851 Algorithm to generate RSA key pair.
3852 Relies on:
3853 1> RSA generator
3854 2> File reader/writer
3855
3856 Overwrites existing Private/Public key file if any.
3857
3858 @param rsa_gen [in] : RSA key pair generator
3859 @param priv_key_filename [in] : File name of private key
3860 @param pub_key_filename [in] : File name of public key
3861 @param filecr [in] : File creator
3862
3863 @returns status of RSA key pair generation.
3864 @retval false Error in RSA key pair generation.
3865 @retval true Private/Public keys are successfully generated.
3866 */
3867 template <typename RSA_generator_func, typename File_creation_func>
create_RSA_key_pair(RSA_generator_func & rsa_gen,const Sql_string_t priv_key_filename,const Sql_string_t pub_key_filename,File_creation_func & filecr)3868 bool create_RSA_key_pair(RSA_generator_func &rsa_gen,
3869 const Sql_string_t priv_key_filename,
3870 const Sql_string_t pub_key_filename,
3871 File_creation_func &filecr)
3872 {
3873 bool ret_val= true;
3874 File_IO * priv_key_file_ostream= NULL;
3875 File_IO * pub_key_file_ostream= NULL;
3876 MY_MODE file_creation_mode= get_file_perm(USER_READ | USER_WRITE);
3877 MY_MODE saved_umask= umask(~(file_creation_mode));
3878
3879 assert(priv_key_filename.size() && pub_key_filename.size());
3880
3881 RSA *rsa= rsa_gen();
3882 DBUG_EXECUTE_IF("null_rsa_error",
3883 {
3884 RSA_free(rsa);
3885 rsa= NULL;
3886 });
3887
3888 if (!rsa)
3889 {
3890 sql_print_error("Could not generate RSA Private/Public key pair");
3891 ret_val= false;
3892 goto end;
3893 }
3894
3895 priv_key_file_ostream= filecr(priv_key_filename);
3896 (*priv_key_file_ostream)<< rsa_priv_key_write(rsa);
3897
3898 DBUG_EXECUTE_IF("key_file_write_error",
3899 {
3900 priv_key_file_ostream->set_error();
3901 });
3902 if (priv_key_file_ostream->get_error())
3903 {
3904 sql_print_error("Could not write private key file: %s", priv_key_filename.c_str());
3905 ret_val= false;
3906 goto end;
3907 }
3908 if (MY_TEST(my_chmod(priv_key_filename.c_str(),
3909 USER_READ|USER_WRITE, MYF(MY_FAE+MY_WME))))
3910 {
3911 sql_print_error("Could not set file permission for %s",
3912 priv_key_filename.c_str());
3913 ret_val= false;
3914 goto end;
3915 }
3916
3917 pub_key_file_ostream= filecr(pub_key_filename);
3918 (*pub_key_file_ostream)<< rsa_pub_key_write(rsa);
3919 DBUG_EXECUTE_IF("cert_pub_key_write_error",
3920 {
3921 pub_key_file_ostream->set_error();
3922 });
3923
3924 if (pub_key_file_ostream->get_error())
3925 {
3926 sql_print_error("Could not write public key file: %s", pub_key_filename.c_str());
3927 ret_val= false;
3928 goto end;
3929 }
3930 if (MY_TEST(my_chmod(pub_key_filename.c_str(),
3931 USER_READ|USER_WRITE|GROUP_READ|OTHERS_READ,
3932 MYF(MY_FAE+MY_WME))))
3933 {
3934 sql_print_error("Could not set file permission for %s",
3935 pub_key_filename.c_str());
3936 ret_val= false;
3937 goto end;
3938 }
3939
3940 end:
3941 if (rsa)
3942 RSA_free(rsa);
3943
3944 umask(saved_umask);
3945 return ret_val;
3946 }
3947
3948
3949 /*
3950 Check auto_generate_certs option and generate
3951 SSL certificates if required.
3952
3953 SSL Certificates are generated iff following conditions are met.
3954 1> auto_generate_certs is set to ON.
3955 2> None of the SSL system variables are specified.
3956 3> Following files are not present in data directory.
3957 a> ca.pem
3958 b> server_cert.pem
3959 c> server_key.pem
3960
3961 If above mentioned conditions are satisfied, following action will be taken:
3962
3963 1> 6 File are generated and placed data directory:
3964 a> ca.pem
3965 b> ca_key.pem
3966 c> server_cert.pem
3967 d> server_key.pem
3968 e> client_cert.pem
3969 f> client_key.pem
3970
3971 ca.pem is self signed auto generated CA certificate. server_cert.pem
3972 and client_cert.pem are signed using auto genreated CA.
3973
3974 ca_key.pem, client_cert.pem and client_key.pem are overwritten if
3975 they are present in data directory.
3976
3977 Path of following system variables are set if certificates are either
3978 generated or already present in data directory.
3979 a> ssl-ca
3980 b> ssl-cert
3981 c> ssl-key
3982
3983 Assumption : auto_detect_ssl() is called before control reaches to
3984 do_auto_cert_generation().
3985
3986 @param auto_detection_status [IN] Status of SSL artifacts detection process
3987
3988 @returns
3989 @retval true i Generation is successful or skipped
3990 @retval false Generation failed.
3991 */
do_auto_cert_generation(ssl_artifacts_status auto_detection_status)3992 bool do_auto_cert_generation(ssl_artifacts_status auto_detection_status)
3993 {
3994 if (opt_auto_generate_certs == true)
3995 {
3996 /*
3997 Do not generate SSL certificates/RSA keys,
3998 If any of the SSL option was specified.
3999 */
4000
4001 if (auto_detection_status == SSL_ARTIFACTS_VIA_OPTIONS)
4002 {
4003 sql_print_information("Skipping generation of SSL certificates "
4004 "as options related to SSL are specified.");
4005 return true;
4006 }
4007 else if(auto_detection_status == SSL_ARTIFACTS_AUTO_DETECTED ||
4008 auto_detection_status == SSL_ARTIFACT_TRACES_FOUND)
4009 {
4010 sql_print_information("Skipping generation of SSL certificates as "
4011 "certificate files are present in data "
4012 "directory.");
4013 return true;
4014 }
4015 else
4016 {
4017 assert(auto_detection_status == SSL_ARTIFACTS_NOT_FOUND);
4018 /* Initialize the key pair generator. It can also be used stand alone */
4019 RSA_gen rsa_gen;
4020 /*
4021 Initialize the file creator.
4022 */
4023 File_creator fcr;
4024 Sql_string_t ca_name= "MySQL_Server_";
4025 Sql_string_t server_name= "MySQL_Server_";
4026 Sql_string_t client_name= "MySQL_Server_";
4027
4028 ca_name.append(MYSQL_SERVER_VERSION);
4029 ca_name.append("_Auto_Generated_CA_Certificate");
4030 server_name.append(MYSQL_SERVER_VERSION);
4031 server_name.append("_Auto_Generated_Server_Certificate");
4032 client_name.append(MYSQL_SERVER_VERSION);
4033 client_name.append("_Auto_Generated_Client_Certificate");
4034
4035 /*
4036 Maximum length of X509 certificate subject is 64.
4037 Make sure that constructed strings are within valid
4038 bounds or change them to minimal default strings
4039 */
4040 if (ca_name.length() > MAX_CN_NAME_LENGTH ||
4041 server_name.length() > MAX_CN_NAME_LENGTH ||
4042 client_name.length() > MAX_CN_NAME_LENGTH)
4043 {
4044 ca_name.clear();
4045 ca_name.append("MySQL_Server_Auto_Generated_CA_Certificate");
4046 server_name.clear();
4047 server_name.append("MySQL_Server_Auto_Generated_Server_Certificate");
4048 client_name.clear();
4049 client_name.append("MySQL_Server_Auto_Generated_Client_Certificate");
4050 }
4051
4052 /* Create and write the certa and keys on disk */
4053 if ((create_x509_certificate(rsa_gen, ca_name, 1, DEFAULT_SSL_CA_CERT,
4054 DEFAULT_SSL_CA_KEY, fcr) == false) ||
4055 (create_x509_certificate(rsa_gen, server_name, 2,
4056 DEFAULT_SSL_SERVER_CERT,
4057 DEFAULT_SSL_SERVER_KEY, fcr,
4058 DEFAULT_SSL_CA_KEY,
4059 DEFAULT_SSL_CA_CERT) == false) ||
4060 (create_x509_certificate(rsa_gen, client_name, 3,
4061 DEFAULT_SSL_CLIENT_CERT,
4062 DEFAULT_SSL_CLIENT_KEY, fcr,
4063 DEFAULT_SSL_CA_KEY,
4064 DEFAULT_SSL_CA_CERT) == false))
4065 {
4066 return false;
4067 }
4068 opt_ssl_ca= (char *)DEFAULT_SSL_CA_CERT;
4069 opt_ssl_cert= (char *)DEFAULT_SSL_SERVER_CERT;
4070 opt_ssl_key= (char *)DEFAULT_SSL_SERVER_KEY;
4071 sql_print_information("Auto generated SSL certificates are placed "
4072 "in data directory.");
4073 }
4074 return true;
4075 }
4076 else
4077 {
4078 sql_print_information("Skipping generation of SSL certificates as "
4079 "--auto_generate_certs is set to OFF.");
4080 return true;
4081 }
4082 }
4083
4084
4085 /*
4086 Check sha256_password_auto_generate_rsa_keys option and generate
4087 RSA key pair if required.
4088
4089 RSA key pair is generated iff following conditions are met.
4090 1> sha256_password_auto_generate_rsa_keys is set to ON.
4091 2> sha256_password_private_key_path or sha256_password_public_key_path
4092 are pointing to non-default locations.
4093 3> Following files are not present in data directory.
4094 a> private_key.pem
4095 b> public_key.pem
4096
4097 If above mentioned conditions are satified private_key.pem and
4098 public_key.pem files are generated and placed in data directory.
4099 */
do_auto_rsa_keys_generation()4100 static bool do_auto_rsa_keys_generation()
4101 {
4102 if (auth_rsa_auto_generate_rsa_keys == true)
4103 {
4104 MY_STAT priv_stat, pub_stat;
4105 if (strcmp(auth_rsa_private_key_path, AUTH_DEFAULT_RSA_PRIVATE_KEY) ||
4106 strcmp(auth_rsa_public_key_path, AUTH_DEFAULT_RSA_PUBLIC_KEY))
4107 {
4108 sql_print_information("Skipping generation of RSA key pair as "
4109 "options related to RSA keys are specified.");
4110 return true;
4111 }
4112 else if (my_stat(AUTH_DEFAULT_RSA_PRIVATE_KEY, &priv_stat, MYF(0)) ||
4113 my_stat(AUTH_DEFAULT_RSA_PUBLIC_KEY, &pub_stat, MYF(0)))
4114 {
4115 sql_print_information("Skipping generation of RSA key pair as "
4116 "key files are present in data directory.");
4117 return true;
4118 }
4119 else
4120 {
4121 /* Initialize the key pair generator. */
4122 RSA_gen rsa_gen;
4123 /* Initialize the file creator. */
4124 File_creator fcr;
4125
4126 if (create_RSA_key_pair(rsa_gen, "private_key.pem", "public_key.pem",
4127 fcr) == false)
4128 return false;
4129
4130 sql_print_information("Auto generated RSA key files are "
4131 "placed in data directory.");
4132 return true;
4133 }
4134 }
4135 else
4136 {
4137 sql_print_information("Skipping generation of RSA key pair as "
4138 "--sha256_password_auto_generate_rsa_keys "
4139 "is set to OFF.");
4140 return true;
4141 }
4142 }
4143 #endif /* HAVE_OPENSSL */
4144
can_authenticate()4145 bool MPVIO_EXT::can_authenticate()
4146 {
4147 return (acl_user && acl_user->can_authenticate);
4148 }
4149
4150 static struct st_mysql_auth native_password_handler=
4151 {
4152 MYSQL_AUTHENTICATION_INTERFACE_VERSION,
4153 native_password_plugin_name.str,
4154 native_password_authenticate,
4155 generate_native_password,
4156 validate_native_password_hash,
4157 set_native_salt,
4158 AUTH_FLAG_USES_INTERNAL_STORAGE
4159 };
4160
4161 #if defined(HAVE_OPENSSL)
4162 static struct st_mysql_auth sha256_password_handler=
4163 {
4164 MYSQL_AUTHENTICATION_INTERFACE_VERSION,
4165 sha256_password_plugin_name.str,
4166 sha256_password_authenticate,
4167 generate_sha256_password,
4168 validate_sha256_password_hash,
4169 set_sha256_salt,
4170 AUTH_FLAG_USES_INTERNAL_STORAGE
4171 };
4172
4173 #endif /* HAVE_OPENSSL */
4174
mysql_declare_plugin(mysql_password)4175 mysql_declare_plugin(mysql_password)
4176 {
4177 MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
4178 &native_password_handler, /* type descriptor */
4179 native_password_plugin_name.str, /* Name */
4180 "R.J.Silk, Sergei Golubchik", /* Author */
4181 "Native MySQL authentication", /* Description */
4182 PLUGIN_LICENSE_GPL, /* License */
4183 NULL, /* Init function */
4184 NULL, /* Deinit function */
4185 0x0101, /* Version (1.0) */
4186 NULL, /* status variables */
4187 NULL, /* system variables */
4188 NULL, /* config options */
4189 0, /* flags */
4190 }
4191 #if defined(HAVE_OPENSSL)
4192 ,
4193 {
4194 MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
4195 &sha256_password_handler, /* type descriptor */
4196 sha256_password_plugin_name.str, /* Name */
4197 "Oracle", /* Author */
4198 "SHA256 password authentication", /* Description */
4199 PLUGIN_LICENSE_GPL, /* License */
4200 &init_sha256_password_handler, /* Init function */
4201 NULL, /* Deinit function */
4202 0x0101, /* Version (1.0) */
4203 NULL, /* status variables */
4204 sha256_password_sysvars, /* system variables */
4205 NULL, /* config options */
4206 0 /* flags */
4207 }
4208 #endif /* HAVE_OPENSSL */
4209 mysql_declare_plugin_end;
4210
4211