-
Notifications
You must be signed in to change notification settings - Fork 1k
/
Copy pathMySQL_Protocol.h
242 lines (217 loc) · 11.4 KB
/
MySQL_Protocol.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#ifndef __CLASS_MYSQL_PROTOCOL_H
#define __CLASS_MYSQL_PROTOCOL_H
#include "proxysql.h"
#include "cpp.h"
#include "MySQL_Variables.h"
#include "MySQL_Prepared_Stmt_info.h"
#define RESULTSET_BUFLEN 16300
extern MySQL_Variables mysql_variables;
/** @brief Forward declaration. */
typedef struct _account_details_t account_details_t;
/* The default mariadb-connecter 3.1.4 does not yet implement CLIENT_DEPRECATE_EOF
* flag.
*/
#ifndef CLIENT_DEPRECATE_EOF
#define CLIENT_DEPRECATE_EOF (1UL << 24)
#endif
enum proxysql_auth_plugins {
AUTH_UNKNOWN_PLUGIN = -1,
AUTH_MYSQL_NATIVE_PASSWORD = 0,
AUTH_MYSQL_CLEAR_PASSWORD,
AUTH_MYSQL_CACHING_SHA2_PASSWORD
};
class MySQL_ResultSet {
private:
bool deprecate_eof_active;
public:
bool transfer_started;
bool resultset_completed;
//bool reset_pid;
uint8_t sid;
MySQL_Data_Stream *myds;
MySQL_Protocol *myprot;
MYSQL *mysql;
MYSQL_RES *result;
MYSQL_STMT *stmt;
unsigned int num_fields;
unsigned long long num_rows;
unsigned long long resultset_size;
PtrSizeArray PSarrayOUT;
//PtrSizeArray *PSarrayOUT;
MySQL_ResultSet();
void init(MySQL_Protocol *_myprot, MYSQL_RES *_res, MYSQL *_my, MYSQL_STMT *_stmt=NULL);
void init_with_stmt(MySQL_Connection *myconn);
/**
* @brief Simple initialization of resulset of 'MySQL_ResultSet' without a resulset.
* @details This initialization allows to reuse the logic from function 'generate_pkt_row3' for filling
* the resulset for later extracting the generated 'PtrSizeArray' via 'buffer_to_PSarrayOut' and
* 'get_resultset'.
*
* IMPORTANT-NOTE: Other member functions are not safe to be used after this initialization.
* @param myproto Used to initialize internal 'MySQL_Protocol' field.
*/
void buffer_init(MySQL_Protocol* myproto);
~MySQL_ResultSet();
unsigned int add_row(MYSQL_ROWS *rows);
unsigned int add_row(MYSQL_ROW row);
unsigned int add_row2(MYSQL_ROWS *row, unsigned char *offset);
void add_eof(bool suppress_warning_count=false);
void remove_last_eof();
void add_err(MySQL_Data_Stream *_myds);
bool get_resultset(PtrSizeArray *PSarrayFinal);
//bool generate_COM_FIELD_LIST_response(PtrSizeArray *PSarrayFinal);
unsigned char *buffer;
unsigned int buffer_used;
void buffer_to_PSarrayOut(bool _last=false);
unsigned long long current_size();
};
uint8_t mysql_decode_length(unsigned char *ptr, uint64_t *len);
/**
* @brief ProxySQL replacement function for 'mysql_stmt_close'. Closes a
* MYSQL_STMT avoiding any blocking commands that are sent by default
* 'mysql_stmt_close'.
*
* NOTE: This function is not safe, caller must check that the supplied
* argument is not NULL.
*
* @param mysql_stmt An already initialized 'MYSQL_STMT'. Caller must ensure
* that the supplied argument is not NULL.
*
* @return The result of calling 'mysql_stmt_close' function over the internally
* modified 'MYSQL_STMT'.
*/
my_bool proxy_mysql_stmt_close(MYSQL_STMT* mysql_stmt);
class MyProt_tmp_auth_vars {
public:
unsigned char *user = NULL;
char *db = NULL;
char *db_tmp = NULL;
unsigned char *pass = NULL;
char* password { nullptr };
PASSWORD_TYPE::E passtype = PASSWORD_TYPE::PRIMARY;
unsigned char *auth_plugin = NULL;
void *sha1_pass=NULL;
unsigned char *_ptr = NULL;;
unsigned int charset;
uint32_t capabilities = 0;
uint32_t max_pkt;
uint32_t pass_len;
bool use_ssl = false;
enum proxysql_session_type session_type;
};
class MyProt_tmp_auth_attrs {
public:
char *default_schema = NULL;
char *attributes = NULL;
int default_hostgroup=-1;
int max_connections;
bool schema_locked;
bool transaction_persistent = true;
bool fast_forward = false;
bool _ret_use_ssl = false;
};
class MySQL_Protocol {
private:
MySQL_Connection_userinfo *userinfo;
MySQL_Session *sess;
public:
MySQL_Data_Stream **myds;
#ifdef DEBUG
bool dump_pkt;
#endif
MySQL_Prepared_Stmt_info *current_PreStmt;
enum proxysql_auth_plugins sent_auth_plugin_id;
enum proxysql_auth_plugins auth_plugin_id;
uint16_t prot_status;
bool more_data_needed;
MySQL_Data_Stream *get_myds() { return *myds; }
MySQL_Protocol() {
sent_auth_plugin_id = AUTH_MYSQL_NATIVE_PASSWORD;
auth_plugin_id = AUTH_UNKNOWN_PLUGIN;
prot_status=0;
more_data_needed = false;
}
void init(MySQL_Data_Stream **, MySQL_Connection_userinfo *, MySQL_Session *);
// members get as arguments:
// - a data stream (optionally NULL for some)
// - a boolean variable to indicate whatever the packet needs to be sent directly in the data stream
// - a pointer to void pointer, used to return the packet if not NULL
// - a pointer to unsigned int, used to return the size of the packet if not NULL
// for now, they all return true
bool generate_pkt_OK(bool send, void **ptr, unsigned int *len, uint8_t sequence_id, unsigned int affected_rows, uint64_t last_insert_id, uint16_t status, uint16_t warnings, char *msg, bool eof_identifier=false);
bool generate_pkt_ERR(bool send, void **ptr, unsigned int *len, uint8_t sequence_id, uint16_t error_code, char *sql_state, const char *sql_message, bool track=false);
bool generate_pkt_EOF(bool send, void **ptr, unsigned int *len, uint8_t sequence_id, uint16_t warnings, uint16_t status, MySQL_ResultSet *myrs=NULL);
// bool generate_COM_INIT_DB(bool send, void **ptr, unsigned int *len, char *schema);
//bool generate_COM_PING(bool send, void **ptr, unsigned int *len);
bool generate_pkt_auth_switch_request(bool send, void **ptr, unsigned int *len);
bool process_pkt_auth_swich_response(unsigned char *pkt, unsigned int len);
// bool generate_pkt_column_count(MySQL_Data_Stream *myds, bool send, void **ptr, unsigned int *len, uint8_t sequence_id, uint64_t count);
bool generate_pkt_column_count(bool send, void **ptr, unsigned int *len, uint8_t sequence_id, uint64_t count, MySQL_ResultSet *myrs=NULL);
// bool generate_pkt_field(MySQL_Data_Stream *myds, bool send, void **ptr, unsigned int *len, uint8_t sequence_id, char *schema, char *table, char *org_table, char *name, char *org_name, uint16_t charset, uint32_t column_length, uint8_t type, uint16_t flags, uint8_t decimals, bool field_list, uint64_t defvalue_length, char *defvalue);
bool generate_pkt_field2(void **ptr, unsigned int *len, uint8_t sequence_id, MYSQL_FIELD *field, MySQL_ResultSet *myrs);
bool generate_pkt_field(bool send, void **ptr, unsigned int *len, uint8_t sequence_id, char *schema, char *table, char *org_table, char *name, char *org_name, uint16_t charset, uint32_t column_length, uint8_t type, uint16_t flags, uint8_t decimals, bool field_list, uint64_t defvalue_length, char *defvalue, MySQL_ResultSet *myrs=NULL);
bool generate_pkt_row(bool send, void **ptr, unsigned int *len, uint8_t sequence_id, int colnums, unsigned long *fieldslen, char **fieldstxt);
uint8_t generate_pkt_row3(MySQL_ResultSet *myrs, unsigned int *len, uint8_t sequence_id, int colnums, unsigned long *fieldslen, char **fieldstxt, unsigned long rl);
virtual bool generate_pkt_initial_handshake(bool send, void **ptr, unsigned int *len, uint32_t *thread_id, bool deprecate_eof_active);
// bool generate_statistics_response(MySQL_Data_Stream *myds, bool send, void **ptr, unsigned int *len);
bool generate_statistics_response(bool send, void **ptr, unsigned int *len);
// process_* members get a arguments:
// - a data stream (optionally NULL for some)
// - pointer to the packet
// - size of the packet
bool process_pkt_handshake_response(unsigned char *pkt, unsigned int len);
// all the following functions were inline inside process_pkt_handshake_response() , but it was split for readibility
int PPHR_1(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1);
bool PPHR_2(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1);
void PPHR_3(MyProt_tmp_auth_vars& vars1);
bool PPHR_4auth0(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1);
bool PPHR_4auth1(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1);
void PPHR_5passwordTrue(bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, account_details_t& attr1);
void PPHR_5passwordFalse_0(bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, account_details_t& attr1);
void PPHR_5passwordFalse_auth2(bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, account_details_t& attr1);
void PPHR_6auth2(bool& ret, MyProt_tmp_auth_vars& vars1);
bool PPHR_verify_sha2(MyProt_tmp_auth_vars& vars1, enum proxysql_auth_plugins passformat, PASSWORD_TYPE::E passtype);
void PPHR_sha2full(bool& ret, MyProt_tmp_auth_vars& vars1, enum proxysql_auth_plugins passformat, PASSWORD_TYPE::E passtype);
void PPHR_7auth1(bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, account_details_t& attr1);
void PPHR_7auth2(bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, account_details_t& attr1);
void PPHR_next_auth_stage(MyProt_tmp_auth_vars& vars1, PASSWORD_TYPE::E passtype);
void PPHR_SetConnAttrs(MyProt_tmp_auth_vars& vars1, account_details_t& attr1);
bool PPHR_verify_password(MyProt_tmp_auth_vars& vars1, account_details_t& account_details);
bool PPHR_verify_password_2(MyProt_tmp_auth_vars& vars1, account_details_t& account_details);
void generate_one_byte_pkt(unsigned char b);
bool process_pkt_COM_CHANGE_USER(unsigned char *pkt, unsigned int len);
void * Query_String_to_packet(uint8_t sid, std::string *s, unsigned int *l);
/**
* @brief Verifies the supplied 'user' and 'password' in order to authenticate an user. For
* doing so, it takes into account:
* * Current session type.
* * Current 'sha1' password for the user, reported by 'GloMyAuth' or 'GloClickHouseAuth'.
* * Current 'auth_plugin' being used for the session.
* * Username received sent by the client.
* * Password received sent by the client.
*
* @param session_type The session type inn which the authentication is taking place.
* @param password Pointer to the stored password for the supplied user.
* @param user Pointer to the user supplied by the client.
* @param pass Pointer to the password supplied by the client.
* @param pass_len Length of the supplied password received from the client.
* @param sha1_pass Pointer to sha1_pass returned by auth cache.
* @param auth_plugin Auth plugin supplied by client in the COM_CHANGE_USER packet. If
* the packet doesn't hold any, 'mysql_native_password' should be supplied
* as default.
*
* @details TODO: This function holds the same authentication block that can be seen in
* "MySQL_Protocol::process_pkt_handshake_response". That portion of the function should be
* refactored into using this very same function.
* @return Returns 'true' if the user password was correctly verified, 'false' otherwise.
*/
bool verify_user_pass(enum proxysql_session_type session_type, const char* password, const char* user, const char* pass, int pass_len, const char* sha1_pass, const char* auth_plugin);
// prepared statements
bool generate_STMT_PREPARE_RESPONSE(uint8_t sequence_id, MySQL_STMT_Global_info *stmt_info, uint32_t _stmt_id=0);
void generate_STMT_PREPARE_RESPONSE_OK(uint8_t sequence_id, uint32_t stmt_id);
stmt_execute_metadata_t * get_binds_from_pkt(void *ptr, unsigned int size, MySQL_STMT_Global_info *stmt_info, stmt_execute_metadata_t **stmt_meta);
bool generate_COM_QUERY_from_COM_FIELD_LIST(PtrSize_t *pkt);
bool verify_user_attributes(int calling_line, const char *calling_func, const unsigned char *user);
bool user_attributes_has_spiffe(int calling_line, const char *calling_func, const unsigned char *user);
};
#endif /* __CLASS_MYSQL_PROTOCOL_H */