1 /* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include <openssl/ossl_typ.h>
24 #include "mysql/plugin_auth_common.h"
25 #include "mysql_async.h"
26 
27 /* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
28 struct MCPVIO_EXT {
29   int (*read_packet)(MYSQL_PLUGIN_VIO *vio, uchar **buf);
30   int (*write_packet)(MYSQL_PLUGIN_VIO *vio, const uchar *pkt, int pkt_len);
31   void (*info)(MYSQL_PLUGIN_VIO *vio, MYSQL_PLUGIN_VIO_INFO *info);
32   net_async_status (*read_packet_nonblocking)(struct MYSQL_PLUGIN_VIO *vio,
33                                               unsigned char **buf, int *result);
34   net_async_status (*write_packet_nonblocking)(struct MYSQL_PLUGIN_VIO *vio,
35                                                const unsigned char *pkt,
36                                                int pkt_len, int *result);
37 
38   /* -= end of MYSQL_PLUGIN_VIO =- */
39   MYSQL *mysql;
40   auth_plugin_t *plugin; /**< what plugin we're under */
41   const char *db;
42   struct {
43     uchar *pkt; /**< pointer into NET::buff */
44     uint pkt_len;
45   } cached_server_reply;
46   int packets_read, packets_written; /**< counters for send/received packets */
47   int mysql_change_user;             /**< if it's mysql_change_user() */
48   int last_read_packet_len; /**< the length of the last *read* packet */
49 };
50 
51 /* Our state machines have four simple return codes: */
52 enum mysql_state_machine_status {
53   STATE_MACHINE_FAILED,      /* Completion with a failure. */
54   STATE_MACHINE_CONTINUE,    /* Keep calling the state machine. */
55   STATE_MACHINE_WOULD_BLOCK, /* Needs to block to continue. */
56   STATE_MACHINE_DONE         /* Completion with a success. */
57 };
58 
59 /* state machine for native password autheintication API */
60 enum client_auth_native_password_plugin_status {
61   NATIVE_READING_PASSWORD = 1,
62   NATIVE_WRITING_RESPONSE
63 };
64 
65 enum client_auth_sha256_password_plugin_status {
66   SHA256_READING_PASSWORD = 1,
67   SHA256_REQUEST_PUBLIC_KEY,
68   SHA256_READ_PUBLIC_KEY,
69   SHA256_SEND_ENCRYPTED_PASSWORD,
70   SHA256_SEND_PLAIN_PASSWORD
71 };
72 
73 enum client_auth_caching_sha2_password_plugin_status {
74   CACHING_SHA2_READING_PASSWORD = 1,
75   CACHING_SHA2_WRITING_RESPONSE,
76   CACHING_SHA2_CHALLENGE_RESPONSE,
77   CACHING_SHA2_REQUEST_PUBLIC_KEY,
78   CACHING_SHA2_READ_PUBLIC_KEY,
79   CACHING_SHA2_SEND_ENCRYPTED_PASSWORD,
80   CACHING_SHA2_SEND_PLAIN_PASSWORD
81 };
82 
83 /* A state machine for authentication itself. */
84 struct mysql_async_auth;
85 typedef mysql_state_machine_status (*authsm_function)(mysql_async_auth *);
86 
87 struct mysql_async_auth {
88   MYSQL *mysql;
89   bool non_blocking;
90 
91   char *data;
92   uint data_len;
93   const char *data_plugin;
94   const char *db;
95 
96   const char *auth_plugin_name;
97   auth_plugin_t *auth_plugin;
98   MCPVIO_EXT mpvio;
99   ulong pkt_length;
100   int res;
101 
102   char *change_user_buff;
103   int change_user_buff_len;
104 
105   int client_auth_plugin_state;
106   authsm_function state_function;
107 };
108 
109 /*
110   Connection is handled with a state machine.  Each state is
111   represented by a function pointer (csm_function) which returns
112   a mysql_state_machine_status to indicate the state of the
113   connection.
114   This state machine has boundaries around network IO to allow
115   reuse between blocking and non-blocking clients.
116 */
117 struct mysql_async_connect;
118 typedef mysql_state_machine_status (*csm_function)(mysql_async_connect *);
119 
120 /*
121   define different states of an asynchronous SSL connection phase
122 */
123 enum ssl_exchange_state {
124   SSL_REQUEST = 8100,
125   SSL_CONNECT = 8101,
126   SSL_COMPLETE = 8102,
127   SSL_NONE = 8103
128 };
129 
130 /*
131   Struct to track the state of a connection being established.  Once
132   the connection is established, the context should be discarded and
133   relevant values copied out of it.
134 */
135 struct mysql_async_connect {
136   /* state for the overall connection process */
137   MYSQL *mysql;
138   const char *host;
139   const char *user;
140   const char *passwd;
141   const char *db;
142   uint port;
143   const char *unix_socket;
144   ulong client_flag;
145   bool non_blocking;
146 
147   ulong pkt_length;
148   char *host_info;
149   char buff[NAME_LEN + USERNAME_LENGTH + 100];
150   int scramble_data_len;
151   char *scramble_data;
152   const char *scramble_plugin;
153   char *scramble_buffer;
154   bool scramble_buffer_allocated;
155 
156   /* context needed to establish asynchronous authentication */
157   struct mysql_async_auth *auth_context;
158   /* state for running init_commands */
159   bool saved_reconnect;
160   char **current_init_command;
161 
162   ssl_exchange_state ssl_state;
163   SSL *ssl;
164   /* state function that will be called next */
165   csm_function state_function;
166 };
167