/* {{{ mysqlnd_vio::free_contents */ static void MYSQLND_METHOD(mysqlnd_vio, free_contents)(MYSQLND_VIO * net) { zend_bool pers = net->persistent; DBG_ENTER("mysqlnd_vio::free_contents"); if (net->data->options.ssl_key) { mnd_pefree(net->data->options.ssl_key, pers); net->data->options.ssl_key = NULL; } if (net->data->options.ssl_cert) { mnd_pefree(net->data->options.ssl_cert, pers); net->data->options.ssl_cert = NULL; } if (net->data->options.ssl_ca) { mnd_pefree(net->data->options.ssl_ca, pers); net->data->options.ssl_ca = NULL; } if (net->data->options.ssl_capath) { mnd_pefree(net->data->options.ssl_capath, pers); net->data->options.ssl_capath = NULL; } if (net->data->options.ssl_cipher) { mnd_pefree(net->data->options.ssl_cipher, pers); net->data->options.ssl_cipher = NULL; } DBG_VOID_RETURN; }
/* {{{ mysqlnd_object_factory::get_io_channel */ PHPAPI MYSQLND_NET * MYSQLND_METHOD(mysqlnd_object_factory, get_io_channel)(zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info) { size_t net_alloc_size = sizeof(MYSQLND_NET) + mysqlnd_plugin_count() * sizeof(void *); size_t net_data_alloc_size = sizeof(MYSQLND_NET_DATA) + mysqlnd_plugin_count() * sizeof(void *); MYSQLND_NET * net = mnd_pecalloc(1, net_alloc_size, persistent); MYSQLND_NET_DATA * net_data = mnd_pecalloc(1, net_data_alloc_size, persistent); DBG_ENTER("mysqlnd_object_factory::get_io_channel"); DBG_INF_FMT("persistent=%u", persistent); if (net && net_data) { net->data = net_data; net->persistent = net->data->persistent = persistent; net->data->m = *mysqlnd_net_get_methods(); if (PASS != net->data->m.init(net, stats, error_info)) { net->data->m.dtor(net, stats, error_info); net = NULL; } } else { if (net_data) { mnd_pefree(net_data, persistent); net_data = NULL; } if (net) { mnd_pefree(net, persistent); net = NULL; } } DBG_RETURN(net); }
/* {{{ mysqlnd_res_meta::free */ static void MYSQLND_METHOD(mysqlnd_res_meta, free)(MYSQLND_RES_METADATA * meta) { int i; MYSQLND_FIELD *fields; DBG_ENTER("mysqlnd_res_meta::free"); DBG_INF_FMT("persistent=%u", meta->persistent); if ((fields = meta->fields)) { DBG_INF("Freeing fields metadata"); i = meta->field_count; while (i--) { php_mysqlnd_free_field_metadata(fields++, meta->persistent); } mnd_pefree(meta->fields, meta->persistent); meta->fields = NULL; } if (meta->zend_hash_keys) { DBG_INF("Freeing zend_hash_keys"); mnd_pefree(meta->zend_hash_keys, meta->persistent); meta->zend_hash_keys = NULL; } DBG_INF("Freeing metadata structure"); mnd_pefree(meta, meta->persistent); DBG_VOID_RETURN; }
/* {{{ mysqlnd_vio::dtor */ static void MYSQLND_METHOD(mysqlnd_vio, dtor)(MYSQLND_VIO * const vio, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info) { DBG_ENTER("mysqlnd_vio::dtor"); if (vio) { vio->data->m.free_contents(vio); vio->data->m.close_stream(vio, stats, error_info); mnd_pefree(vio->data, vio->data->persistent); mnd_pefree(vio, vio->persistent); } DBG_VOID_RETURN; }
/* {{{ php_mysqlnd_free_field_metadata */ static void php_mysqlnd_free_field_metadata(MYSQLND_FIELD *meta, zend_bool persistent TSRMLS_DC) { if (meta) { if (meta->root) { mnd_pefree(meta->root, persistent); meta->root = NULL; } if (meta->def) { mnd_pefree(meta->def, persistent); meta->def = NULL; } } }
/* {{{ php_mysqlnd_free_field_metadata */ static void php_mysqlnd_free_field_metadata(MYSQLND_FIELD *meta, zend_bool persistent) { if (meta) { if (meta->root) { mnd_pefree(meta->root, persistent); meta->root = NULL; } if (meta->def) { mnd_pefree(meta->def, persistent); meta->def = NULL; } if (meta->sname) { zend_string_release(meta->sname); } } }
/* {{{ mysqlnd_net::dtor */ static void MYSQLND_METHOD(mysqlnd_net, dtor)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info) { DBG_ENTER("mysqlnd_net::dtor"); if (net) { net->data->m.free_contents(net); net->data->m.close_stream(net, stats, error_info); if (net->cmd_buffer.buffer) { DBG_INF("Freeing cmd buffer"); mnd_pefree(net->cmd_buffer.buffer, net->persistent); net->cmd_buffer.buffer = NULL; } mnd_pefree(net->data, net->data->persistent); mnd_pefree(net, net->persistent); } DBG_VOID_RETURN; }
/* {{{ mysqlnd_error_list_pdtor */ static void mysqlnd_error_list_pdtor(void * pDest) { MYSQLND_ERROR_LIST_ELEMENT * element = (MYSQLND_ERROR_LIST_ELEMENT *) pDest; DBG_ENTER("mysqlnd_error_list_pdtor"); if (element->error) { mnd_pefree(element->error, TRUE); } DBG_VOID_RETURN; }
/* {{{ mysqlnd_res_meta::read_metadata */ static enum_func_status MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND_CONN_DATA * conn) { unsigned int i = 0; MYSQLND_PACKET_RES_FIELD * field_packet; DBG_ENTER("mysqlnd_res_meta::read_metadata"); field_packet = conn->payload_decoder_factory->m.get_result_field_packet(conn->payload_decoder_factory, FALSE); if (!field_packet) { SET_OOM_ERROR(conn->error_info); DBG_RETURN(FAIL); } field_packet->persistent_alloc = meta->persistent; for (;i < meta->field_count; i++) { zend_ulong idx; if (meta->fields[i].root) { /* We re-read metadata for PS */ mnd_pefree(meta->fields[i].root, meta->persistent); meta->fields[i].root = NULL; } field_packet->metadata = &(meta->fields[i]); if (FAIL == PACKET_READ(field_packet)) { PACKET_FREE(field_packet); DBG_RETURN(FAIL); } if (field_packet->error_info.error_no) { COPY_CLIENT_ERROR(conn->error_info, field_packet->error_info); /* Return back from CONN_QUERY_SENT */ PACKET_FREE(field_packet); DBG_RETURN(FAIL); } if (mysqlnd_ps_fetch_functions[meta->fields[i].type].func == NULL) { DBG_ERR_FMT("Unknown type %u sent by the server. Please send a report to the developers", meta->fields[i].type); php_error_docref(NULL, E_WARNING, "Unknown type %u sent by the server. Please send a report to the developers", meta->fields[i].type); PACKET_FREE(field_packet); DBG_RETURN(FAIL); } /* For BC we have to check whether the key is numeric and use it like this */ if ((meta->zend_hash_keys[i].is_numeric = ZEND_HANDLE_NUMERIC(field_packet->metadata->sname, idx))) { meta->zend_hash_keys[i].key = idx; } } PACKET_FREE(field_packet); DBG_RETURN(PASS); }
/* {{{ mysqlnd_object_factory::get_connection */ static MYSQLND * MYSQLND_METHOD(mysqlnd_object_factory, get_connection)(zend_bool persistent TSRMLS_DC) { size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *); size_t alloc_size_ret_data = sizeof(MYSQLND_CONN_DATA) + mysqlnd_plugin_count() * sizeof(void *); MYSQLND * new_object; MYSQLND_CONN_DATA * data; DBG_ENTER("mysqlnd_driver::get_connection"); DBG_INF_FMT("persistent=%u", persistent); new_object = mnd_pecalloc(1, alloc_size_ret, persistent); if (!new_object) { DBG_RETURN(NULL); } new_object->data = mnd_pecalloc(1, alloc_size_ret_data, persistent); if (!new_object->data) { mnd_pefree(new_object, persistent); DBG_RETURN(NULL); } new_object->persistent = persistent; new_object->m = mysqlnd_conn_get_methods(); data = new_object->data; data->error_info = &(data->error_info_impl); data->options = &(data->options_impl); data->upsert_status = &(data->upsert_status_impl); data->persistent = persistent; data->m = mysqlnd_conn_data_get_methods(); CONN_SET_STATE(data, CONN_ALLOCED); data->m->get_reference(data TSRMLS_CC); if (PASS != data->m->init(data TSRMLS_CC)) { new_object->m->dtor(new_object TSRMLS_CC); DBG_RETURN(NULL); } data->error_info->error_list = mnd_pecalloc(1, sizeof(zend_llist), persistent); if (!data->error_info->error_list) { new_object->m->dtor(new_object TSRMLS_CC); DBG_RETURN(NULL); } else { zend_llist_init(data->error_info->error_list, sizeof(MYSQLND_ERROR_LIST_ELEMENT), (llist_dtor_func_t)mysqlnd_error_list_pdtor, persistent); } DBG_RETURN(new_object); }
/* {{{ mysqlnd_com_init_db_run */ static enum_func_status mysqlnd_com_init_db_run(void *cmd) { struct st_mysqlnd_protocol_com_init_db_command * command = (struct st_mysqlnd_protocol_com_init_db_command *) cmd; enum_func_status ret = FAIL; MYSQLND_CONN_DATA * conn = command->context.conn; const MYSQLND_CSTRING db = command->context.db; func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command; func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response; DBG_ENTER("mysqlnd_com_init_db_run"); ret = send_command(conn->payload_decoder_factory, COM_INIT_DB, (zend_uchar*) command->context.db.s, command->context.db.l, FALSE, &conn->state, conn->error_info, conn->upsert_status, conn->stats, conn->m->send_close, conn); if (PASS == ret) { ret = send_command_handle_response(conn->payload_decoder_factory, PROT_OK_PACKET, FALSE, COM_INIT_DB, TRUE, conn->error_info, conn->upsert_status, &conn->last_message, conn->persistent); } /* The server sends 0 but libmysql doesn't read it and has established a protocol of giving back -1. Thus we have to follow it :( */ UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); if (ret == PASS) { if (conn->connect_or_select_db.s) { mnd_pefree(conn->connect_or_select_db.s, conn->persistent); } conn->connect_or_select_db.s = mnd_pestrndup(db.s, db.l, conn->persistent); conn->connect_or_select_db.l = db.l; if (!conn->connect_or_select_db.s) { /* OOM */ SET_OOM_ERROR(conn->error_info); ret = FAIL; } } DBG_RETURN(ret); }
/* {{{ mysqlnd_net::free_contents */ static void MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net) { zend_bool pers = net->persistent; DBG_ENTER("mysqlnd_net::free_contents"); #ifdef MYSQLND_COMPRESSION_ENABLED if (net->uncompressed_data) { net->uncompressed_data->free_buffer(&net->uncompressed_data); } #endif if (net->data->options.ssl_key) { mnd_pefree(net->data->options.ssl_key, pers); net->data->options.ssl_key = NULL; } if (net->data->options.ssl_cert) { mnd_pefree(net->data->options.ssl_cert, pers); net->data->options.ssl_cert = NULL; } if (net->data->options.ssl_ca) { mnd_pefree(net->data->options.ssl_ca, pers); net->data->options.ssl_ca = NULL; } if (net->data->options.ssl_capath) { mnd_pefree(net->data->options.ssl_capath, pers); net->data->options.ssl_capath = NULL; } if (net->data->options.ssl_cipher) { mnd_pefree(net->data->options.ssl_cipher, pers); net->data->options.ssl_cipher = NULL; } if (net->data->options.sha256_server_public_key) { mnd_pefree(net->data->options.sha256_server_public_key, pers); net->data->options.sha256_server_public_key = NULL; } DBG_VOID_RETURN; }
/* {{{ mysqlnd_vio::set_client_option */ static enum_func_status MYSQLND_METHOD(mysqlnd_vio, set_client_option)(MYSQLND_VIO * const net, enum_mysqlnd_client_option option, const char * const value) { DBG_ENTER("mysqlnd_vio::set_client_option"); DBG_INF_FMT("option=%u", option); switch (option) { case MYSQLND_OPT_NET_CMD_BUFFER_SIZE: DBG_INF("MYSQLND_OPT_NET_CMD_BUFFER_SIZE"); if (*(unsigned int*) value < MYSQLND_NET_CMD_BUFFER_MIN_SIZE) { DBG_RETURN(FAIL); } net->cmd_buffer.length = *(unsigned int*) value; DBG_INF_FMT("new_length="MYSQLND_SZ_T_SPEC, net->cmd_buffer.length); if (!net->cmd_buffer.buffer) { net->cmd_buffer.buffer = mnd_pemalloc(net->cmd_buffer.length, net->persistent); } else { net->cmd_buffer.buffer = mnd_perealloc(net->cmd_buffer.buffer, net->cmd_buffer.length, net->persistent); } break; case MYSQLND_OPT_NET_READ_BUFFER_SIZE: DBG_INF("MYSQLND_OPT_NET_READ_BUFFER_SIZE"); net->data->options.net_read_buffer_size = *(unsigned int*) value; DBG_INF_FMT("new_length="MYSQLND_SZ_T_SPEC, net->data->options.net_read_buffer_size); break; case MYSQL_OPT_CONNECT_TIMEOUT: DBG_INF("MYSQL_OPT_CONNECT_TIMEOUT"); net->data->options.timeout_connect = *(unsigned int*) value; break; case MYSQLND_OPT_SSL_KEY: { zend_bool pers = net->persistent; if (net->data->options.ssl_key) { mnd_pefree(net->data->options.ssl_key, pers); } net->data->options.ssl_key = value? mnd_pestrdup(value, pers) : NULL; break; } case MYSQLND_OPT_SSL_CERT: { zend_bool pers = net->persistent; if (net->data->options.ssl_cert) { mnd_pefree(net->data->options.ssl_cert, pers); } net->data->options.ssl_cert = value? mnd_pestrdup(value, pers) : NULL; break; } case MYSQLND_OPT_SSL_CA: { zend_bool pers = net->persistent; if (net->data->options.ssl_ca) { mnd_pefree(net->data->options.ssl_ca, pers); } net->data->options.ssl_ca = value? mnd_pestrdup(value, pers) : NULL; break; } case MYSQLND_OPT_SSL_CAPATH: { zend_bool pers = net->persistent; if (net->data->options.ssl_capath) { mnd_pefree(net->data->options.ssl_capath, pers); } net->data->options.ssl_capath = value? mnd_pestrdup(value, pers) : NULL; break; } case MYSQLND_OPT_SSL_CIPHER: { zend_bool pers = net->persistent; if (net->data->options.ssl_cipher) { mnd_pefree(net->data->options.ssl_cipher, pers); } net->data->options.ssl_cipher = value? mnd_pestrdup(value, pers) : NULL; break; } case MYSQLND_OPT_SSL_PASSPHRASE: { zend_bool pers = net->persistent; if (net->data->options.ssl_passphrase) { mnd_pefree(net->data->options.ssl_passphrase, pers); } net->data->options.ssl_passphrase = value? mnd_pestrdup(value, pers) : NULL; break; } case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: { enum mysqlnd_ssl_peer val = *((enum mysqlnd_ssl_peer *)value); switch (val) { case MYSQLND_SSL_PEER_VERIFY: DBG_INF("MYSQLND_SSL_PEER_VERIFY"); break; case MYSQLND_SSL_PEER_DONT_VERIFY: DBG_INF("MYSQLND_SSL_PEER_DONT_VERIFY"); break; case MYSQLND_SSL_PEER_DEFAULT: DBG_INF("MYSQLND_SSL_PEER_DEFAULT"); val = MYSQLND_SSL_PEER_DEFAULT; break; default: DBG_INF("default = MYSQLND_SSL_PEER_DEFAULT_ACTION"); val = MYSQLND_SSL_PEER_DEFAULT; break; } net->data->options.ssl_verify_peer = val; break; } case MYSQL_OPT_READ_TIMEOUT: net->data->options.timeout_read = *(unsigned int*) value; break; #ifdef WHEN_SUPPORTED_BY_MYSQLI case MYSQL_OPT_WRITE_TIMEOUT: net->data->options.timeout_write = *(unsigned int*) value; break; #endif default: DBG_RETURN(FAIL); } DBG_RETURN(PASS); }
/* {{{ mysqlnd_auth_change_user */ enum_func_status mysqlnd_auth_change_user(MYSQLND_CONN_DATA * const conn, const char * const user, const size_t user_len, const char * const passwd, const size_t passwd_len, const char * const db, const size_t db_len, const zend_bool silent, zend_bool use_full_blown_auth_packet, const char * const auth_protocol, zend_uchar * auth_plugin_data, size_t auth_plugin_data_len, char ** switch_to_auth_protocol, size_t * switch_to_auth_protocol_len, zend_uchar ** switch_to_auth_protocol_data, size_t * switch_to_auth_protocol_data_len ) { enum_func_status ret = FAIL; const MYSQLND_CHARSET * old_cs = conn->charset; MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * change_auth_resp_packet = NULL; MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp = NULL; MYSQLND_PACKET_AUTH * auth_packet = NULL; DBG_ENTER("mysqlnd_auth_change_user"); chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE); if (!chg_user_resp) { SET_OOM_ERROR(*conn->error_info); goto end; } if (use_full_blown_auth_packet != TRUE) { change_auth_resp_packet = conn->protocol->m.get_change_auth_response_packet(conn->protocol, FALSE); if (!change_auth_resp_packet) { SET_OOM_ERROR(*conn->error_info); goto end; } change_auth_resp_packet->auth_data = auth_plugin_data; change_auth_resp_packet->auth_data_len = auth_plugin_data_len; if (!PACKET_WRITE(change_auth_resp_packet, conn)) { CONN_SET_STATE(conn, CONN_QUIT_SENT); SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); goto end; } } else { auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE); if (!auth_packet) { SET_OOM_ERROR(*conn->error_info); goto end; } auth_packet->is_change_user_packet = TRUE; auth_packet->user = user; auth_packet->db = db; auth_packet->db_len = db_len; auth_packet->silent = silent; auth_packet->auth_data = auth_plugin_data; auth_packet->auth_data_len = auth_plugin_data_len; auth_packet->auth_plugin_name = auth_protocol; if (conn->m->get_server_version(conn) >= 50123) { auth_packet->charset_no = conn->charset->nr; } if (!PACKET_WRITE(auth_packet, conn)) { CONN_SET_STATE(conn, CONN_QUIT_SENT); SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); goto end; } } ret = PACKET_READ(chg_user_resp, conn); COPY_CLIENT_ERROR(*conn->error_info, chg_user_resp->error_info); if (0xFE == chg_user_resp->response_code) { ret = FAIL; if (!chg_user_resp->new_auth_protocol) { DBG_ERR(mysqlnd_old_passwd); SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd); } else { *switch_to_auth_protocol = mnd_pestrndup(chg_user_resp->new_auth_protocol, chg_user_resp->new_auth_protocol_len, FALSE); *switch_to_auth_protocol_len = chg_user_resp->new_auth_protocol_len; if (chg_user_resp->new_auth_protocol_data) { *switch_to_auth_protocol_data_len = chg_user_resp->new_auth_protocol_data_len; *switch_to_auth_protocol_data = mnd_emalloc(*switch_to_auth_protocol_data_len); memcpy(*switch_to_auth_protocol_data, chg_user_resp->new_auth_protocol_data, *switch_to_auth_protocol_data_len); } else { *switch_to_auth_protocol_data = NULL; *switch_to_auth_protocol_data_len = 0; } } } if (conn->error_info->error_no) { ret = FAIL; /* COM_CHANGE_USER is broken in 5.1. At least in 5.1.15 and 5.1.14, 5.1.11 is immune. bug#25371 mysql_change_user() triggers "packets out of sync" When it gets fixed, there should be one more check here */ if (conn->m->get_server_version(conn) > 50113L &&conn->m->get_server_version(conn) < 50118L) { MYSQLND_PACKET_OK * redundant_error_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE); if (redundant_error_packet) { PACKET_READ(redundant_error_packet, conn); PACKET_FREE(redundant_error_packet); DBG_INF_FMT("Server is %u, buggy, sends two ERR messages", conn->m->get_server_version(conn)); } else { SET_OOM_ERROR(*conn->error_info); } } } if (ret == PASS) { char * tmp = NULL; /* if we get conn->user as parameter and then we first free it, then estrndup it, we will crash */ tmp = mnd_pestrndup(user, user_len, conn->persistent); if (conn->user) { mnd_pefree(conn->user, conn->persistent); } conn->user = tmp; tmp = mnd_pestrdup(passwd, conn->persistent); if (conn->passwd) { mnd_pefree(conn->passwd, conn->persistent); } conn->passwd = tmp; if (conn->last_message) { mnd_pefree(conn->last_message, conn->persistent); conn->last_message = NULL; } memset(conn->upsert_status, 0, sizeof(*conn->upsert_status)); /* set charset for old servers */ if (conn->m->get_server_version(conn) < 50123) { ret = conn->m->set_charset(conn, old_cs->name); } } else if (ret == FAIL && chg_user_resp->server_asked_323_auth == TRUE) { /* old authentication with new server !*/ DBG_ERR(mysqlnd_old_passwd); SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd); } end: PACKET_FREE(change_auth_resp_packet); PACKET_FREE(auth_packet); PACKET_FREE(chg_user_resp); DBG_RETURN(ret); }
/* {{{ mysqlnd_run_authentication */ enum_func_status mysqlnd_run_authentication( MYSQLND_CONN_DATA * conn, const char * const user, const char * const passwd, const size_t passwd_len, const char * const db, const size_t db_len, const MYSQLND_STRING auth_plugin_data, const char * const auth_protocol, unsigned int charset_no, const MYSQLND_SESSION_OPTIONS * const session_options, zend_ulong mysql_flags, zend_bool silent, zend_bool is_change_user ) { enum_func_status ret = FAIL; zend_bool first_call = TRUE; char * switch_to_auth_protocol = NULL; size_t switch_to_auth_protocol_len = 0; char * requested_protocol = NULL; zend_uchar * plugin_data; size_t plugin_data_len; DBG_ENTER("mysqlnd_run_authentication"); plugin_data_len = auth_plugin_data.l; plugin_data = mnd_emalloc(plugin_data_len + 1); if (!plugin_data) { goto end; } memcpy(plugin_data, auth_plugin_data.s, plugin_data_len); plugin_data[plugin_data_len] = '\0'; requested_protocol = mnd_pestrdup(auth_protocol? auth_protocol : MYSQLND_DEFAULT_AUTH_PROTOCOL, FALSE); if (!requested_protocol) { goto end; } do { struct st_mysqlnd_authentication_plugin * auth_plugin = conn->m->fetch_auth_plugin_by_name(requested_protocol); if (!auth_plugin) { php_error_docref(NULL, E_WARNING, "The server requested authentication method unknown to the client [%s]", requested_protocol); SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method unknown to the client"); goto end; } DBG_INF("plugin found"); { zend_uchar * switch_to_auth_protocol_data = NULL; size_t switch_to_auth_protocol_data_len = 0; zend_uchar * scrambled_data = NULL; size_t scrambled_data_len = 0; switch_to_auth_protocol = NULL; switch_to_auth_protocol_len = 0; if (conn->authentication_plugin_data.s) { mnd_pefree(conn->authentication_plugin_data.s, conn->persistent); conn->authentication_plugin_data.s = NULL; } conn->authentication_plugin_data.l = plugin_data_len; conn->authentication_plugin_data.s = mnd_pemalloc(conn->authentication_plugin_data.l, conn->persistent); if (!conn->authentication_plugin_data.s) { SET_OOM_ERROR(conn->error_info); goto end; } memcpy(conn->authentication_plugin_data.s, plugin_data, plugin_data_len); DBG_INF_FMT("salt(%d)=[%.*s]", plugin_data_len, plugin_data_len, plugin_data); /* The data should be allocated with malloc() */ scrambled_data = auth_plugin->methods.get_auth_data(NULL, &scrambled_data_len, conn, user, passwd, passwd_len, plugin_data, plugin_data_len, session_options, conn->protocol_frame_codec->data, mysql_flags); if (conn->error_info->error_no) { goto end; } if (FALSE == is_change_user) { ret = mysqlnd_auth_handshake(conn, user, passwd, passwd_len, db, db_len, session_options, mysql_flags, charset_no, first_call, requested_protocol, scrambled_data, scrambled_data_len, &switch_to_auth_protocol, &switch_to_auth_protocol_len, &switch_to_auth_protocol_data, &switch_to_auth_protocol_data_len ); } else { ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, passwd_len, db, db_len, silent, first_call, requested_protocol, scrambled_data, scrambled_data_len, &switch_to_auth_protocol, &switch_to_auth_protocol_len, &switch_to_auth_protocol_data, &switch_to_auth_protocol_data_len ); } first_call = FALSE; free(scrambled_data); DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a"); if (requested_protocol && switch_to_auth_protocol) { mnd_efree(requested_protocol); requested_protocol = switch_to_auth_protocol; } if (plugin_data) { mnd_efree(plugin_data); } plugin_data_len = switch_to_auth_protocol_data_len; plugin_data = switch_to_auth_protocol_data; } DBG_INF_FMT("conn->error_info->error_no = %d", conn->error_info->error_no); } while (ret == FAIL && conn->error_info->error_no == 0 && switch_to_auth_protocol != NULL); if (ret == PASS) { DBG_INF_FMT("saving requested_protocol=%s", requested_protocol); conn->m->set_client_option(conn, MYSQLND_OPT_AUTH_PROTOCOL, requested_protocol); } end: if (plugin_data) { mnd_efree(plugin_data); } if (requested_protocol) { mnd_efree(requested_protocol); } DBG_RETURN(ret); }
/* {{{ mysqlnd_res_meta::read_metadata */ static enum_func_status MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND_CONN_DATA * conn) { unsigned int i = 0; MYSQLND_PACKET_RES_FIELD * field_packet; DBG_ENTER("mysqlnd_res_meta::read_metadata"); field_packet = conn->payload_decoder_factory->m.get_result_field_packet(conn->payload_decoder_factory, FALSE); if (!field_packet) { SET_OOM_ERROR(conn->error_info); DBG_RETURN(FAIL); } field_packet->persistent_alloc = meta->persistent; for (;i < meta->field_count; i++) { zend_ulong idx; if (meta->fields[i].root) { /* We re-read metadata for PS */ mnd_pefree(meta->fields[i].root, meta->persistent); meta->fields[i].root = NULL; } field_packet->metadata = &(meta->fields[i]); if (FAIL == PACKET_READ(field_packet)) { PACKET_FREE(field_packet); DBG_RETURN(FAIL); } if (field_packet->error_info.error_no) { COPY_CLIENT_ERROR(conn->error_info, field_packet->error_info); /* Return back from CONN_QUERY_SENT */ PACKET_FREE(field_packet); DBG_RETURN(FAIL); } if (mysqlnd_ps_fetch_functions[meta->fields[i].type].func == NULL) { DBG_ERR_FMT("Unknown type %u sent by the server. Please send a report to the developers", meta->fields[i].type); php_error_docref(NULL, E_WARNING, "Unknown type %u sent by the server. Please send a report to the developers", meta->fields[i].type); PACKET_FREE(field_packet); DBG_RETURN(FAIL); } if (meta->fields[i].type == MYSQL_TYPE_BIT) { size_t field_len; DBG_INF("BIT"); ++meta->bit_fields_count; /* .length is in bits */ field_len = meta->fields[i].length / 8; /* If there is rest, add one byte : 8 bits = 1 byte but 9 bits = 2 bytes */ if (meta->fields[i].length % 8) { ++field_len; } switch (field_len) { case 8: case 7: case 6: case 5: meta->bit_fields_total_len += 20;/* 21 digis, no sign*/ break; case 4: meta->bit_fields_total_len += 10;/* 2 000 000 000*/ break; case 3: meta->bit_fields_total_len += 8;/* 12 000 000*/ break; case 2: meta->bit_fields_total_len += 5;/* 32 500 */ break; case 1: meta->bit_fields_total_len += 3;/* 120 */ break; } } /* For BC we have to check whether the key is numeric and use it like this */ if ((meta->zend_hash_keys[i].is_numeric = ZEND_HANDLE_NUMERIC(field_packet->metadata->sname, idx))) { meta->zend_hash_keys[i].key = idx; } } PACKET_FREE(field_packet); DBG_RETURN(PASS); }