Пример #1
0
bool
cuev_emit(struct curlev *cuev, char *url, struct curl_slist *headers,
	curlev_cb_t cb, void *cb_data)
{
	struct curlex *ex = NULL;
	CURL *easy = curl_easy_init();
	CURLMcode code;
	if (!easy) {
		xsyslog(LOG_WARNING, "curl_easy_init() failed for url '%s' (errno: %d)",
				url, errno);
		return false;
	}
	curl_easy_setopt(easy, CURLOPT_URL, url);
	curl_easy_setopt(easy, CURLOPT_VERBOSE, 0L);

	curl_easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L);
	curl_easy_setopt(easy, CURLOPT_FOLLOWLOCATION, 1L);
	curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, _curl_write_cb);
	if (cb) {
		ex = calloc(1, sizeof(*ex));
		if (!ex) {
			xsyslog(LOG_WARNING, "cuev_emit() failed: calloc(%d) with errno: %d",
				   (int)sizeof(*ex), errno);
			curl_easy_cleanup(easy);
			return false;
		}
		ex->cb = cb;
		ex->cb_data = cb_data;
		curl_easy_setopt(easy, CURLOPT_WRITEDATA, ex);
		curl_easy_setopt(easy, CURLOPT_PRIVATE, ex);
	} else {
		curl_easy_setopt(easy, CURLOPT_WRITEDATA, NULL);
		curl_easy_setopt(easy, CURLOPT_PRIVATE, NULL);
	}

	if (headers) {
		/* TODO: добавить хидеры */
	}

	if ((code = curl_multi_add_handle(cuev->multi, easy)) != CURLM_OK) {
		xsyslog(LOG_WARNING, "curl_multi_add_handle() failed for url '%s', code: %d",
				url, code);
		curl_easy_cleanup(easy);
		return false;
	}
	return true;
}
Пример #2
0
static void
_ev_timer_curl_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
{
	int running = 0;
	struct curlev *cuev = w->data;
	curl_multi_socket_action(cuev->multi, CURL_SOCKET_TIMEOUT, 0, &running);
	xsyslog(LOG_INFO, "ev timer: %p, running: %d", (void*)cuev, running);
}
Пример #3
0
static int
_curl_socket_cb(CURL *e, curl_socket_t s, int what,
		struct curlev *cuev, struct ev_io *evio)
{
	xsyslog(LOG_DEBUG, "socket #%d action: %d, evio %p", s, what, (void*)evio);
	/* события curl с сокетами (what):
	 * CURL_POLL_NONE: ничего
	 * CURL_POLL_REMOVE: удаление
	 * CURL_POLL_IN: регистрирация для чтения
	 * CURL_POLL_OUT: регистрация для записи
	 * CURL_POLL_INOUT: регистрация для чтения и записи
	 *
	 * до вызова curl_multi_assign() аргумент evio == NULL
	 */
	if (what == CURL_POLL_REMOVE) {
		xsyslog(LOG_DEBUG, "curl remove socket #%d", s);
		if (!evio) {
			xsyslog(LOG_WARNING, "curl: no data to remove");
			return 0;
		}
		ev_io_stop(cuev->loop, evio);
		free(evio);
	} else {
		int eva = (what & CURL_POLL_IN ? EV_READ : 0) |
			(what & CURL_POLL_OUT ? EV_WRITE : 0);
		if (!evio) {
			xsyslog(LOG_DEBUG, "curl alloc socket #%d (action: %d)", s, eva);
			/* не проциниализировано */
			evio = calloc(1, sizeof(struct ev_io));
			evio->data = cuev;
			ev_io_init(evio, _ev_event_curl_cb, s, eva);
			ev_io_start(cuev->loop, evio);
			curl_multi_assign(cuev->multi, s, evio);
		} else {
			xsyslog(LOG_DEBUG, "curl update socket #%d (action: %d)", s, eva);
			/* изменение состояния */
			ev_io_stop(cuev->loop, evio);
			ev_io_set(evio, s, eva);
			ev_io_start(cuev->loop, evio);
		}
	}
	return 0;
}
Пример #4
0
/* find the address of (MPVIO_EXT *)->scramble (the random string sent to the client for "mysql_native_password" authentication)
 *
 * see sql/sql_acl.cc native_password_authenticate() for the layout of `struct MPVIO_EXT'
 * for mysql57, see sql/auth/sql_authentication.h
 *
 * [0] : MYSQL_PLUGIN_VIO sizeof() == 24 bytes
 *
 * we could hardcode the offset somewhere. ideally, we should have an API to query if from `sql_acl.cc'
 */
