mirror of
https://gitee.com/wangbin579/cetus.git
synced 2024-12-02 03:47:41 +08:00
implement server-side auth switch, now mysql8 client can login
This commit is contained in:
parent
0b8bc3cf97
commit
dea8ae911d
@ -111,7 +111,7 @@ NETWORK_MYSQLD_PLUGIN_PROTO(server_con_init)
|
||||
challenge->server_version_str = g_strdup_printf("%s admin", PACKAGE_STRING);
|
||||
challenge->server_version = 50099;
|
||||
challenge->charset = charset_get_number("latin1");
|
||||
challenge->capabilities = CETUS_DEFAULT_FLAGS;
|
||||
challenge->capabilities = CETUS_DEFAULT_FLAGS & ~CLIENT_TRANSACTIONS;
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (chas->ssl) {
|
||||
challenge->capabilities |= CLIENT_SSL;
|
||||
@ -155,30 +155,50 @@ NETWORK_MYSQLD_PLUGIN_PROTO(server_read_auth)
|
||||
/* decode the packet */
|
||||
network_mysqld_proto_skip_network_header(&packet);
|
||||
|
||||
auth = network_mysqld_auth_response_new(con->client->challenge->capabilities);
|
||||
if (network_mysqld_proto_get_auth_response(&packet, auth)) {
|
||||
network_mysqld_auth_response_free(auth);
|
||||
return NETWORK_SOCKET_ERROR;
|
||||
}
|
||||
if (!(auth->client_capabilities & CLIENT_PROTOCOL_41)) {
|
||||
/* should use packet-id 0 */
|
||||
network_mysqld_queue_append(con->client, con->client->send_queue,
|
||||
C("\xff\xd7\x07" "4.0 protocol is not supported"));
|
||||
network_mysqld_auth_response_free(auth);
|
||||
return NETWORK_SOCKET_ERROR;
|
||||
}
|
||||
if (con->client->response == NULL) {
|
||||
auth = network_mysqld_auth_response_new(con->client->challenge->capabilities);
|
||||
if (network_mysqld_proto_get_auth_response(&packet, auth)) {
|
||||
network_mysqld_auth_response_free(auth);
|
||||
return NETWORK_SOCKET_ERROR;
|
||||
}
|
||||
if (!(auth->client_capabilities & CLIENT_PROTOCOL_41)) {
|
||||
/* should use packet-id 0 */
|
||||
network_mysqld_queue_append(con->client, con->client->send_queue,
|
||||
C("\xff\xd7\x07" "4.0 protocol is not supported"));
|
||||
network_mysqld_auth_response_free(auth);
|
||||
return NETWORK_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (auth->ssl_request) {
|
||||
network_ssl_create_connection(con->client, NETWORK_SSL_SERVER);
|
||||
g_string_free(g_queue_pop_tail(con->client->recv_queue->chunks), TRUE);
|
||||
con->state = ST_FRONT_SSL_HANDSHAKE;
|
||||
return NETWORK_SOCKET_SUCCESS;
|
||||
}
|
||||
if (auth->ssl_request) {
|
||||
network_ssl_create_connection(con->client, NETWORK_SSL_SERVER);
|
||||
g_string_free(g_queue_pop_tail(con->client->recv_queue->chunks), TRUE);
|
||||
con->state = ST_FRONT_SSL_HANDSHAKE;
|
||||
return NETWORK_SOCKET_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
con->client->response = auth;
|
||||
|
||||
con->client->response = auth;
|
||||
|
||||
if (g_strcmp0(auth->auth_plugin_name->str, "mysql_native_password") != 0) {
|
||||
GString *packet = g_string_new(0);
|
||||
network_mysqld_proto_append_auth_switch(packet, "mysql_native_password",
|
||||
con->client->challenge->auth_plugin_data);
|
||||
network_mysqld_queue_append(con->client, con->client->send_queue, S(packet));
|
||||
con->state = ST_SEND_AUTH_RESULT;
|
||||
con->auth_result_state = AUTH_SWITCH;
|
||||
g_string_free(packet, TRUE);
|
||||
g_string_free(g_queue_pop_tail(recv_sock->recv_queue->chunks), TRUE);
|
||||
return NETWORK_SOCKET_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
/* auth switch response */
|
||||
gsize auth_data_len = packet.data->len - 4;
|
||||
GString *auth_data = g_string_sized_new(auth_data_len);
|
||||
network_mysqld_proto_get_gstr_len(&packet, auth_data_len, auth_data);
|
||||
g_string_append_len(con->client->response->auth_plugin_data, S(auth_data));
|
||||
g_string_free(auth_data, TRUE);
|
||||
auth = con->client->response;
|
||||
}
|
||||
/* Check client addr in admin-allow-ip and admin-deny-ip */
|
||||
gboolean check_ip;
|
||||
char *ip_err_msg = NULL;
|
||||
|
@ -1118,7 +1118,6 @@ network_mysqld_auth_challenge_new()
|
||||
shake = g_new0(network_mysqld_auth_challenge, 1);
|
||||
|
||||
shake->auth_plugin_data = g_string_new("");
|
||||
shake->scrambled_password = g_string_new("");
|
||||
shake->capabilities = CETUS_DEFAULT_FLAGS;
|
||||
shake->auth_plugin_name = g_string_new(NULL);
|
||||
|
||||
@ -1135,8 +1134,6 @@ network_mysqld_auth_challenge_free(network_mysqld_auth_challenge *shake)
|
||||
g_free(shake->server_version_str);
|
||||
if (shake->auth_plugin_data)
|
||||
g_string_free(shake->auth_plugin_data, TRUE);
|
||||
if (shake->scrambled_password)
|
||||
g_string_free(shake->scrambled_password, TRUE);
|
||||
if (shake->auth_plugin_name)
|
||||
g_string_free(shake->auth_plugin_name, TRUE);
|
||||
|
||||
@ -1179,8 +1176,19 @@ network_mysqld_auth_challenge_set_challenge(network_mysqld_auth_challenge *shake
|
||||
shake->auth_plugin_data->str[i] = (94.0 * (rand() / (RAND_MAX + 1.0))) + 33;
|
||||
}
|
||||
|
||||
shake->auth_plugin_data->len = 20;
|
||||
shake->auth_plugin_data->len = 21;
|
||||
shake->auth_plugin_data->str[shake->auth_plugin_data->len] = '\0';
|
||||
g_string_assign(shake->auth_plugin_name, "mysql_native_password");
|
||||
}
|
||||
|
||||
int network_mysqld_proto_append_auth_switch(GString *packet, char *method_name, GString *salt)
|
||||
{
|
||||
network_mysqld_proto_append_int8(packet, 0xfe);
|
||||
/*TODO: different algorithm for methods */
|
||||
g_string_append_len(packet, method_name, strlen(method_name));
|
||||
g_string_append_c(packet, 0);
|
||||
g_string_append_len(packet, salt->str, salt->len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -95,16 +95,21 @@ typedef struct {
|
||||
#define CLIENT_PLUGIN_AUTH (1UL << 19)
|
||||
#endif
|
||||
|
||||
#define CETUS_DEFAULT_FLAGS CLIENT_BASIC_FLAGS \
|
||||
& ~CLIENT_PLUGIN_AUTH /* not support plugin auth */ \
|
||||
& ~CLIENT_NO_SCHEMA /* permit database.table.column */ \
|
||||
& ~CLIENT_IGNORE_SPACE \
|
||||
& ~CLIENT_CONNECT_ATTRS \
|
||||
& ~CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA \
|
||||
& ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS \
|
||||
& ~CLIENT_SESSION_TRACK \
|
||||
& ~CLIENT_DEPRECATE_EOF \
|
||||
& ~CLIENT_LOCAL_FILES
|
||||
#if MYSQL_VERSION_ID < 50606
|
||||
#define COMPATIBLE_BASIC_FLAGS (CLIENT_BASIC_FLAGS \
|
||||
|CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA \
|
||||
|CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS \
|
||||
|CLIENT_SESSION_TRACK)
|
||||
#else
|
||||
#define COMPATIBLE_BASIC_FLAGS CLIENT_BASIC_FLAGS
|
||||
#endif
|
||||
|
||||
#define CETUS_DEFAULT_FLAGS (COMPATIBLE_BASIC_FLAGS \
|
||||
& ~CLIENT_NO_SCHEMA /* permit database.table.column */ \
|
||||
& ~CLIENT_IGNORE_SPACE \
|
||||
& ~CLIENT_DEPRECATE_EOF \
|
||||
& ~CLIENT_LOCAL_FILES \
|
||||
& ~CLIENT_CONNECT_ATTRS)
|
||||
|
||||
NETWORK_API network_mysqld_com_query_result_t *network_mysqld_com_query_result_new(void);
|
||||
NETWORK_API void network_mysqld_com_query_result_free(network_mysqld_com_query_result_t *);
|
||||
@ -194,7 +199,6 @@ struct network_mysqld_auth_challenge {
|
||||
guint32 server_version;
|
||||
guint32 thread_id;
|
||||
GString *auth_plugin_data;
|
||||
GString *scrambled_password;
|
||||
guint32 capabilities;
|
||||
guint8 charset;
|
||||
guint16 server_status;
|
||||
@ -223,6 +227,7 @@ struct network_mysqld_auth_response {
|
||||
NETWORK_API network_mysqld_auth_response *network_mysqld_auth_response_new(guint server_capabilities);
|
||||
NETWORK_API void network_mysqld_auth_response_free(network_mysqld_auth_response *);
|
||||
NETWORK_API int network_mysqld_proto_append_auth_response(GString *, network_mysqld_auth_response *);
|
||||
int network_mysqld_proto_append_auth_switch(GString *, char *method_name, GString* salt);
|
||||
NETWORK_API int network_mysqld_proto_get_auth_response(network_packet *, network_mysqld_auth_response *);
|
||||
NETWORK_API int network_mysqld_proto_get_and_change_auth_response(network_packet *, network_mysqld_auth_response *);
|
||||
|
||||
|
@ -1166,18 +1166,14 @@ plugin_call(chassis *srv, network_mysqld_con *con, int state)
|
||||
*/
|
||||
switch (con->auth_result_state) {
|
||||
case MYSQLD_PACKET_OK:
|
||||
if (con->login_failed) {
|
||||
g_message("%s: clt login failed:%p", G_STRLOC, con);
|
||||
} else {
|
||||
/*
|
||||
* OK, delivered to client,
|
||||
* switch to command phase
|
||||
*/
|
||||
con->state = ST_READ_QUERY;
|
||||
if (con->is_client_compressed) {
|
||||
con->client->do_compress = 1;
|
||||
network_socket_set_send_buffer_size(con->client, COMPRESS_BUF_SIZE);
|
||||
}
|
||||
/*
|
||||
* OK, delivered to client,
|
||||
* switch to command phase
|
||||
*/
|
||||
con->state = ST_READ_QUERY;
|
||||
if (con->is_client_compressed) {
|
||||
con->client->do_compress = 1;
|
||||
network_socket_set_send_buffer_size(con->client, COMPRESS_BUF_SIZE);
|
||||
}
|
||||
break;
|
||||
case MYSQLD_PACKET_ERR:
|
||||
@ -1185,6 +1181,10 @@ plugin_call(chassis *srv, network_mysqld_con *con, int state)
|
||||
con->prev_state = con->state;
|
||||
con->state = ST_ERROR;
|
||||
break;
|
||||
case AUTH_SWITCH:
|
||||
con->auth_result_state = MYSQLD_PACKET_OK;
|
||||
con->state = ST_READ_AUTH;
|
||||
break;
|
||||
default:
|
||||
g_debug("%s: unexpected st for SEND_AUTH_RESULT: %02x", G_STRLOC, con->auth_result_state);
|
||||
con->prev_state = con->state;
|
||||
@ -4359,6 +4359,7 @@ proxy_self_create_auth(chassis *srv, server_connection_state_t *con)
|
||||
|
||||
const network_mysqld_auth_challenge *challenge = send_sock->challenge;
|
||||
network_mysqld_auth_response *auth = network_mysqld_auth_response_new(challenge->capabilities);
|
||||
g_string_assign(auth->auth_plugin_name, "mysql_native_password");
|
||||
|
||||
auth->client_capabilities = CETUS_DEFAULT_FLAGS;
|
||||
|
||||
@ -4373,8 +4374,6 @@ proxy_self_create_auth(chassis *srv, server_connection_state_t *con)
|
||||
auth->client_capabilities &= ~CLIENT_FOUND_ROWS;
|
||||
}
|
||||
|
||||
auth->client_capabilities &= ~CLIENT_PLUGIN_AUTH;
|
||||
|
||||
auth->max_packet_size = 0x01000000;
|
||||
auth->charset = con->charset_code;
|
||||
con->is_multi_stmt_set = 1;
|
||||
@ -4383,8 +4382,6 @@ proxy_self_create_auth(chassis *srv, server_connection_state_t *con)
|
||||
g_string_truncate(auth->auth_plugin_data, 0);
|
||||
network_mysqld_proto_password_scramble(auth->auth_plugin_data, S(challenge->auth_plugin_data), S(con->hashed_pwd));
|
||||
|
||||
g_string_assign_len(challenge->scrambled_password, S(auth->auth_plugin_data));
|
||||
|
||||
g_string_append_len(auth->database, S(send_sock->default_db));
|
||||
g_string_assign_len(auth->username, S(send_sock->username));
|
||||
g_debug("%s:username: %s ", G_STRLOC, send_sock->username->str);
|
||||
|
@ -385,6 +385,10 @@ typedef struct query_cache_item {
|
||||
} query_cache_item;
|
||||
|
||||
struct query_queue_t;
|
||||
|
||||
enum {
|
||||
AUTH_SWITCH = 3, /* for now, value not equal to 0 or 0xff is fine */
|
||||
};
|
||||
/**
|
||||
* get the name of a connection state
|
||||
*/
|
||||
@ -511,7 +515,6 @@ struct network_mysqld_con {
|
||||
|
||||
unsigned int is_wait_server:1; /* first connect to backend failed, retrying */
|
||||
unsigned int is_calc_found_rows:1;
|
||||
unsigned int login_failed:1;
|
||||
unsigned int is_auto_commit:1;
|
||||
unsigned int is_start_tran_command:1;
|
||||
unsigned int is_prepared:1;
|
||||
|
@ -81,11 +81,12 @@ do_read_auth(network_mysqld_con *con, GHashTable *allow_ip_table, GHashTable *de
|
||||
|
||||
packet.data = g_queue_peek_tail(recv_sock->recv_queue->chunks);
|
||||
packet.offset = 0;
|
||||
network_mysqld_proto_skip_network_header(&packet);
|
||||
|
||||
/* assume that we may get called twice:
|
||||
*
|
||||
* 1. for the initial packet
|
||||
* 2. for the win-auth extra data
|
||||
* 2. in case auth switch happened, for the auth switch response
|
||||
*
|
||||
* this is detected by con->client->response being NULL
|
||||
*/
|
||||
@ -99,8 +100,11 @@ do_read_auth(network_mysqld_con *con, GHashTable *allow_ip_table, GHashTable *de
|
||||
guint32 capabilities = con->client->challenge->capabilities;
|
||||
auth = network_mysqld_auth_response_new(capabilities);
|
||||
|
||||
network_mysqld_proto_skip_network_header(&packet);
|
||||
int err = network_mysqld_proto_get_auth_response(&packet, auth);
|
||||
if (err) {
|
||||
network_mysqld_auth_response_free(auth);
|
||||
return NETWORK_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (con->srv->ssl && auth->ssl_request) {
|
||||
@ -113,10 +117,6 @@ do_read_auth(network_mysqld_con *con, GHashTable *allow_ip_table, GHashTable *de
|
||||
return NETWORK_SOCKET_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
if (err) {
|
||||
network_mysqld_auth_response_free(auth);
|
||||
return NETWORK_SOCKET_ERROR;
|
||||
}
|
||||
if (!(auth->client_capabilities & CLIENT_PROTOCOL_41)) {
|
||||
/* should use packet-id 0 */
|
||||
network_mysqld_queue_append(con->client, con->client->send_queue,
|
||||
@ -124,6 +124,7 @@ do_read_auth(network_mysqld_con *con, GHashTable *allow_ip_table, GHashTable *de
|
||||
network_mysqld_auth_response_free(auth);
|
||||
return NETWORK_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
if (auth->client_capabilities & CLIENT_COMPRESS) {
|
||||
con->is_client_compressed = 1;
|
||||
g_message("%s: client compressed for con:%p", G_STRLOC, con);
|
||||
@ -134,19 +135,25 @@ do_read_auth(network_mysqld_con *con, GHashTable *allow_ip_table, GHashTable *de
|
||||
|
||||
con->client->response = auth;
|
||||
|
||||
if (g_strcmp0(auth->auth_plugin_name->str, "mysql_native_password") != 0) {
|
||||
GString *packet = g_string_new(0);
|
||||
network_mysqld_proto_append_auth_switch(packet, "mysql_native_password",
|
||||
con->client->challenge->auth_plugin_data);
|
||||
network_mysqld_queue_append(con->client, con->client->send_queue, S(packet));
|
||||
con->state = ST_SEND_AUTH_RESULT;
|
||||
con->auth_result_state = AUTH_SWITCH;
|
||||
g_string_free(packet, TRUE);
|
||||
g_string_free(g_queue_pop_tail(recv_sock->recv_queue->chunks), TRUE);
|
||||
return NETWORK_SOCKET_SUCCESS;
|
||||
}
|
||||
|
||||
g_string_assign_len(con->client->default_db, S(auth->database));
|
||||
g_debug("%s:1nd round auth and set default db:%s for con:%p", G_STRLOC, con->client->default_db->str, con);
|
||||
|
||||
} else {
|
||||
GString *auth_data;
|
||||
gsize auth_data_len;
|
||||
|
||||
/*
|
||||
* get all the data from the packet and append it
|
||||
* to the auth_plugin_data
|
||||
*/
|
||||
auth_data_len = packet.data->len - 4;
|
||||
auth_data = g_string_sized_new(auth_data_len);
|
||||
/* auth switch response */
|
||||
gsize auth_data_len = packet.data->len - 4;
|
||||
GString *auth_data = g_string_sized_new(auth_data_len);
|
||||
network_mysqld_proto_get_gstr_len(&packet, auth_data_len, auth_data);
|
||||
|
||||
g_string_append_len(con->client->response->auth_plugin_data, S(auth_data));
|
||||
@ -212,7 +219,6 @@ do_read_auth(network_mysqld_con *con, GHashTable *allow_ip_table, GHashTable *de
|
||||
response->username->str, con->client->src->name->str);
|
||||
network_mysqld_con_send_error_full(con->client, L(msg), ER_ACCESS_DENIED_ERROR, "28000");
|
||||
g_message("%s", msg);
|
||||
con->login_failed = 1;
|
||||
con->state = ST_SEND_ERROR;
|
||||
}
|
||||
|
||||
@ -372,6 +378,8 @@ do_connect_cetus(network_mysqld_con *con, network_backend_t **backend, int *back
|
||||
challenge->capabilities &= ~CLIENT_SSL;
|
||||
#endif
|
||||
network_mysqld_auth_challenge_set_challenge(challenge);
|
||||
challenge->server_status |= SERVER_STATUS_AUTOCOMMIT;
|
||||
challenge->charset = 0xC0;
|
||||
GString *version = g_string_new("");
|
||||
network_backends_server_version(g->backends, version);
|
||||
g_string_append(version, " (cetus)");
|
||||
|
Loading…
Reference in New Issue
Block a user