static int lua_proto_append_response_packet (lua_State *L) {
	GString *packet;
	network_mysqld_auth_response *auth_response;
	gboolean needs_auto_capabilities = TRUE;
	guint32 server_capabilities;

	luaL_checktype(L, 1, LUA_TTABLE);

	/* extract the server_capabilities first as we need them to create the struct */
	lua_getfield_literal(L, -1, C("server_capabilities"));
	if (lua_isnil(L, -1)) {
		return luaL_error(L, ".server_capabilities has to be set");
	} else if (lua_isnumber(L, -1)) {
		server_capabilities = lua_tointeger(L, -1);
	} else {
		return luaL_error(L, ".server_capabilities has to be a number");
	}
	lua_pop(L, 1);

	packet = g_string_new(NULL);	
	auth_response = network_mysqld_auth_response_new(server_capabilities);

	lua_getfield_literal(L, -1, C("capabilities"));
	if (!lua_isnil(L, -1)) {
		auth_response->client_capabilities = lua_tointeger(L, -1);
		needs_auto_capabilities = FALSE;
	}
	lua_pop(L, 1);

	LUA_IMPORT_INT(auth_response, max_packet_size);
	LUA_IMPORT_INT(auth_response, charset);

	LUA_IMPORT_STR(auth_response, username);
	LUA_IMPORT_STR_FROM(auth_response, auth_plugin_data, "response");
	LUA_IMPORT_STR(auth_response, auth_plugin_name);
	LUA_IMPORT_STR(auth_response, database);

	if (network_mysqld_proto_append_auth_response(packet, auth_response)) {
		network_mysqld_auth_response_free(auth_response);
		g_string_free(packet, TRUE);

		luaL_error(L, "to_response_packet() failed");
		g_string_free(packet, TRUE);
		return 0;
	}
	
	network_mysqld_auth_response_free(auth_response);

	lua_pushlstring(L, S(packet));
	
	g_string_free(packet, TRUE);

	return 1;
}
Esempio n. 2
0
static network_mysqld_lua_stmt_ret master_lua_read_query(network_mysqld_con *con) {
    network_mysqld_con_lua_t *st = con->plugin_con_state;
    char command = -1;
    network_socket *recv_sock = con->client;
    GList   *chunk  = recv_sock->recv_queue->chunks->head;
    GString *packet = chunk->data;

    if (packet->len < NET_HEADER_SIZE) return PROXY_SEND_QUERY; /* packet too short */

    command = packet->str[NET_HEADER_SIZE + 0];

    if (COM_QUERY == command) {
        /* we need some more data after the COM_QUERY */
        if (packet->len < NET_HEADER_SIZE + 2) return PROXY_SEND_QUERY;

        /* LOAD DATA INFILE is nasty */
        if (packet->len - NET_HEADER_SIZE - 1 >= sizeof("LOAD ") - 1 &&
                0 == g_ascii_strncasecmp(packet->str + NET_HEADER_SIZE + 1, C("LOAD "))) return PROXY_SEND_QUERY;
    }

    /* reset the query status */
    network_injection_queue_reset(st->injected.queries);

    /* ok, here we go */

#ifdef HAVE_LUA_H
    switch(network_mysqld_con_lua_register_callback(con, con->config->lua_script)) {
    case REGISTER_CALLBACK_SUCCESS:
        break;
    case REGISTER_CALLBACK_LOAD_FAILED:
        network_mysqld_con_send_error(con->client, C("MySQL Proxy Lua script failed to load. Check the error log."));
        con->state = CON_STATE_SEND_ERROR;
        return PROXY_SEND_RESULT;
    case REGISTER_CALLBACK_EXECUTE_FAILED:
        network_mysqld_con_send_error(con->client, C("MySQL Proxy Lua script failed to execute. Check the error log."));
        con->state = CON_STATE_SEND_ERROR;
        return PROXY_SEND_RESULT;
    }

    if (st->L) {
        lua_State *L = st->L;
        network_mysqld_lua_stmt_ret ret = PROXY_NO_DECISION;

        g_assert(lua_isfunction(L, -1));
        lua_getfenv(L, -1);
        g_assert(lua_istable(L, -1));

        /**
         * reset proxy.response to a empty table
         */
        lua_getfield(L, -1, "proxy");
        g_assert(lua_istable(L, -1));

        lua_newtable(L);
        lua_setfield(L, -2, "response");

        lua_pop(L, 1);

        /**
         * get the call back
         */
        lua_getfield_literal(L, -1, C("read_query"));
        if (lua_isfunction(L, -1)) {

            /* pass the packet as parameter */
            lua_pushlstring(L, packet->str + NET_HEADER_SIZE, packet->len - NET_HEADER_SIZE);

            if (lua_pcall(L, 1, 1, 0) != 0) {
                /* hmm, the query failed */
                g_critical("(read_query) %s", lua_tostring(L, -1));

                lua_pop(L, 2); /* fenv + errmsg */

                /* perhaps we should clean up ?*/

                return PROXY_SEND_QUERY;
            } else {
                if (lua_isnumber(L, -1)) {
                    ret = lua_tonumber(L, -1);
                }
                lua_pop(L, 1);
            }

            switch (ret) {
            case PROXY_SEND_RESULT:
                /* check the proxy.response table for content,
                 *
                 */


                if (network_mysqld_con_lua_handle_proxy_response(con, con->config->lua_script)) {
                    /**
                     * handling proxy.response failed
                     *
                     * send a ERR packet
                     */

                    network_mysqld_con_send_error(con->client, C("(lua) handling proxy.response failed, check error-log"));
                }

                break;
            case PROXY_NO_DECISION:
                /**
                 * PROXY_NO_DECISION and PROXY_SEND_QUERY may pick another backend
                 */
                break;
            case PROXY_SEND_QUERY:
                /* send the injected queries
                 *
                 * injection_new(..., query);
                 *
                 *  */

                if (st->injected.queries->length) {
                    ret = PROXY_SEND_INJECTION;
                }

                break;
            default:
                break;
            }
            lua_pop(L, 1); /* fenv */
        } else {
            lua_pop(L, 2); /* fenv + nil */
        }

        g_assert(lua_isfunction(L, -1));

        if (ret != PROXY_NO_DECISION) {
            return ret;
        }
    } else {
        network_mysqld_con_handle_stmt(NULL, con, packet);
        return PROXY_SEND_RESULT;
    }
#endif
    return PROXY_NO_DECISION;
}