void _find_addr_scramble(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info, struct auth_flex_data *d_flex_data)
{
    void **addr_scramble = NULL;
    int i;

    for (i = 30; i < 50; ++i)
    {
        void *addr = ((void *)&vio[1]) + sizeof(*info) + 4 * i;
        DEBUG xsyslog(LOG_LOCAL7 | LOG_NOTICE, "%s : compare at %p (* -> %p) (diff %ld)",
                      __func__, addr, *(void **)addr, (long int)(addr - (void *)vio));

        /* addr_scramble should be +/- sizeof(void *) depending on if `info->host_or_ip' is an host or an ip ...
         * we will figure if it is an host or an ip later below.
         */
        if (*(void **)addr == info->host_or_ip)
        {
            DEBUG xsyslog(LOG_LOCAL7 | LOG_NOTICE, "%s : found info->host_or_ip (%s) at %p!", __func__, info->host_or_ip, addr);

            /* assume info->host_or_ip == (MPVIO_EXT *)->host */
            {
                /* be careful..., arithmetic on a (void **) would move 4x faster than on a (void *)... */
                addr_scramble = (void **)(((void *)addr) - 4 * 16);
            }

            if (strspn(info->host_or_ip, "0123456789.") == strlen(info->host_or_ip))
            {
                DEBUG xsyslog(LOG_LOCAL7 | LOG_NOTICE, "%s : info->host_or_ip is an ip, fix !", __func__);
                /* info->host_or_ip was info->ip instead of info->host */
                {
                    /* (void **) arithmetic... move 4 bytes indeed... */
                    addr_scramble += 1;
                }
            }

            DEBUG xsyslog(LOG_LOCAL7 | LOG_NOTICE, "%s : scramble should be at %p (diff %ld)", __func__, *(char **)addr_scramble, (long int)((void *)addr_scramble - (void *)vio));
            DEBUG xsyslog(LOG_LOCAL7 | LOG_NOTICE, "%s : scramble [%ld] `%s'", __func__, (long int)strlen(*(char **)addr_scramble), *(char **)addr_scramble);
            break;
        }
    }

    d_flex_data->addr_scramble_ptr = addr_scramble;
    d_flex_data->addr_scramble = *d_flex_data->addr_scramble_ptr;
}
Пример #5
0
static int MS_CALLBACK slg_write(BIO *b, const char *in, int inl)
	{
	int ret= inl;
	char* buf;
	char* pp;
	int priority, i;
	static struct
		{
		int strl;
		char str[10];
		int log_level;
		}
	mapping[] =
		{
		{ 6, "PANIC ", LOG_EMERG },
		{ 6, "EMERG ", LOG_EMERG },
		{ 4, "EMR ", LOG_EMERG },
		{ 6, "ALERT ", LOG_ALERT },
		{ 4, "ALR ", LOG_ALERT },
		{ 5, "CRIT ", LOG_CRIT },
		{ 4, "CRI ", LOG_CRIT },
		{ 6, "ERROR ", LOG_ERR },
		{ 4, "ERR ", LOG_ERR },
		{ 8, "WARNING ", LOG_WARNING },
		{ 5, "WARN ", LOG_WARNING },
		{ 4, "WAR ", LOG_WARNING },
		{ 7, "NOTICE ", LOG_NOTICE },
		{ 5, "NOTE ", LOG_NOTICE },
		{ 4, "NOT ", LOG_NOTICE },
		{ 5, "INFO ", LOG_INFO },
		{ 4, "INF ", LOG_INFO },
		{ 6, "DEBUG ", LOG_DEBUG },
		{ 4, "DBG ", LOG_DEBUG },
		{ 0, "", LOG_ERR } /* The default */
		};

	if((buf= (char *)OPENSSL_malloc(inl+ 1)) == NULL){
		return(0);
	}
	strncpy(buf, in, inl);
	buf[inl]= '\0';

	i = 0;
	while(strncmp(buf, mapping[i].str, mapping[i].strl) != 0) i++;
	priority = mapping[i].log_level;
	pp = buf + mapping[i].strl;

	xsyslog(b, priority, pp);

	OPENSSL_free(buf);
	return(ret);
	}
