Пример #1
0
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
			      xmpp_stanza_t * const stanza,
			      void * const userdata)
{
    char *name;
    name = xmpp_stanza_get_name(stanza);
    xmpp_debug(conn->ctx, "xmpp",
	"handle proceedtls called for %s", name);

    if (strcmp(name, "proceed") == 0) {
        xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");

	conn->tls = tls_new(conn->ctx, conn->sock);

	if (!tls_start(conn->tls))
	{
	    xmpp_debug(conn->ctx, "xmpp", "Couldn't start TLS! error %d", tls_error(conn->tls));
	    tls_free(conn->tls);
	    conn->tls = NULL;
	    conn->tls_failed = 1;

	    /* failed tls spoils the connection, so disconnect */
	    xmpp_disconnect(conn);
	}
	else
	{
            conn->secured = 1;
            conn_prepare_reset(conn, auth_handle_open);

	    conn_open_stream(conn);
	}
    }

    return 0;
}
Пример #2
0
int conn_tls_start(xmpp_conn_t * const conn)
{
    int rc;

    if (conn->tls_disabled) {
        conn->tls = NULL;
        rc = -ENOSYS;
    } else {
        conn->tls = tls_new(conn->ctx, conn->sock);
        rc = conn->tls == NULL ? -ENOMEM : 0;
    }

    if (conn->tls != NULL) {
        if (tls_start(conn->tls)) {
            conn->secured = 1;
            conn_prepare_reset(conn, auth_handle_open);
        } else {
            rc = tls_error(conn->tls);
            conn->error = rc;
            tls_free(conn->tls);
            conn->tls = NULL;
            conn->tls_failed = 1;
        }
    }
    if (rc != 0)
        xmpp_debug(conn->ctx, "conn", "Couldn't start TLS! error %d", rc);

    return rc;
}
Пример #3
0
static int _handle_sasl_result(xmpp_conn_t * const conn,
			       xmpp_stanza_t * const stanza,
			       void * const userdata)
{
    char *name;

    name = xmpp_stanza_get_name(stanza);

    /* the server should send a <success> or <failure> stanza */
    if (strcmp(name, "failure") == 0) {
	xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed",
		   (char *)userdata);

	/* fall back to next auth method */
	_auth(conn);
    } else if (strcmp(name, "success") == 0) {
	/* SASL PLAIN auth successful, we need to restart the stream */
	xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
		   (char *)userdata);

	/* reset parser */
	conn_prepare_reset(conn, _handle_open_sasl);

	/* send stream tag */
	conn_open_stream(conn);
    } else {
	/* got unexpected reply */
	xmpp_error(conn->ctx, "xmpp", "Got unexpected reply to SASL %s"\
		   "authentication.", (char *)userdata);
	xmpp_disconnect(conn);
    }

    return 0;
}
Пример #4
0
/** Send the default opening stream tag.
 *  The default tag is the one sent by xmpp_connect_client().
 *  User's connection handler is called with event XMPP_CONN_CONNECT when
 *  server replies with its opening tag.
 *
 *  @return XMPP_EOK (0) on success a number less than 0 on failure
 *
 *  @note The connection must be connected with xmpp_connect_raw().
 *
 *  @ingroup Connections
 */
int xmpp_conn_open_stream_default(xmpp_conn_t * const conn)
{
    if (!conn->is_raw)
        return XMPP_EINVOP;

    conn_prepare_reset(conn, auth_handle_open_raw);
    conn_open_stream(conn);

    return XMPP_EOK;
}
Пример #5
0
/** Initiate a component connection to server.
 *  This function returns immediately after starting the connection
 *  process to the XMPP server, and notifiations of connection state changes
 *  will be sent to the internal callback function that will set up handler
 *  for the component handshake as defined in XEP-0114.
 *  The domain and port to connect to must be provided in this case as the JID
 *  provided to the call serves as component identifier to the server and is
 *  not subject to DNS resolution.
 *
 *  @param conn a Strophe connection object
 *  @param server a string with domain to use directly as the domain can't be
 *      extracted from the component name/JID. If this is not set, the call
 *      will fail.
 *  @param port an integer port number to use to connect to server expecting
 *      an external component.  If this is 0, the port 5347 will be assumed.
 *  @param callback a xmpp_conn_handler callback function that will receive
 *      notifications of connection status
 *  @param userdata an opaque data pointer that will be passed to the callback
 *
 *  @return 0 on success and -1 on an error
 *
 *  @ingroup Connections
 */
