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