Пример #6
0
static int
_curl_timer_cb(CURLM *multi, long timeout_ms, struct curlev *cuev)
{
	if (cuev->timered) {
		ev_timer_stop(cuev->loop, &cuev->timer);
		cuev->timered = false;
	}
	xsyslog(LOG_INFO, "curl update timer to %ldms", timeout_ms);
	if (timeout_ms > 0) {
		double _t = timeout_ms / 1000.0;
		ev_timer_set(&cuev->timer, _t, 0.);
		ev_timer_start(cuev->loop, &cuev->timer);
		cuev->timered = true;
	} else {
		_ev_timer_curl_cb(cuev->loop, &cuev->timer, 0);
	}
	return 0;
}
Пример #7
0
/* find the address of (MPVIO_EXT *)->client_capabilities
 *
 * we use it to known if the client support CLIENT_PLUGIN_AUTH (change user plugin to "mysql_clear_password" request)
 */
void _find_addr_client_capabilities(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info, struct auth_flex_data *d_flex_data)
{
    ulong client_capabilities;
    void **addr_client_capabilities_ptr;
    /* be careful..., arithmetic on a (void **) would move 4x faster than on a (void *)... */
#if DBMS_mysql < 57
    addr_client_capabilities_ptr = ((void *)d_flex_data->addr_scramble_ptr) - sizeof(void *);
#else /* DBMS_mysql < 57 */
    /* mysql 5.7 use a c++ class to hold client_capabilities, so we will have to use advanced black magic.
     *
     * http://stackoverflow.com/questions/12378271/what-does-an-object-look-like-in-memory/12378515#12378515
     *
     * As you suspect, the data members (fields) are laid out sequentially.
     * This also includes the fields of base classes.
     *
     * If the class (or one of its base classes) contain any virtual methods, the layout typically starts
     * with a vptr, i.e a pointer to a virtual table (or vtable) which is a table of pointers to function
     * implementations related to that class.
     *
     * Please note that this is not defined by standard, but AFAIK all current compilers use this approach.
     * Also, with multiple inheritance it gets more hairy, so let's ignore it for the moment.
     *
     * +-----------+
     * |  vptr     |  pointer to vtable which is located elsewhere
     * +-----------+
     * |  fieldA   |  first member
     * |  fieldB   |  ...
     * |  fieldC   |
     * |  ...      |
     * +-----------+
     *
     */
    void **addr_protocol_classic_ptr = ((void *)d_flex_data->addr_scramble_ptr) + 5 * sizeof(void *);
    addr_client_capabilities_ptr = *addr_protocol_classic_ptr + sizeof(void *);
#endif /* DBMS_mysql < 57 */
    client_capabilities = *(ulong *)addr_client_capabilities_ptr;
    DEBUG xsyslog(LOG_LOCAL7 | LOG_NOTICE, "%s : client_capabilities %ld (CLIENT_PLUGIN_AUTH : %d)", __func__,
                  client_capabilities, client_capabilities & CLIENT_PLUGIN_AUTH ? 1 : 0);
    d_flex_data->client_capabilities = client_capabilities;
}
Пример #8
0
static void
_ev_event_curl_cb(struct ev_loop *loop, struct ev_io *w, int revents)
{
	struct curlev *cuev = w->data;
	CURLMcode rc = 0;
	int curla = (revents & EV_READ ? CURL_POLL_IN : 0) |
		( revents & EV_WRITE ? CURL_POLL_OUT : 0);
	int running = 0;

	if ((rc = curl_multi_socket_action(cuev->multi, w->fd, curla, &running))
			!= CURLM_OK) {
		xsyslog(LOG_WARNING, "curl_multi_socket_action() error: rc=%d", rc);
		return;
	}
	/* TODO: ? */
	/* проверка состояния */
	{
		int _msgs = 0;
		CURLMsg *_msg = NULL;
		CURL *_easy = NULL;
		struct curlex *_ex = NULL;
		while ((_msg = curl_multi_info_read(cuev->multi, &_msgs)) != NULL) {
			if (_msg->msg == CURLMSG_DONE) {
				_easy = _msg->easy_handle;
				/* освбождение всякого мусора */
				if (!curl_easy_getinfo(_easy, CURLINFO_PRIVATE, &_ex) && _ex) {
					if (_ex->cb) {
						/* финализация записи */
						_ex->cb(NULL, 0ul, _ex->cb_data);
					}
					free(_ex);
				}
				curl_multi_remove_handle(cuev->multi, _easy);
				curl_easy_cleanup(_easy);
			}
		} /* while */
	}

}
Пример #9
0
/* ask the client to "change plugin", so that it will send us the password in cleartext...
 *
 * HELP:
 * - http://lists.mysql.com/commits/136992
 * - http://bugs.mysql.com/bug.php?id=57442
 * - wireshark...
 */