int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
                           unsigned short port, xmpp_conn_handler callback,
                           void * const userdata)
{
    int connectport;

    if (conn->state != XMPP_STATE_DISCONNECTED)
        return -1;
    if (conn->domain != NULL)
        xmpp_free(conn->ctx, conn->domain);

    conn->type = XMPP_COMPONENT;
    conn->secured = 0;
    conn->tls_failed = 0;
    /* JID serves as an identificator here and will be used as "to" attribute
       of the stream */
    conn->domain = xmpp_strdup(conn->ctx, conn->jid);

    /*  The server domain, jid and password MUST be specified. */
    if (!(server && conn->jid && conn->pass)) return -1;

    connectport = port ? port : _conn_default_port(conn);

    xmpp_debug(conn->ctx, "xmpp", "Connecting via %s", server);
    conn->sock = sock_connect(server, connectport);
    xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d",
               server, connectport, conn->sock);
    if (conn->sock == -1) return -1;

    /* XEP-0114 does not support TLS */
    conn->tls_disabled = 1;

    /* setup handler */
    conn->conn_handler = callback;
    conn->userdata = userdata;

    conn_prepare_reset(conn, auth_handle_component_open);

    /* FIXME: it could happen that the connect returns immediately as
     * successful, though this is pretty unlikely.  This would be a little
     * hard to fix, since we'd have to detect and fire off the callback
     * from within the event loop */

    conn->state = XMPP_STATE_CONNECTING;
    conn->timeout_stamp = time_stamp();
    xmpp_debug(conn->ctx, "xmpp", "attempting to connect to %s", server);

    return 0;
}
Пример #6
0
static int _conn_connect(xmpp_conn_t * const conn,
                         const char * const domain,
                         const char * const host,
                         unsigned short port,
                         xmpp_conn_type_t type,
                         xmpp_conn_handler callback,
                         void * const userdata)
{
    xmpp_open_handler open_handler;

    if (conn->state != XMPP_STATE_DISCONNECTED) return XMPP_EINVOP;
    if (type != XMPP_CLIENT && type != XMPP_COMPONENT) return XMPP_EINVOP;
    if (host == NULL || port == 0) return XMPP_EINT;

    _conn_reset(conn);

    conn->type = type;
    conn->domain = xmpp_strdup(conn->ctx, domain);
    if (!conn->domain) return XMPP_EMEM;

    conn->sock = sock_connect(host, port);
    xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
               host, port, conn->sock);
    if (conn->sock == -1) return XMPP_EINT;
    if (conn->ka_timeout || conn->ka_interval)
        sock_set_keepalive(conn->sock, conn->ka_timeout, conn->ka_interval);

    /* setup handler */
    conn->conn_handler = callback;
    conn->userdata = userdata;

    open_handler = conn->is_raw ? auth_handle_open_stub :
                   type == XMPP_CLIENT ? auth_handle_open :
                                         auth_handle_component_open;
    conn_prepare_reset(conn, open_handler);

    /* FIXME: it could happen that the connect returns immediately as
     * successful, though this is pretty unlikely.  This would be a little
     * hard to fix, since we'd have to detect and fire off the callback
     * from within the event loop */

    conn->state = XMPP_STATE_CONNECTING;
    conn->timeout_stamp = time_stamp();
    xmpp_debug(conn->ctx, "xmpp", "Attempting to connect to %s", host);

    return 0;
}
Пример #7
0
/** Send an opening stream tag.
 *  User's connection handler is called with event XMPP_CONN_CONNECT when
 *  server replies with its opening tag.
 *
 *  @param conn a Strophe connection object
 *  @param attributes Array of strings in format: even index points to
 *      an attribute name and odd index points to its value
 *  @param attributes_len Number of elements in the attributes array, it
 *      should be number of attributes multiplied by 2
 *
 *  @return XMPP_EOK (0) on success a number less than 0 on failure
 *
 *  @note The connection must be connected with xmpp_connect_raw().
 *
 *  @ingroup Connections
 */
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
                          size_t attributes_len)
{
    char *tag;

    if (!conn->is_raw)
        return XMPP_EINVOP;

    tag = _conn_build_stream_tag(conn, attributes, attributes_len);
    if (!tag)
        return XMPP_EMEM;

    conn_prepare_reset(conn, auth_handle_open_raw);
    xmpp_send_raw_string(conn, "<?xml version=\"1.0\"?>%s", tag);
    xmpp_free(conn->ctx, tag);

    return XMPP_EOK;
}
Пример #8
0
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
			      xmpp_stanza_t * const stanza,
			      void * const userdata)
{
    const char *name;

    name = xmpp_stanza_get_name(stanza);
    xmpp_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name);

    if (strcmp(name, "proceed") == 0) {
        xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");

        if (conn_tls_start(conn) == 0) {
            conn_prepare_reset(conn, auth_handle_open);
            conn_open_stream(conn);
        } else {
            /* failed tls spoils the connection, so disconnect */
            xmpp_disconnect(conn);
        }
    }

    return 0;
}
Пример #9
0
/** Create a new Strophe connection object.
 *
 *  @param ctx a Strophe context object
 *
 *  @return a Strophe connection object or NULL on an error
 *
 *  @ingroup Connections
 */
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
{
    xmpp_conn_t *conn = NULL;
    xmpp_connlist_t *tail, *item;

    if (ctx == NULL) return NULL;
	conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t));
    
    if (conn != NULL) {
	conn->ctx = ctx;

	conn->type = XMPP_UNKNOWN;
        conn->state = XMPP_STATE_DISCONNECTED;
	conn->sock = -1;
	conn->tls = NULL;
	conn->timeout_stamp = 0;
	conn->error = 0;
	conn->stream_error = NULL;

	/* default send parameters */
	conn->blocking_send = 0;
	conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX;
	conn->send_queue_len = 0;
	conn->send_queue_head = NULL;
	conn->send_queue_tail = NULL;

	/* default timeouts */
	conn->connect_timeout = CONNECT_TIMEOUT;

	conn->lang = xmpp_strdup(conn->ctx, "en");
	if (!conn->lang) {
	    xmpp_free(conn->ctx, conn);
	    return NULL;
	}
	conn->domain = NULL;
	conn->jid = NULL;
	conn->pass = NULL;
	conn->stream_id = NULL;
        conn->bound_jid = NULL;

	conn->tls_support = 0;
	conn->tls_disabled = 0;
	conn->tls_failed = 0;
	conn->sasl_support = 0;
        conn->secured = 0;

	conn->bind_required = 0;
	conn->session_required = 0;

	conn->parser = parser_new(conn->ctx, 
                                  _handle_stream_start,
                                  _handle_stream_end,
                                  _handle_stream_stanza,
                                  conn);
        conn->reset_parser = 0;
        conn_prepare_reset(conn, auth_handle_open);

	conn->authenticated = 0;
	conn->conn_handler = NULL;
	conn->userdata = NULL;
	conn->timed_handlers = NULL;
	/* we own (and will free) the hash values */
	conn->id_handlers = hash_new(conn->ctx, 32, NULL);
	conn->handlers = NULL;

	/* give the caller a reference to connection */
	conn->ref = 1;

	/* add connection to ctx->connlist */
	tail = conn->ctx->connlist;
	while (tail && tail->next) tail = tail->next;

	item = xmpp_alloc(conn->ctx, sizeof(xmpp_connlist_t));
	if (!item) {
	    xmpp_error(conn->ctx, "xmpp", "failed to allocate memory");
	    xmpp_free(conn->ctx, conn->lang);
            parser_free(conn->parser);
	    xmpp_free(conn->ctx, conn);
	    conn = NULL;
	} else {
	    item->conn = conn;
	    item->next = NULL;

	    if (tail) tail->next = item;
	    else conn->ctx->connlist = item;
	}
    }
    
    return conn;
}
Пример #10
0
/** Create a new Strophe connection object.
 *
 *  @param ctx a Strophe context object
 *
 *  @return a Strophe connection object or NULL on an error
 *
 *  @ingroup Connections
 */
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
{
	xmpp_conn_t *conn;
	list_t *item;

	if (!ctx)
		return NULL;
	conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t));

	if (!conn)
		return NULL;

	conn->ctx = ctx;

	conn->type = XMPP_UNKNOWN;
	conn->state = XMPP_STATE_DISCONNECTED;
	conn->sock = -1;
	conn->tls = NULL;
	conn->timeout_stamp = 0;
	conn->error = 0;
	conn->stream_error = NULL;

	/* default send parameters */
	conn->blocking_send = 0;
	conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX;
	conn->send_queue = list_init(ctx);
	if (!conn->send_queue)
		goto out_free_conn;

	/* default timeouts */
	conn->connect_timeout = CONNECT_TIMEOUT;

	conn->lang = xmpp_strdup(ctx, "en");
	if (!conn->lang)
		goto out_free_send_queue;

	conn->domain = NULL;
	conn->jid = NULL;
	conn->pass = NULL;
	conn->stream_id = NULL;
	conn->bound_jid = NULL;

	conn->tls_support = 0;
	conn->tls_disabled = 0;
	conn->tls_failed = 0;
	conn->sasl_support = 0;
	conn->secured = 0;

	conn->bind_required = 0;
	conn->session_required = 0;

	conn->parser = parser_new(ctx,
				  _handle_stream_start,
				  _handle_stream_end,
				  _handle_stream_stanza,
				  conn);
	if (!conn->parser)
		goto out_free_lang;
	conn->reset_parser = 0;
	conn_prepare_reset(conn, auth_handle_open);

	conn->authenticated = 0;
	conn->conn_handler = NULL;
	conn->userdata = NULL;
	/* we own (and will free) the hash values */
	conn->id_handlers = hash_new(ctx, 32, NULL);
	conn->timed_handlers = list_init(ctx);
	if (!conn->timed_handlers)
		goto out_free_parser;
	conn->handlers = list_init(ctx);
	if (!conn->handlers)
		goto out_free_timed_handlers;

	/* give the caller a reference to connection */
	conn->ref = 1;

	/* add connection to ctx->connlist */
	item = list_init_item(ctx);
	if (!item)
		goto out_free_handlers;
	else {
		item->data = (void *)conn;
		list_push(ctx->connlist, item);
	}

	return conn;

out_free_handlers:
	list_destroy(conn->handlers);
out_free_timed_handlers:
	list_destroy(conn->timed_handlers);
out_free_parser:
	parser_free(conn->parser);
out_free_lang:
	xmpp_free(ctx, conn->lang);
out_free_send_queue:
	list_destroy(conn->send_queue);
out_free_conn:
	xmpp_free(ctx, conn);
	return NULL;
}