//////////////////////////////////////// // SKYSQL Utils // By Massimiliano Pinto 2012 // SkySQL AB //////////////////////////////////////// #include "skysql_gw.h" #include "apr_sha1.h" #define MYSQL_PROTOCOL_VERSION41_CHAR '*' #define char_val(X) (X >= '0' && X <= '9' ? X-'0' :\ X >= 'A' && X <= 'Z' ? X-'A'+10 :\ X >= 'a' && X <= 'z' ? X-'a'+10 :\ '\177') char hex_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char hex_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; ///////////////////////////////// // binary data to hex string // output must be pre allocated ///////////////////////////////// char *bin2hex(char *out, const uint8_t *in, unsigned int len) { const uint8_t *in_end= in + len; if (len == 0 || in == NULL) { return NULL; } for (; in != in_end; ++in) { *out++= hex_upper[((uint8_t) *in) >> 4]; *out++= hex_upper[((uint8_t) *in) & 0x0F]; } *out= '\0'; return out; } ///////////////////////////////// // hex string to binary data // output must be pre allocated ///////////////////////////////// int hex2bin(uint8_t *out, const char *in, unsigned int len) { const char *in_end= in + len; if (len == 0 || in == NULL) { return 1; } while (in < in_end) { register char tmp_ptr = char_val(*in++); *out++= (tmp_ptr << 4) | char_val(*in++); } return 0; } ///////////////////////////////// // general random string // output must be pre allocated ///////////////////////////////// void skysql_set_random_str(uint8_t *output, unsigned int length) { uint8_t *ptr = output; apr_status_t rv = apr_generate_random_bytes(output, length); // this is for debug, the same scramble for every handshake //strcpy(output, "12345678abcdefjhilmn"); } ///////////////////////////////////////////////////////////// // fill a 20 bytes preallocated with SHA1 digest (160 bits) // for one input on in_len bytes ///////////////////////////////////////////////////////////// void skysql_sha1_str(const uint8_t *in, int in_len, uint8_t *out) { int l; apr_sha1_ctx_t context; apr_byte_t digest[APR_SHA1_DIGESTSIZE]; apr_sha1_init(&context); apr_sha1_update(&context, in, in_len); apr_sha1_final(digest, &context); memcpy(out, digest, APR_SHA1_DIGESTSIZE); } ///////////////////////////////////////////////////////////// // fill 20 bytes preallocated with SHA1 digest (160 bits) // for two inputs, in_len and in2_len bytes ///////////////////////////////////////////////////////////// void skysql_sha1_2_str(const uint8_t *in, int in_len, const uint8_t *in2, int in2_len, uint8_t *out) { int l; apr_sha1_ctx_t context; apr_byte_t digest[APR_SHA1_DIGESTSIZE]; apr_sha1_init(&context); apr_sha1_update(&context, in, in_len); apr_sha1_update(&context, in2, in2_len); apr_sha1_final(digest, &context); memcpy(out, digest, APR_SHA1_DIGESTSIZE); } /////////////////////////////////////////////////////// // fill a preallocated buffer with XOR(str1, str2) // XOR between 2 equal len strings // note that XOR(str1, XOR(str1 CONCAT str2)) == str2 // and that XOR(str1, str2) == XOR(str2, str1) /////////////////////////////////////////////////////// void skysql_str_xor(char *output, const uint8_t *input1, const uint8_t *input2, unsigned int len) { const uint8_t *input1_end = NULL; input1_end = input1 + len; while (input1 < input1_end) *output++= *input1++ ^ *input2++; *output = '\0'; } ////////////////////////////////////////// // get skygateway password from username // output is SHA1(SHA1(password)) ////////////////////////////////////////// char *gateway_find_user_password_sha1(char *username, void *repository, conn_rec *c, apr_pool_t *p) { uint8_t hash1[APR_SHA1_DIGESTSIZE]; uint8_t hash2[APR_SHA1_DIGESTSIZE]; skysql_sha1_str(username, strlen(username), hash1); skysql_sha1_str(hash1, APR_SHA1_DIGESTSIZE, hash2); return apr_pstrmemdup(p, hash2, APR_SHA1_DIGESTSIZE); } ///////////////////////////////////////////// // get the SHA1(SHA1(password)) from client ///////////////////////////////////////////// int skysql_check_scramble(conn_rec *c, apr_pool_t *p, uint8_t *token, unsigned int token_len, uint8_t *scramble, unsigned int scramble_len, char *username, uint8_t *stage1_hash) { uint8_t step1[APR_SHA1_DIGESTSIZE]; uint8_t step2[APR_SHA1_DIGESTSIZE +1]; uint8_t check_hash[APR_SHA1_DIGESTSIZE]; char hex_double_sha1[2 * APR_SHA1_DIGESTSIZE + 1]=""; uint8_t *password = gateway_find_user_password_sha1("pippo", NULL, c, p); bin2hex(hex_double_sha1, password, APR_SHA1_DIGESTSIZE); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "stored hex(SHA1(SHA1(password))) [%s]", hex_double_sha1); // possible, now skipped /* if (password == NULL) { ?????? } */ // step 1 skysql_sha1_2_str(scramble, scramble_len, password, APR_SHA1_DIGESTSIZE, step1); //step2 skysql_str_xor(step2, token, step1, token_len); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway SHA1(password) [%s]", step2); memcpy(stage1_hash, step2, 20); skysql_sha1_str(step2, APR_SHA1_DIGESTSIZE, check_hash); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SHA1 di SHA1(client password) [%s]", check_hash); return memcmp(password, check_hash, APR_SHA1_DIGESTSIZE); } apr_status_t gateway_reply_data(conn_rec *c, apr_pool_t *pool, void *data, int len) { apr_status_t rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket_brigade *r_bb; // create brigade bb = apr_brigade_create(pool, c->bucket_alloc); apr_brigade_write(bb, ap_filter_flush, c->output_filters, data, len); ap_fflush(c->output_filters, bb); apr_brigade_destroy(bb); return 1; } apr_status_t skysql_change_user(conn_rec *c, apr_pool_t *p, char *username, char *database, MYSQL_conn *conn, uint8_t *stage1_hash) { uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t skysql_packet_id = 0; uint8_t change_user_command = 0x11; uint8_t *outbuf = NULL; uint8_t token[20 + 1]=""; 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] =""; //get password from repository password = gateway_find_user_password_sha1("pippo", NULL, c, p); memcpy(backend_scramble, conn->scramble, 20); skysql_sha1_2_str(backend_scramble, 20, password, 20, temp_token); *token = '\x14'; charset[0]='\x08'; charset[1]='\x00'; skysql_str_xor(token+1, temp_token, stage1_hash, 20); 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 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); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(p, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = skysql_packet_id; memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); memcpy(outbuf + sizeof(skysql_packet_header), &change_user_command, 1); memcpy(outbuf + sizeof(skysql_packet_header) + 1, username, user_len); 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)); write(fd, outbuf, sizeof(skysql_packet_header) + skysql_payload_size); } 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) { apr_bucket_brigade *r_bb; apr_bucket *r_b; apr_status_t rv; int seen_eos = 0; int child_stopped_reading = 0; int i; apr_bucket *auth_bucket; apr_bucket *bucket; const char *client_auth_packet = NULL; unsigned int query_ret = 0; int return_data = 0; int input_read = 0; uint8_t client_flags[4]; char *current_slave_server_host = NULL; int current_slave_server_port = 3306; apr_pool_t *p = NULL; mysql_driver_details *mysql_driver = NULL; uint8_t *token = NULL; unsigned int token_len = 0; int auth_ret = 0; // use the passed pool? p = pool == NULL ? c->pool : pool; // now read the client authentication r_bb = apr_brigade_create(p, c->bucket_alloc); if (((rv = ap_get_brigade(c->input_filters, r_bb, AP_MODE_READBYTES, APR_BLOCK_READ, 8192)) != APR_SUCCESS) || APR_BRIGADE_EMPTY(r_bb)) { apr_brigade_destroy(r_bb); return input_read; } for (auth_bucket = APR_BRIGADE_FIRST(r_bb); bucket != APR_BRIGADE_SENTINEL(r_bb); bucket = APR_BUCKET_NEXT(auth_bucket)) { apr_size_t len; const char *data; if (APR_BUCKET_IS_EOS(auth_bucket)) { seen_eos = 1; break; } if (APR_BUCKET_IS_FLUSH(auth_bucket)) { continue; } if (child_stopped_reading) { break; } rv = apr_bucket_read(auth_bucket, &data, &len, APR_BLOCK_READ); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "Auth Data len [%i]", len); if (rv != APR_SUCCESS) { child_stopped_reading = 1; } client_auth_packet = apr_pstrmemdup(p, data, len); input_read = 1; } // this brigade is useless apr_brigade_destroy(r_bb); if (input_read && client_auth_packet) { // now fill data structure for client data in driver MYSQL5 if (mysql_client_data != NULL) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "Now decode MYSQL client auth packet"); mysql_driver = (mysql_driver_details *)mysql_client_data->driver_details; if (mysql_driver != NULL) { uint8_t hash_stage1[20 +1]; /* uint8_t hash_stage1[20]; uint8_t hash_stage2[20]; uint8_t temp_token[20]; uint8_t client_token[20]; uint8_t check_auth[20]; uint8_t final_hash[20]; */ // 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_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); token = apr_pstrmemdup(p, client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(mysql_client_data->username) + 1 + 1, token_len); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "[client TO gateway] current username is [%s], token is [%s] len %i", mysql_client_data->username, token, token_len); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "[gateway TO client] server scramble was [%s], len %i", scramble, scramble_len); /* skysql_sha1_str(mysql_client_data->username, strlen(mysql_client_data->username), hash_stage1); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SHA1 di '%s' [%s]", mysql_client_data->username, hash_stage1); skysql_sha1_str(hash_stage1, 20, hash_stage2); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SHA1 di SHA1('%s') [%s]", mysql_client_data->username, hash_stage2); skysql_sha1_2_str(scramble, scramble_len, hash_stage2, 20, temp_token); skysql_str_xor(check_auth, hash_stage1, temp_token, 20); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "This is the client input?? [%s]", check_auth); memset(temp_token, '\0', sizeof(temp_token)); memcpy(client_token, scramble, scramble_len); memcpy(client_token + scramble_len, hash_stage2, 20); skysql_sha1_str(client_token, scramble_len, temp_token); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "This is the client input?? [%s]", temp_token); skysql_str_xor(check_auth, hash_stage2, hash_stage1, scramble_len); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "XOR( client token, stage2_hash) [%s]", check_auth); skysql_sha1_str(check_auth, 20, final_hash); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SHA1 di check_auth [%s]", final_hash); */ // decode the token and check the password auth_ret = skysql_check_scramble(c, p, token, token_len, scramble, scramble_len, mysql_client_data->username, stage1_hash); if (auth_ret == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SkySQL Gateway Authentication OK for [%s]", mysql_client_data->username); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "**** SkySQL Gateway Authentication ERROR [%s], retcode = [%i]", mysql_client_data->username, auth_ret); } if (mysql_driver->connect_with_db) { mysql_client_data->database = apr_pstrndup(p, client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(mysql_client_data->username) + 1 + 1 + token_len, 128); } } } } return input_read; } apr_status_t gateway_send_error (conn_rec *c, apr_pool_t *p, uint8_t packet_number) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t *skysql_payload = NULL; uint8_t field_count = 0; uint8_t affected_rows = 0; uint8_t insert_id = 0; uint8_t skysql_err[2]; uint8_t skysql_statemsg[6]; unsigned int skysql_errno = 0; const char *skysql_error_msg = NULL; const char *skysql_state = NULL; skysql_errno = 6969; skysql_error_msg = "Too many queries in one connection"; skysql_state = "FA5D3"; field_count = 0xff; skysql_set_byte2(skysql_err, skysql_errno); skysql_statemsg[0]='#'; memcpy(skysql_statemsg+1, skysql_state, 5); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQL_Error: Errno [%u], ErrorMessage [%s], State [%s]", skysql_errno, skysql_error_msg, skysql_state); skysql_payload_size = sizeof(field_count) + sizeof(skysql_err) + sizeof(skysql_statemsg) + strlen(skysql_error_msg); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(p, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = packet_number; // write header memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); skysql_payload = outbuf + sizeof(skysql_packet_header); // write field memcpy(skysql_payload, &field_count, sizeof(field_count)); skysql_payload = skysql_payload + sizeof(field_count); // write errno memcpy(skysql_payload, skysql_err, sizeof(skysql_err)); skysql_payload = skysql_payload + sizeof(skysql_err); // write sqlstate memcpy(skysql_payload, skysql_statemsg, sizeof(skysql_statemsg)); skysql_payload = skysql_payload + sizeof(skysql_statemsg); // write err messg memcpy(skysql_payload, skysql_error_msg, strlen(skysql_error_msg)); // create brigade bb = apr_brigade_create(p, c->bucket_alloc); b = apr_bucket_pool_create(outbuf, sizeof(skysql_packet_header) + skysql_payload_size, p, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return ap_pass_brigade(c->output_filters, bb); } apr_status_t skysql_send_error (conn_rec *c, uint8_t packet_number, MYSQL_conn *conn) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t *skysql_payload = NULL; uint8_t field_count = 0; uint8_t affected_rows = 0; uint8_t insert_id = 0; uint8_t skysql_err[2]; uint8_t skysql_statemsg[6]; unsigned int skysql_errno = 0; const char *skysql_error_msg = NULL; const char *skysql_state = NULL; skysql_errno = mysql_errno(conn); skysql_error_msg = mysql_error(conn); skysql_state = mysql_sqlstate(conn); field_count = 0xff; skysql_set_byte2(skysql_err, skysql_errno); skysql_statemsg[0]='#'; memcpy(skysql_statemsg+1, skysql_state, 5); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQL_Error: Errno [%u], ErrorMessage [%s], State [%s]", skysql_errno, skysql_error_msg, skysql_state); skysql_payload_size = sizeof(field_count) + sizeof(skysql_err) + sizeof(skysql_statemsg) + strlen(skysql_error_msg); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(c->pool, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = packet_number; // write header memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); skysql_payload = outbuf + sizeof(skysql_packet_header); // write field memcpy(skysql_payload, &field_count, sizeof(field_count)); skysql_payload = skysql_payload + sizeof(field_count); // write errno memcpy(skysql_payload, skysql_err, sizeof(skysql_err)); skysql_payload = skysql_payload + sizeof(skysql_err); // write sqlstate memcpy(skysql_payload, skysql_statemsg, sizeof(skysql_statemsg)); skysql_payload = skysql_payload + sizeof(skysql_statemsg); // write err messg memcpy(skysql_payload, skysql_error_msg, strlen(skysql_error_msg)); // create brigade bb = apr_brigade_create(c->pool, c->bucket_alloc); b = apr_bucket_pool_create(outbuf, sizeof(skysql_packet_header) + skysql_payload_size, c->pool, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return ap_pass_brigade(c->output_filters, bb); } apr_status_t skysql_send_result(conn_rec *c, uint8_t *data, uint8_t len) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; // create brigade bb = apr_brigade_create(c->pool, c->bucket_alloc); // write apr_brigade_write(bb, ap_filter_flush, c->output_filters, data, len); //send & flush return ap_fflush(c->output_filters, bb); } apr_status_t skysql_send_eof(conn_rec *c, uint8_t packet_number) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t *skysql_payload = NULL; uint8_t field_count = 0; uint8_t skysql_server_status[2]; uint8_t skysql_warning_count[2]; field_count = 0xfe; skysql_payload_size = sizeof(field_count) + sizeof(skysql_server_status) + sizeof(skysql_warning_count); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(c->pool, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = packet_number; // write header memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); skysql_payload = outbuf + sizeof(skysql_packet_header); skysql_server_status[0] = 2; skysql_server_status[1] = 0; skysql_warning_count[0] = 0; skysql_warning_count[1] = 0; // write data memcpy(skysql_payload, &field_count, sizeof(field_count)); skysql_payload = skysql_payload + sizeof(field_count); memcpy(skysql_payload, skysql_server_status, sizeof(skysql_server_status)); skysql_payload = skysql_payload + sizeof(skysql_server_status); memcpy(skysql_payload, skysql_warning_count, sizeof(skysql_warning_count)); skysql_payload = skysql_payload + sizeof(skysql_warning_count); // create brigade bb = apr_brigade_create(c->pool, c->bucket_alloc); // write apr_brigade_write(bb, ap_filter_flush, c->output_filters, outbuf, sizeof(skysql_packet_header) + skysql_payload_size); //send & flush return ap_fflush(c->output_filters, bb); } apr_status_t skysql_send_ok(conn_rec *c, apr_pool_t *p, uint8_t packet_number, uint8_t in_affected_rows, const char* skysql_message) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t *skysql_payload = NULL; uint8_t field_count = 0; uint8_t affected_rows = 0; uint8_t insert_id = 0; uint8_t skysql_server_status[2]; uint8_t skysql_warning_count[2]; affected_rows = in_affected_rows; skysql_payload_size = sizeof(field_count) + sizeof(affected_rows) + sizeof(insert_id) + sizeof(skysql_server_status) + sizeof(skysql_warning_count); if (skysql_message != NULL) { skysql_payload_size += strlen(skysql_message); } // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(p, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = packet_number; // write header memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); skysql_payload = outbuf + sizeof(skysql_packet_header); skysql_server_status[0] = 2; skysql_server_status[1] = 0; skysql_warning_count[0] = 0; skysql_warning_count[1] = 0; // write data memcpy(skysql_payload, &field_count, sizeof(field_count)); skysql_payload = skysql_payload + sizeof(field_count); memcpy(skysql_payload, &affected_rows, sizeof(affected_rows)); skysql_payload = skysql_payload + sizeof(affected_rows); memcpy(skysql_payload, &insert_id, sizeof(insert_id)); skysql_payload = skysql_payload + sizeof(insert_id); memcpy(skysql_payload, skysql_server_status, sizeof(skysql_server_status)); skysql_payload = skysql_payload + sizeof(skysql_server_status); memcpy(skysql_payload, skysql_warning_count, sizeof(skysql_warning_count)); skysql_payload = skysql_payload + sizeof(skysql_warning_count); if (skysql_message != NULL) { memcpy(skysql_payload, skysql_message, strlen(skysql_message)); } // create brigade bb = apr_brigade_create(p, c->bucket_alloc); /* b = apr_bucket_pool_create(outbuf, sizeof(skysql_packet_header) + skysql_payload_size, c->pool, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return ap_pass_brigade(c->output_filters, bb); */ apr_brigade_write(bb, ap_filter_flush, c->output_filters, outbuf, sizeof(skysql_packet_header) + skysql_payload_size); ap_fflush(c->output_filters, bb); apr_brigade_destroy(bb); return 1; } /////////////////////////// // scramble is 20 bytes and must be pre allocated apr_status_t skysql_send_handshake(conn_rec *c, uint8_t *scramble, int *scramble_len) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; apr_pool_t *p = c->pool; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t skysql_packet_id = 0; uint8_t skysql_filler = SKYSQL_HANDSKAKE_FILLER; uint8_t skysql_protocol_version = SKYSQL_PROTOCOL_VERSION; uint8_t *skysql_handshake_payload = NULL; uint8_t skysql_thread_id[4]; uint8_t skysql_scramble_buf[9] = ""; uint8_t skysql_plugin_data[13] = ""; uint8_t skysql_server_capabilities_one[2]; uint8_t skysql_server_capabilities_two[2]; uint8_t skysql_server_language = 8; uint8_t skysql_server_status[2]; uint8_t skysql_scramble_len = 21; uint8_t skysql_filler_ten[10]; uint8_t skysql_last_byte = 0x00; uint8_t scramble_buffer[20]=""; skysql_set_random_str(scramble_buffer, 20); // set len to the caller memset(scramble_len, 20, 1); // copy back to the caller memcpy(scramble, scramble_buffer, 20); memset(&skysql_filler_ten, 0x00, sizeof(skysql_filler_ten)); // thread id, now put the apache child PID, then a conversion map in memory is needed! skysql_set_byte4(skysql_thread_id, getpid()); memcpy(skysql_scramble_buf, scramble_buffer, 8); memcpy(skysql_plugin_data, scramble_buffer + 8, 12); skysql_payload_size = sizeof(skysql_protocol_version) + (strlen(SKYSQL_VERSION) + 1) + sizeof(skysql_thread_id) + 8 + sizeof(skysql_filler) + sizeof(skysql_server_capabilities_one) + sizeof(skysql_server_language) + sizeof(skysql_server_status) + sizeof(skysql_server_capabilities_two) + sizeof(skysql_scramble_len) + sizeof(skysql_filler_ten) + 12 + sizeof(skysql_last_byte) + strlen("mysql_native_password") + sizeof(skysql_last_byte); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(p, sizeof(skysql_packet_header) + skysql_payload_size); // write packet heder with skysql_payload_size skysql_set_byte3(skysql_packet_header, skysql_payload_size); //skysql_packet_header[0] = skysql_payload_size; // write packent number, now is 0 skysql_packet_header[3]= skysql_packet_id; memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); // current buffer pointer skysql_handshake_payload = outbuf + sizeof(skysql_packet_header); // write protocol version memcpy(skysql_handshake_payload, &skysql_protocol_version, sizeof(skysql_protocol_version)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_protocol_version); // write server version plus 0 filler strcpy(skysql_handshake_payload, SKYSQL_VERSION); skysql_handshake_payload = skysql_handshake_payload + strlen(SKYSQL_VERSION); *skysql_handshake_payload = 0x00; skysql_handshake_payload++; // write thread id memcpy(skysql_handshake_payload, skysql_thread_id, sizeof(skysql_thread_id)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_thread_id); // write scramble buf memcpy(skysql_handshake_payload, skysql_scramble_buf, 8); skysql_handshake_payload = skysql_handshake_payload + 8; *skysql_handshake_payload = SKYSQL_HANDSKAKE_FILLER; skysql_handshake_payload++; // write server capabilities part one skysql_server_capabilities_one[0] = SKYSQL_SERVER_CAPABILITIES_BYTE1; skysql_server_capabilities_one[1] = SKYSQL_SERVER_CAPABILITIES_BYTE2; memcpy(skysql_handshake_payload, skysql_server_capabilities_one, sizeof(skysql_server_capabilities_one)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_server_capabilities_one); // write server language memcpy(skysql_handshake_payload, &skysql_server_language, sizeof(skysql_server_language)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_server_language); //write server status skysql_server_status[0] = 2; skysql_server_status[1] = 0; memcpy(skysql_handshake_payload, skysql_server_status, sizeof(skysql_server_status)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_server_status); //write server capabilities part two skysql_server_capabilities_two[0] = 15; skysql_server_capabilities_two[1] = 128; memcpy(skysql_handshake_payload, skysql_server_capabilities_two, sizeof(skysql_server_capabilities_two)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_server_capabilities_two); // write scramble_len memcpy(skysql_handshake_payload, &skysql_scramble_len, sizeof(skysql_scramble_len)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_scramble_len); //write 10 filler memcpy(skysql_handshake_payload, skysql_filler_ten, sizeof(skysql_filler_ten)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_filler_ten); // write plugin data memcpy(skysql_handshake_payload, skysql_plugin_data, 12); skysql_handshake_payload = skysql_handshake_payload + 12; //write last byte, 0 *skysql_handshake_payload = 0x00; skysql_handshake_payload++; // to be understanded ???? memcpy(skysql_handshake_payload, "mysql_native_password", strlen("mysql_native_password")); skysql_handshake_payload = skysql_handshake_payload + strlen("mysql_native_password"); //write last byte, 0 *skysql_handshake_payload = 0x00; skysql_handshake_payload++; // create brigade bb = apr_brigade_create(p, c->bucket_alloc); /* b = apr_bucket_pool_create(outbuf, sizeof(skysql_packet_header) + skysql_payload_size, p, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); ap_pass_brigade(c->output_filters, bb); apr_brigade_destroy(bb); */ apr_brigade_write(bb, ap_filter_flush, c->output_filters, outbuf, sizeof(skysql_packet_header) + skysql_payload_size); ap_fflush(c->output_filters, bb); apr_brigade_destroy(bb); return 1; } int skygateway_query_result(conn_rec *c, apr_pool_t *p, MYSQL_conn *conn, const char *query) { int query_ret = 0; int num_fields = 0; int return_data = 0; uint8_t result_column_count = 0; uint8_t header_result_packet[4]; apr_bucket_brigade *bb1; apr_bucket *b1; uint8_t *outbuf = NULL; apr_status_t rv; uint8_t buffer[MAX_CHUNK]; unsigned long bytes = MAX_CHUNK; query_ret = mysql_query(conn, query); fprintf(stderr, "HERE SEND QUERY\n"); fflush(stderr); if (query_ret) { // send error, packet #1 skysql_send_error(c, 1, conn); return 1; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW is sending result set ..."); rv = apr_socket_recv(conn->socket, buffer, &bytes); if (rv != APR_SUCCESS) { fprintf(stderr, "Errore in recv\n"); fflush(stderr); return 1; } 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); return 0; }