From 92d3a89fcbbdd07cf0a1000d86ecf7dd09addbe2 Mon Sep 17 00:00:00 2001 From: Massimiliano Pinto Date: Mon, 28 Jan 2013 13:48:14 +0100 Subject: [PATCH] Compression supported change_user added: auth token still to be extracted from COM_CHANGE_USER --- protocol_1.0/mod_skysql.c | 69 +++++++++++++----- protocol_1.0/skysql_client.h | 17 ++++- protocol_1.0/skysql_gw.h | 1 + protocol_1.0/skysql_utils.c | 134 +++++++++++++++++++++++++++++++++-- 4 files changed, 197 insertions(+), 24 deletions(-) diff --git a/protocol_1.0/mod_skysql.c b/protocol_1.0/mod_skysql.c index 5298a887a..bf58500ef 100644 --- a/protocol_1.0/mod_skysql.c +++ b/protocol_1.0/mod_skysql.c @@ -243,7 +243,7 @@ int mysql_print_result(MYSQL_conn *conn) { return (int) buffer[4]; } -static int mysql_connect(char *host, int port, char *dbname, char *user, char *passwd, MYSQL_conn *conn) { +static int mysql_connect(char *host, int port, char *dbname, char *user, char *passwd, MYSQL_conn *conn, int compress) { apr_status_t rv; int connect = 0; int ciclo = 0; @@ -477,8 +477,14 @@ static int mysql_connect(char *host, int port, char *dbname, char *user, char *p packet_buffer[3] = '\x01'; //final_capabilities = 1025669; + final_capabilities |= SKYSQL_CAPABILITIES_PROTOCOL_41; - final_capabilities &= SKYSQL_CAPABILITIES_CLIENT; + final_capabilities |= SKYSQL_CAPABILITIES_CLIENT; + if (compress) { + final_capabilities |= SKYSQL_CAPABILITIES_COMPRESS; + fprintf(stderr, "Backend Connection with compression\n"); + fflush(stderr); + } if (passwd != NULL) { uint8_t hash1[APR_SHA1_DIGESTSIZE]; @@ -517,10 +523,10 @@ static int mysql_connect(char *host, int port, char *dbname, char *user, char *p skysql_set_byte4(client_capabilities, final_capabilities); memcpy(packet_buffer + 4, client_capabilities, 4); - packet_buffer[4] = '\x8d'; - packet_buffer[5] = '\xa6'; - packet_buffer[6] = '\x0f'; - packet_buffer[7] = '\x00'; + //packet_buffer[4] = '\x8d'; + //packet_buffer[5] = '\xa6'; + //packet_buffer[6] = '\x0f'; + //packet_buffer[7] = '\x00'; skysql_set_byte4(packet_buffer + 4 + 4, 16777216); packet_buffer[12] = '\x08'; @@ -536,18 +542,19 @@ static int mysql_connect(char *host, int port, char *dbname, char *user, char *p bytes += strlen(user); if (dbname == NULL) { - strcpy(packet_buffer+36 + 5 + 2, "mysql_native_password"); + //strcpy(packet_buffer+36 + 5 + 2, "mysql_native_password"); } else { if (passwd != NULL) { *(packet_buffer+36 + 5 + 1) = 20; memcpy(packet_buffer+36 + 5 + 1 + 1, client_scramble, 20); strcpy(packet_buffer+36 + 5 + 1 + 1 + 20, dbname); - strcpy(packet_buffer+36 + 5 + 1 + 1 + 20 + strlen(dbname) + 1, "mysql_native_password"); - bytes += 20 + strlen(dbname) + 1; + //strcpy(packet_buffer+36 + 5 + 1 + 1 + 20 + strlen(dbname) + 1, "mysql_native_password"); + //bytes += 20 + strlen(dbname) + 1; + bytes += strlen(dbname) -1; } else { strcpy(packet_buffer+36 + 5 + 1 + 1, dbname); - strcpy(packet_buffer+36 + 5 + 1 + 1 + strlen(dbname) + 1, "mysql_native_password"); - bytes += strlen(dbname) + 1; + //strcpy(packet_buffer+36 + 5 + 1 + 1 + strlen(dbname) + 1, "mysql_native_password"); + bytes += strlen(dbname) -1; } } @@ -807,6 +814,17 @@ static int skysql_process_connection(conn_rec *c) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "current username is [%s]", mysql_client_data->username); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "current DB is [%s]", mysql_client_data->database != NULL ? mysql_client_data->database : ""); + /////////////////////////// + // check for compression // + /////////////////////////// + if (mysql_driver->compress) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "Compress Request is in connect packet"); + } + + ///////////////////// + // Let's go ahead // + ///////////////////// + // now the pool pointer is set to NULL pool = NULL; @@ -853,7 +871,7 @@ static int skysql_process_connection(conn_rec *c) { selected_dbname = "test"; } - if (mysql_connect(selected_host, selected_port, selected_dbname, mysql_client_data->username, "pippo", conn) != 0) { + if (mysql_connect(selected_host, selected_port, selected_dbname, mysql_client_data->username, "pippo", conn, mysql_driver->compress) != 0) { //if (mysql_real_connect(conn, "192.168.1.40", "root", "pippo", "test", 3306, NULL, 0) == NULL) // ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, "MYSQL Connect [%s:%i] Error %u: %s", selected_host, selected_port, mysql_errno(conn), mysql_error(conn)); return 500; @@ -883,6 +901,7 @@ static int skysql_process_connection(conn_rec *c) { apr_socket_timeout_set(ap_get_conn_socket(c), timeout); while(1) { + char i_username[100]=""; ////////////////////////////////////////////////////////////// // the new pool is allocated on c->pool // this new pool is the right one for the while(1) main loop @@ -1018,7 +1037,9 @@ static int skysql_process_connection(conn_rec *c) { break; case 0x04 : ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "COM_FIELD_LIST", query_from_client+5); - skysql_send_ok(c, pool, 1, 0, NULL); + mysql_pass_packet(conn, query_from_client, query_from_client_len); + mysql_receive_packet(c, pool, conn); + //skysql_send_ok(c, pool, 1, 0, NULL); break; case 0x1b : @@ -1072,10 +1093,22 @@ static int skysql_process_connection(conn_rec *c) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "MYSQL_conn is NULL? %i", conn == NULL ? 1 : 0); } break; - dafault : - ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, "UNKNOW MYSQL PROTOCOL COMMAND [%x]", mysql_command); - // reponse sent to the client, with custom error: TODO - skysql_send_ok(c, pool, 1, 0, "unknow command"); + case 0x11 : + strcpy(i_username, query_from_client+5); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "COM_CHANGE_USER"); + skysql_change_user(c, pool, i_username, "test", conn, stage1_hash); + mysql_receive_packet(c, pool, conn); + break; + + default : + if (mysql_driver->compress) { + mysql_pass_packet(conn, query_from_client, query_from_client_len); + mysql_receive_packet(c, pool, conn); + } else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "UNKNOW MYSQL PROTOCOL COMMAND [%x]", mysql_command); + // reponse sent to the client, with custom error: TODO + skysql_send_ok(c, pool, 1, 0, "unknow command"); + } break; } @@ -1179,7 +1212,7 @@ static void skysql_child_init(apr_pool_t *p, server_rec *s) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "MYSQL init Error %u: %s\n", mysql_errno(conf->conn), mysql_error(conf->conn)); return; } - if (mysql_connect("127.0.0.1", 3306, "test", "pippo", "pippo", conf->conn) != 0) { + if (mysql_connect("127.0.0.1", 3306, "test", "pippo", "pippo", conf->conn, 0) != 0) { //if (mysql_real_connect(conf->conn, "192.168.1.40", "root", "pippo", "test", 3306, NULL, 0) == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "MYSQL Connect Error %u: %s\n", mysql_errno(conf->conn), mysql_error(conf->conn)); return ; diff --git a/protocol_1.0/skysql_client.h b/protocol_1.0/skysql_client.h index 3d03b3614..36bb1b9d2 100644 --- a/protocol_1.0/skysql_client.h +++ b/protocol_1.0/skysql_client.h @@ -116,12 +116,25 @@ typedef enum SKYSQL_CAPABILITIES_MULTI_STATEMENTS | SKYSQL_CAPABILITIES_MULTI_RESULTS | SKYSQL_CAPABILITIES_PS_MULTI_RESULTS | - SKYSQL_CAPABILITIES_SECURE_CONNECTION) + SKYSQL_CAPABILITIES_SECURE_CONNECTION), + SKYSQL_CAPABILITIES_CLIENT_COMPRESS= (SKYSQL_CAPABILITIES_LONG_PASSWORD | + SKYSQL_CAPABILITIES_FOUND_ROWS | + SKYSQL_CAPABILITIES_LONG_FLAG | + SKYSQL_CAPABILITIES_CONNECT_WITH_DB | + SKYSQL_CAPABILITIES_LOCAL_FILES | + SKYSQL_CAPABILITIES_PLUGIN_AUTH | + SKYSQL_CAPABILITIES_TRANSACTIONS | + SKYSQL_CAPABILITIES_PROTOCOL_41 | + SKYSQL_CAPABILITIES_MULTI_STATEMENTS | + SKYSQL_CAPABILITIES_MULTI_RESULTS | + SKYSQL_CAPABILITIES_PS_MULTI_RESULTS | + SKYSQL_CAPABILITIES_COMPRESS + ), } skysql_capabilities_t; #define SMALL_CHUNK 1024 -#define MAX_CHUNK SMALL_CHUNK * 8 * 2 +#define MAX_CHUNK SMALL_CHUNK * 8 * 4 #define ToHex(Y) (Y>='0'&&Y<='9'?Y-'0':Y-'A'+10) //#define MYSQL_CONN_DEBUG diff --git a/protocol_1.0/skysql_gw.h b/protocol_1.0/skysql_gw.h index 53aec4689..5e088929d 100644 --- a/protocol_1.0/skysql_gw.h +++ b/protocol_1.0/skysql_gw.h @@ -93,6 +93,7 @@ typedef struct { uint8_t charset; uint8_t scramble_buff; int connect_with_db; + int compress; } mysql_driver_details; int skysql_ext_file_ver(); diff --git a/protocol_1.0/skysql_utils.c b/protocol_1.0/skysql_utils.c index 8729787c1..f41fa8dee 100644 --- a/protocol_1.0/skysql_utils.c +++ b/protocol_1.0/skysql_utils.c @@ -197,17 +197,17 @@ apr_status_t skysql_change_user(conn_rec *c, apr_pool_t *p, char *username, char uint8_t charset[2]=""; uint8_t backend_scramble[20 +1]=""; - int fd = 0; - int user_len = strlen(username); int database_len = strlen(database); uint8_t *password = NULL; uint8_t temp_token[20 +1] =""; uint8_t stage1_password[20 +1] =""; + apr_status_t rv = -1; + long bytes; //get password from repository - password = gateway_find_user_password_sha1("pippo", NULL, c, p); + password = gateway_find_user_password_sha1(username, NULL, c, p); memcpy(backend_scramble, conn->scramble, 20); skysql_sha1_2_str(backend_scramble, 20, password, 20, temp_token); @@ -221,9 +221,11 @@ apr_status_t skysql_change_user(conn_rec *c, apr_pool_t *p, char *username, char ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway TO backend scramble [%s]", backend_scramble); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway SHA1(password) [%s]", stage1_hash); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway internal password [%s]", password); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway SHA1(scramble + SHA1(stage1_hash)) [%s]", temp_token); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway TO backend token [%s]", token+1); + //skysql_payload_size = 1 + user_len + 1 + sizeof(token) + database_len + 1 + sizeof(charset) + 1 + sizeof("mysql_native_password") + 1; skysql_payload_size = 1 + user_len + 1 + sizeof(token) + database_len + 1 + sizeof(charset); // allocate memory for packet header + payload @@ -239,8 +241,11 @@ apr_status_t skysql_change_user(conn_rec *c, apr_pool_t *p, char *username, char memcpy(outbuf + sizeof(skysql_packet_header) + 1 + strlen(username) + 1, token, 21); memcpy(outbuf + sizeof(skysql_packet_header) + 1 + strlen(username) + 1 + 21, database, database_len); memcpy(outbuf + sizeof(skysql_packet_header) + 1 + strlen(username) + 1 + 21 + database_len + 1, charset, sizeof(charset)); + //memcpy(outbuf + sizeof(skysql_packet_header) + 1 + strlen(username) + 1 + 21 + database_len + 1 + sizeof(charset) + 1, "mysql_native_password", strlen("mysql_native_password")); - write(fd, outbuf, sizeof(skysql_packet_header) + skysql_payload_size); + bytes = sizeof(skysql_packet_header) + skysql_payload_size; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skysql_change_user is %li bytes", bytes); + rv = apr_socket_send(conn->socket, outbuf, &bytes); } apr_status_t skysql_read_client_autentication(conn_rec *c, apr_pool_t *pool, uint8_t *scramble, int scramble_len, skysql_client_auth *mysql_client_data, uint8_t *stage1_hash) { @@ -328,6 +333,7 @@ apr_status_t skysql_read_client_autentication(conn_rec *c, apr_pool_t *pool, uin // todo: insert constant values instead of numbers memcpy(mysql_driver->client_flags, client_auth_packet + 4, 4); mysql_driver->connect_with_db = SKYSQL_CAPABILITIES_CONNECT_WITH_DB & skysql_get_byte4(mysql_driver->client_flags); + mysql_driver->compress = SKYSQL_CAPABILITIES_COMPRESS & skysql_get_byte4(mysql_driver->client_flags); mysql_client_data->username = apr_pstrndup(p, client_auth_packet + 4 + 4 + 4 + 1 + 23, 128); memcpy(&token_len, client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(mysql_client_data->username) + 1, 1); @@ -769,6 +775,9 @@ apr_status_t skysql_send_handshake(conn_rec *c, uint8_t *scramble, int *scramble //write server capabilities part two skysql_server_capabilities_two[0] = 15; skysql_server_capabilities_two[1] = 128; + + //skysql_server_capabilities_two[0] & SKYSQL_CAPABILITIES_COMPRESS; + memcpy(skysql_handshake_payload, skysql_server_capabilities_two, sizeof(skysql_server_capabilities_two)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_server_capabilities_two); @@ -1213,3 +1222,120 @@ int mysql_send_command(MYSQL_conn *conn, const char *command, int cmd, int len) return 0; } + +int mysql_pass_packet(MYSQL_conn *conn, const char *command, int len) { + apr_status_t rv; + //uint8_t *packet_buffer=NULL; + uint8_t packet_buffer[SMALL_CHUNK]; + long bytes; + int fd; + + //packet_buffer = (uint8_t *) calloc(1, 5 + len + 1); + memset(&packet_buffer, '\0', sizeof(packet_buffer)); + + memcpy(packet_buffer, command, len); + + bytes = len; + +#ifdef MYSQL_CONN_DEBUG + fprintf(stderr, "THE COMMAND is [%s] len %i\n", command, bytes); + fprintf(stderr, "THE COMMAND TID is [%lu]", conn->tid); + fprintf(stderr, "THE COMMAND scramble is [%s]", conn->scramble); + if (conn->socket == NULL) { + fprintf(stderr, "***** THE COMMAND sock struct is NULL\n"); + } + fwrite(packet_buffer, bytes, 1, stderr); + fflush(stderr); +#endif + apr_os_sock_get(&fd,conn->socket); + +#ifdef MYSQL_CONN_DEBUG + fprintf(stderr, "PACKET Socket FD is %i\n", fd); + fflush(stderr); +#endif + + rv = apr_socket_send(conn->socket, packet_buffer, &bytes); + +#ifdef MYSQL_CONN_DEBUG + fprintf(stderr, "PACKET SENT [%s]\n", command); + fflush(stderr); +#endif + + if (rv != APR_SUCCESS) { + return 1; + } + + return 0; +} + +int mysql_receive_packet(conn_rec *c, apr_pool_t *p, MYSQL_conn *conn) { + apr_bucket_brigade *bb1; + apr_bucket *b1; + apr_status_t rv; + uint8_t buffer[MAX_CHUNK]; + unsigned long bytes = MAX_CHUNK; + unsigned long tot_bytes = 0; + int cycle=0; + int is_eof = 0; + apr_socket_timeout_set(conn->socket, 100000000); + + while(1) { + char errmesg_p[1000]=""; + bytes=MAX_CHUNK; + + memset(buffer, '\0', MAX_CHUNK); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW is receiving ..."); + + rv = apr_socket_recv(conn->socket, buffer, &bytes); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW received %lu bytes", bytes); + + if (rv) { + if (APR_STATUS_IS_EAGAIN(rv)) { + continue; + } + } + + tot_bytes += bytes; + + if (rv != APR_SUCCESS && rv != APR_EOF && rv != APR_EAGAIN) { + char errmesg[1000]=""; + apr_strerror(rv, errmesg, sizeof(errmesg)); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error %i, [%s]", rv, errmesg); + + return 1; + } + + if (rv == APR_EOF && bytes == 0) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error: EOF"); + } + + bb1 = apr_brigade_create(p, c->bucket_alloc); + + apr_brigade_write(bb1, ap_filter_flush, c->output_filters, buffer, bytes); + ap_fflush(c->output_filters, bb1); + + apr_brigade_destroy(bb1); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive, brigade sent with %li bytes", bytes); + + cycle++; + + if (bytes < MAX_CHUNK) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: less bytes than buffer here, Return from query result: total bytes %lu in %i", tot_bytes, cycle); + + return 0; + } + + if (bytes == MAX_CHUNK) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: ALL bytes in the buffer here, continue"); + } + + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: Return from query result: total bytes %lu in %i", tot_bytes, cycle); + + return 0; +}