Example #1
0
/* {{{ mysqlnd_object_factory::get_prepared_statement */
static MYSQLND_STMT *
MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement)(MYSQLND_CONN_DATA * const conn)
{
	size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
	MYSQLND_STMT * ret = mnd_pecalloc(1, alloc_size, conn->persistent);
	MYSQLND_STMT_DATA * stmt = NULL;

	DBG_ENTER("mysqlnd_object_factory::get_prepared_statement");
	do {
		if (!ret) {
			break;
		}
		ret->m = mysqlnd_stmt_get_methods();
		ret->persistent = conn->persistent;

		stmt = ret->data = mnd_pecalloc(1, sizeof(MYSQLND_STMT_DATA), conn->persistent);
		DBG_INF_FMT("stmt=%p", stmt);
		if (!stmt) {
			break;
		}
		stmt->persistent = conn->persistent;
		stmt->error_info = &(stmt->error_info_impl);
		stmt->upsert_status = &(stmt->upsert_status_impl);
		stmt->state = MYSQLND_STMT_INITTED;
		stmt->execute_cmd_buffer.length = 4096;
		stmt->execute_cmd_buffer.buffer = mnd_pemalloc(stmt->execute_cmd_buffer.length, stmt->persistent);
		if (!stmt->execute_cmd_buffer.buffer) {
			break;
		}

		stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
		/*
		  Mark that we reference the connection, thus it won't be
		  be destructed till there is open statements. The last statement
		  or normal query result will close it then.
		*/
		stmt->conn = conn->m->get_reference(conn);
		stmt->error_info->error_list = mnd_pecalloc(1, sizeof(zend_llist), ret->persistent);
		if (!stmt->error_info->error_list) {
			break;
		}

		zend_llist_init(stmt->error_info->error_list, sizeof(MYSQLND_ERROR_LIST_ELEMENT), (llist_dtor_func_t) mysqlnd_error_list_pdtor, conn->persistent);

		DBG_RETURN(ret);
	} while (0);

	SET_OOM_ERROR(*conn->error_info);
	if (ret) {
		ret->m->dtor(ret, TRUE);
		ret = NULL;
	}
	DBG_RETURN(NULL);
}
Example #2
0
/* {{{ 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);
}
Example #3
0
/* {{{ 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::clone_metadata */
static MYSQLND_RES_METADATA *
MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata)(const MYSQLND_RES_METADATA * const meta, const zend_bool persistent)
{
	unsigned int i;
	/* +1 is to have empty marker at the end */
	MYSQLND_RES_METADATA * new_meta = NULL;
	MYSQLND_FIELD * new_fields;
	MYSQLND_FIELD * orig_fields = meta->fields;
	size_t len = meta->field_count * sizeof(struct mysqlnd_field_hash_key);

	DBG_ENTER("mysqlnd_res_meta::clone_metadata");
	DBG_INF_FMT("persistent=%u", persistent);

	new_meta = mnd_pecalloc(1, sizeof(MYSQLND_RES_METADATA), persistent);
	if (!new_meta) {
		goto oom;
	}
	new_meta->persistent = persistent;
	new_meta->m = meta->m;

	new_fields = mnd_pecalloc(meta->field_count + 1, sizeof(MYSQLND_FIELD), persistent);
	if (!new_fields) {
		goto oom;
	}

	new_meta->zend_hash_keys = mnd_pemalloc(len, persistent);
	if (!new_meta->zend_hash_keys) {
		goto oom;
	}
	memcpy(new_meta->zend_hash_keys, meta->zend_hash_keys, len);

	/*
	  This will copy also the strings and the root, which we will have
	  to adjust in the loop
	*/
	memcpy(new_fields, orig_fields, (meta->field_count) * sizeof(MYSQLND_FIELD));
	for (i = 0; i < meta->field_count; i++) {
		/* First copy the root, then field by field adjust the pointers */
		new_fields[i].root = mnd_pemalloc(orig_fields[i].root_len, persistent);

		if (!new_fields[i].root) {
			goto oom;
		}

		memcpy(new_fields[i].root, orig_fields[i].root, new_fields[i].root_len);

		if (orig_fields[i].sname) {
			new_fields[i].sname = zend_string_copy(orig_fields[i].sname);
			new_fields[i].name = ZSTR_VAL(new_fields[i].sname);
			new_fields[i].name_length = ZSTR_LEN(new_fields[i].sname);
		}

		if (orig_fields[i].org_name && orig_fields[i].org_name != mysqlnd_empty_string) {
			new_fields[i].org_name = new_fields[i].root +
				(orig_fields[i].org_name - orig_fields[i].root);
		}
		if (orig_fields[i].table && orig_fields[i].table != mysqlnd_empty_string) {
			new_fields[i].table	= new_fields[i].root +
				(orig_fields[i].table - orig_fields[i].root);
		}
		if (orig_fields[i].org_table && orig_fields[i].org_table != mysqlnd_empty_string) {
			new_fields[i].org_table	= new_fields[i].root +
				(orig_fields[i].org_table - orig_fields[i].root);
		}
		if (orig_fields[i].db && orig_fields[i].db != mysqlnd_empty_string) {
			new_fields[i].db = new_fields[i].root + (orig_fields[i].db - orig_fields[i].root);
		}
		if (orig_fields[i].catalog && orig_fields[i].catalog != mysqlnd_empty_string) {
			new_fields[i].catalog = new_fields[i].root + (orig_fields[i].catalog - orig_fields[i].root);
		}
		/* def is not on the root, if allocated at all */
		if (orig_fields[i].def) {
			new_fields[i].def = mnd_pemalloc(orig_fields[i].def_length + 1, persistent);
			if (!new_fields[i].def) {
				goto oom;
			}
			/* copy the trailing \0 too */
			memcpy(new_fields[i].def, orig_fields[i].def, orig_fields[i].def_length + 1);
		}
	}
	new_meta->current_field = 0;
	new_meta->field_count = meta->field_count;

	new_meta->fields = new_fields;

	DBG_RETURN(new_meta);
oom:
	if (new_meta) {
		new_meta->m->free_metadata(new_meta);
		new_meta = NULL;
	}
	DBG_RETURN(NULL);
}