void flex_change_plugin_to_cleartext(MYSQL_PLUGIN_VIO *vio, struct auth_flex_data *d_auth_flex_data)
{
    char * __attribute__ ((unused)) pkt_change_plugin = "mysql_clear_password";

#if DBMS_mysql < 57

    void **addr_net_ptr = NULL;

    /* we cannot call vio->write_packet() because send_plugin_request_packet() would concatenate
     *  and send the current auth pluging + the requested one (\254 + "mysql_native_password\0" + "mysql_clear_password\0")
     * so, below we send the "plugin change" request ourselves on the wire. (\254 + "mysql_clear_password\0")
     */
    {
        /* be careful..., arithmetic on a (void **) would move 4x faster than on a (void *)... */
        addr_net_ptr = (void *)(((void *)d_auth_flex_data->addr_scramble_ptr) + sizeof(void *) * 4 + sizeof(ulong));
    }
    DEBUG xsyslog(LOG_LOCAL7 | LOG_NOTICE, "%s : addr_scramble/%p addr_net/%p (diff %ld)", __func__,
                  d_auth_flex_data->addr_scramble_ptr, addr_net_ptr, (long int)(addr_net_ptr - d_auth_flex_data->addr_scramble_ptr));

    net_write_command(*addr_net_ptr, 254, pkt_change_plugin, strlen(pkt_change_plugin) + 1, "", 0);

#else /* DBMS_mysql < 57 */

    /* for mysql 5.7, things get a bit hairy.
     *
     * we have to simulate a MYSQL_PLUGIN_VIO struct, fill in some interesting fields
     * and send it back to our mysql client so it can retry auth with desired plugin.
     *
     * don't do this at home, kids.
     *
     */

    struct MYSQL_PLUGIN_VIO_FAKE
    {
        MYSQL_PLUGIN_VIO plugin_vio;
        MYSQL_SERVER_AUTH_INFO auth_info;
        void *acl_user;
        struct st_plugin_int {
            LEX_STRING name;
            struct st_mysql_plugin *plugin;
        } *plugin;
        LEX_STRING db;
        struct {
            char *plugin, *pkt;
            uint pkt_len;
        } cached_client_reply;
        struct {
            char *pkt;
            uint pkt_len;
        } cached_server_packet;
        int packets_read, packets_written;
        enum { SUCCESS, FAILURE, RESTART } status;
    };

    struct MYSQL_PLUGIN_VIO_FAKE *vio_fake = (struct MYSQL_PLUGIN_VIO_FAKE *)vio;
    int old_status = vio_fake->status;
    vio_fake->status = RESTART;

    struct st_mysql_auth tmp_auth = {0};
    tmp_auth.client_auth_plugin = pkt_change_plugin;
    struct st_mysql_plugin tmp_plugin = {0};
    tmp_plugin.info = &tmp_auth;
    struct st_plugin_int tmp_int = {0};
    tmp_int.plugin = &tmp_plugin;

    void *old_plugin = vio_fake->plugin;
    vio_fake->plugin = &tmp_int;

    DEBUG xsyslog(LOG_LOCAL7 | LOG_NOTICE, "%s : packets read/written %d/%d", __func__,
                  vio_fake->packets_read, vio_fake->packets_written);
    vio->write_packet(vio, "", 0); /* This will somehow trigger the CHANGE_PLUGIN procedure... */
    vio_fake->plugin = old_plugin;
    vio_fake->status = old_status;

#endif /* DBMS_mysql < 57 */

}