Пример #1
0
xmpp_user_t* xmpp_user_new(xmpp_conn_t * const conn, const char *jid, const char *name)
{
	xmpp_user_t *user = xmpp_alloc(conn->ctx, sizeof(xmpp_user_t));
	user->conn = conn;
	user->jid = xmpp_strdup(conn->ctx, jid);
	user->name = xmpp_strdup(conn->ctx, name);
	return user;
}
Пример #2
0
/** Copy a stanza and its children.
 *  This function copies a stanza along with all its children and returns
 *  the new stanza and children with a reference count of 1.  The returned
 *  stanza will have no parent and no siblings.  This function is useful
 *  for extracting a child stanza for inclusion in another tree.
 *
 *  @param stanza a Strophe stanza object
 *
 *  @return a new Strophe stanza object
 *
 *  @ingroup Stanza
 */
xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
{
    xmpp_stanza_t *copy, *child, *copychild, *tail;
    hash_iterator_t *iter;
    const char *key;
    void *val;

    copy = xmpp_stanza_new(stanza->ctx);
    if (!copy) goto copy_error;

    copy->type = stanza->type;

    if (stanza->data) {
        copy->data = xmpp_strdup(stanza->ctx, stanza->data);
        if (!copy->data) goto copy_error;
    }

    if (stanza->attributes) {
        copy->attributes = hash_new(stanza->ctx, 8, xmpp_free);
        if (!copy->attributes) goto copy_error;
        iter = hash_iter_new(stanza->attributes);
        if (!iter) {
            printf("DEBUG HERE\n");
            goto copy_error;
        }
        while ((key = hash_iter_next(iter))) {
            val = xmpp_strdup(stanza->ctx,
                              (char *)hash_get(stanza->attributes, key));
            if (!val) goto copy_error;

            if (hash_add(copy->attributes, key, val))
                goto copy_error;
        }
        hash_iter_release(iter);
    }

    tail = copy->children;
    for (child = stanza->children; child; child = child->next) {
        copychild = xmpp_stanza_copy(child);
        if (!copychild) goto copy_error;
        copychild->parent = copy;

        if (tail) {
            copychild->prev = tail;
            tail->next = copychild;
        } else
            copy->children = copychild;
        tail = copychild;
    }

    return copy;

copy_error:
    /* release all the hitherto allocated memory */
    if (copy) xmpp_stanza_release(copy);
    return NULL;
}
Пример #3
0
/** Create a stanza object in reply to another.
 *  This function makes a copy of a stanza object with the attribute “to” set
 *  its original “from”.
 *  The stanza will have a reference count of one, so the caller does not
 *  need to clone it.
 *
 *  @param stanza a Strophe stanza object
 *
 *  @return a new Strophe stanza object
 *
 *  @ingroup Stanza
 */
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
{
    xmpp_stanza_t *copy = NULL;
    const char *from;
    int rc;

    from = xmpp_stanza_get_from(stanza);
    if (!from) goto copy_error;

    copy = xmpp_stanza_new(stanza->ctx);
    if (!copy) goto copy_error;

    copy->type = stanza->type;

    if (stanza->data) {
        copy->data = xmpp_strdup(stanza->ctx, stanza->data);
        if (!copy->data) goto copy_error;
    }

    if (stanza->attributes) {
        if (_stanza_copy_attributes(copy, stanza) < 0)
            goto copy_error;
    }

    xmpp_stanza_del_attribute(copy, "to");
    xmpp_stanza_del_attribute(copy, "from");
    rc = xmpp_stanza_set_to(copy, from);
    if (rc != XMPP_EOK) goto copy_error;

    return copy;

copy_error:
    if (copy) xmpp_stanza_release(copy);
    return NULL;
}
Пример #4
0
/** Set an attribute for a stanza object.
 *  
 *  @param stanza a Strophe stanza object
 *  @param key a string with the attribute name
 *  @param value a string with the attribute value
 *
 *  @return XMPP_EOK (0) on success or a number less than 0 on failure
 *
 *  @ingroup Stanza
 */
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
                              const char * const key,
                              const char * const value)
{
    char *val;
    int rc;

    if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;

    if (!stanza->attributes) {
        stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
        if (!stanza->attributes) return XMPP_EMEM;
    }

    val = xmpp_strdup(stanza->ctx, value);
    if (!val) {
        hash_release(stanza->attributes);
        return XMPP_EMEM;
    }

    rc = hash_add(stanza->attributes, key, val);
    if (rc < 0) {
        xmpp_free(stanza->ctx, val);
        return XMPP_EMEM;
    }

    return XMPP_EOK;
}
Пример #5
0
/** Get the text data for a text stanza.
 *  This function copies the text data from a stanza and returns the new
 *  allocated string.  The caller is responsible for freeing this string
 *  with xmpp_free().
 *
 *  @param stanza a Strophe stanza object
 *
 *  @return an allocated string with the text data
 *
 *  @ingroup Stanza
 */
char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
{
    size_t len, clen;
    xmpp_stanza_t *child;
    char *text;

    if (stanza->type == XMPP_STANZA_TEXT) {
        if (stanza->data)
            return xmpp_strdup(stanza->ctx, stanza->data);
        else
            return NULL;
    }

    len = 0;
    for (child = stanza->children; child; child = child->next)
        if (child->type == XMPP_STANZA_TEXT)
            len += strlen(child->data);

    if (len == 0) return NULL;

    text = (char *)xmpp_alloc(stanza->ctx, len + 1);
    if (!text) return NULL;

    len = 0;
    for (child = stanza->children; child; child = child->next)
        if (child->type == XMPP_STANZA_TEXT) {
            clen = strlen(child->data);
            memcpy(&text[len], child->data, clen);
            len += clen;
        }

    text[len] = 0;

    return text;
}
Пример #6
0
/** add a key, value pair to a hash table.
 *  each key can appear only once; the value of any
 *  identical key will be replaced
 */
int hash_add(hash_t *table, const char * const key, void *data)
{
   xmpp_ctx_t *ctx = table->ctx;
   hashentry_t *entry = NULL;
   int table_index = _hash_key(table, key);

   /* drop existing entry, if any */
   hash_drop(table, key);

   /* allocate and fill a new entry */
   entry = xmpp_alloc(ctx, sizeof(hashentry_t));
   if (!entry) return -1;
   entry->key = xmpp_strdup(ctx, key);
   if (!entry->key) {
       xmpp_free(ctx, entry);
       return -1;
   }
   entry->value = data;
   /* insert ourselves in the linked list */
   /* TODO: this leaks duplicate keys */
   entry->next = table->entries[table_index];
   table->entries[table_index] = entry;
   table->num_keys++;

   return 0;
}
Пример #7
0
/*
 * Copy the attributes of stanza src into stanza dst. Return -1 on error.
 */
static int _stanza_copy_attributes(xmpp_stanza_t * dst,
                                   const xmpp_stanza_t * const src)
{
    hash_iterator_t *iter = NULL;
    const char *key;
    void *val;

    dst->attributes = hash_new(src->ctx, 8, xmpp_free);
    if (!dst->attributes)
        return -1;
    iter = hash_iter_new(src->attributes);
    if (!iter)
        goto error;
    while ((key = hash_iter_next(iter))) {
        val = xmpp_strdup(src->ctx,
                          (char *)hash_get(src->attributes, key));
        if (!val)
            goto error;

        if (hash_add(dst->attributes, key, val)) {
            xmpp_free(src->ctx, val);
            goto error;
        }
    }
    hash_iter_release(iter);
    return 0;

error:
    if (iter != NULL)
        hash_iter_release(iter);
    hash_release(dst->attributes);
    return -1;
}
Пример #8
0
/** Create a stanza object in reply to another.
 *  This function makes a copy of a stanza object with the attribute “to” set
 *  its original “from”.
 *  The stanza will have a reference count of one, so the caller does not
 *  need to clone it.
 *
 *  @param stanza a Strophe stanza object
 *
 *  @return a new Strophe stanza object
 *
 *  @ingroup Stanza
 */
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
{
    xmpp_stanza_t *copy;

    copy = xmpp_stanza_new(stanza->ctx);
    if (!copy) goto copy_error;

    copy->type = stanza->type;

    if (stanza->data) {
        copy->data = xmpp_strdup(stanza->ctx, stanza->data);
        if (!copy->data) goto copy_error;
    }

    if (stanza->attributes) {
        if (_stanza_copy_attributes(copy, stanza) == -1)
            goto copy_error;
    }

    xmpp_stanza_set_to(copy, xmpp_stanza_get_from(stanza));
    xmpp_stanza_del_attribute(copy, "from");

    return copy;

copy_error:
    if (copy) xmpp_stanza_release(copy);
    return NULL;
}
Пример #9
0
static void _handle_stream_start(char *name, char **attrs, 
                                 void * const userdata)
{
    xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
    char *id;

    if (strcmp(name, "stream:stream") != 0) {
        printf("name = %s\n", name);
        xmpp_error(conn->ctx, "conn", "Server did not open valid stream.");
        conn_disconnect(conn);
    } else {
        _log_open_tag(conn, attrs);
        
        if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id);

        id = _get_stream_attribute(attrs, "id");
        if (id)
            conn->stream_id = xmpp_strdup(conn->ctx, id);

        if (!conn->stream_id) {
            xmpp_error(conn->ctx, "conn", "Memory allocation failed.");
            conn_disconnect(conn);
        }
    }
    
    /* call stream open handler */
    conn->open_handler(conn);
}
Пример #10
0
static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
                                 char ***attributes, size_t *attributes_len)
{
    char **array = NULL;
    size_t nr = 0;
    size_t i;

    if (attrs) {
        for (; attrs[nr]; ++nr);
        array = xmpp_alloc(conn->ctx, sizeof(*array) * nr);
        for (i = 0; array && i < nr; ++i) {
            array[i] = (i & 1) == 0 ? parser_attr_name(conn->ctx, attrs[i])
                                    : xmpp_strdup(conn->ctx, attrs[i]);
            if (array[i] == NULL) break;
        }
        if (!array || i < nr) {
            xmpp_error(conn->ctx, "xmpp", "Memory allocation error.");
            _conn_attributes_destroy(conn, array, i);
            array = NULL;
            nr = 0;
        }
    }
    *attributes = array;
    *attributes_len = nr;
}
Пример #11
0
/** Set the name of a stanza.
 *  
 *  @param stanza a Strophe stanza object
 *  @param name a string with the name of the stanza
 *
 *  @return XMPP_EOK on success, a number less than 0 on failure (XMPP_EMEM,
 *      XMPP_EINVOP)
 *
 *  @ingroup Stanza
 */
int xmpp_stanza_set_name(xmpp_stanza_t *stanza, 
                         const char * const name)
{
    if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP;

    if (stanza->data) xmpp_free(stanza->ctx, stanza->data);

    stanza->type = XMPP_STANZA_TAG;
    stanza->data = xmpp_strdup(stanza->ctx, name);

    return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
}
Пример #12
0
/** Set the text data for a text stanza.
 *  This function copies the text given and sets the stanza object's text to
 *  it.  Attempting to use this function on a stanza that has a name will
 *  fail with XMPP_EINVOP.  This function takes the text as a null-terminated
 *  string.
 *
 *  @param stanza a Strophe stanza object
 *  @param text a string with the text
 *
 *  @return XMPP_EOK (0) on success or a number less than zero on failure
 *
 *  @ingroup Stanza
 */
int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
                         const char * const text)
{
    if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
    
    stanza->type = XMPP_STANZA_TEXT;

    if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
    stanza->data = xmpp_strdup(stanza->ctx, text);

    return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
}
Пример #13
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;
}
Пример #14
0
/** Create a bare JID from a JID.
 *  
 *  @param ctx the Strophe context object
 *  @param jid the JID
 *
 *  @return an allocated string with the bare JID or NULL on an error
 */
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
{
    char *result;
    const char *c;

    c = strchr(jid, '/');
    if (c == NULL) return xmpp_strdup(ctx, jid);

    result = xmpp_alloc(ctx, c-jid+1);
    if (result != NULL) {
	memcpy(result, jid, c-jid);
	result[c-jid] = '\0';
    }

    return result;
}
Пример #15
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;
}
Пример #16
0
/* return allocated string with the name from a delimited
 * namespace/name string */
static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
{
    char *result = NULL;
    const char *c;
    int len;

    c = strchr(nsname, NAMESPACE_SEP);
    if (c == NULL) return xmpp_strdup(ctx, nsname);

    c++;
    len = strlen(c);
    result = xmpp_alloc(ctx, len + 1);
    if (result != NULL) {
	memcpy(result, c, len);
	result[len] = '\0';
    }

    return result;
}
Пример #17
0
static void _id_handler_add(xmpp_conn_t * const conn,
			 xmpp_handler handler,
			 const char * const id,
			 void * const userdata, int user_handler)
{
    xmpp_handlist_t *item, *tail;

    /* check if handler is already in the list */
    item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
    while (item) {
	if (item->handler == (void *)handler)
	    break;
	item = item->next;
    }
    if (item) return;

    /* build new item */
    item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
    if (!item) return;

    item->user_handler = user_handler;
    item->handler = (void *)handler;
    item->userdata = userdata;
    item->enabled = 0;
    item->next = NULL;

    item->id = xmpp_strdup(conn->ctx, id);
    if (!item->id) {
	xmpp_free(conn->ctx, item);
	return;
    }

    /* put on list in hash table */
    tail = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
    if (!tail)
	hash_add(conn->id_handlers, id, item);
    else {
	while (tail->next) 
	    tail = tail->next;
	tail->next = item;
    }
}
Пример #18
0
/** Copy a stanza and its children.
 *  This function copies a stanza along with all its children and returns
 *  the new stanza and children with a reference count of 1.  The returned
 *  stanza will have no parent and no siblings.  This function is useful
 *  for extracting a child stanza for inclusion in another tree.
 *
 *  @param stanza a Strophe stanza object
 *
 *  @return a new Strophe stanza object
 *
 *  @ingroup Stanza
 */
xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
{
    xmpp_stanza_t *copy, *child, *copychild, *tail;

    copy = xmpp_stanza_new(stanza->ctx);
    if (!copy) goto copy_error;

    copy->type = stanza->type;

    if (stanza->data) {
        copy->data = xmpp_strdup(stanza->ctx, stanza->data);
        if (!copy->data) goto copy_error;
    }

    if (stanza->attributes) {
        if (_stanza_copy_attributes(copy, stanza) == -1)
            goto copy_error;
    }

    tail = copy->children;
    for (child = stanza->children; child; child = child->next) {
        copychild = xmpp_stanza_copy(child);
        if (!copychild) goto copy_error;
        copychild->parent = copy;

        if (tail) {
            copychild->prev = tail;
            tail->next = copychild;
        } else
            copy->children = copychild;
        tail = copychild;
    }

    return copy;

copy_error:
    /* release all the hitherto allocated memory */
    if (copy) xmpp_stanza_release(copy);
    return NULL;
}
Пример #19
0
/** Set or replace attributes on a stanza.
 *  This function replaces all previous attributes (if any) with the
 *  attributes given.  It is used primarily by the XML parser during
 *  stanza creation.  All strings in the array are copied before placing them
 *  inside the stanza object.
 *
 *  @param stanza a Strophe stanza object
 *  @param attr an array of strings with the attributes in the following
 *      format: attr[i] = attribute name, attr[i+1] = attribute value
 *
 *  @return XMPP_EOK on success, a number less than 0 on failure (XMPP_EMEM,
 *      XMPP_EINVOP)
 *
 *  @ingroup Stanza
 */
int xmpp_stanza_set_attributes(xmpp_stanza_t * const stanza,
			       const char * const * const attr)
{
    int i;
    char *value;

    if (stanza->attributes != NULL)
	hash_release(stanza->attributes);

    stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
    if (!stanza->attributes) return XMPP_EMEM;
    
    for (i = 0; attr[i]; i += 2) {
	value = xmpp_strdup(stanza->ctx, attr[i + 1]);
	if (!value) {
	    /* FIXME: memory allocation error */
	    continue;
	}
	hash_add(stanza->attributes, attr[i], value);
    }
    
    return XMPP_EOK;
}
Пример #20
0
/** Initiate a component connection to the XMPP 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 callback function.  The domain and port specify the
 *  server to connect to. Strophe will then attempt to bind to the domain specified 
 *  previously with xmpp_conn_set_jid
 *
 *  @param conn a Strophe connection object
 *  @param server a string with domain of the server to connect to, commonly "localhost"
 *  @param port an integer port number to connect to
 *  @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)
{
    char connectdomain[2048];
    int connectport;
    char *domain;

    conn->type = XMPP_COMPONENT;

    conn->domain = xmpp_strdup(conn->ctx, server);
    if (!conn->domain) return -1;

    domain = conn->domain;
    strcpy(connectdomain, domain);
    connectport = port ? port : 5222;
    conn->sock = sock_connect(connectdomain, connectport);
    if (conn->sock == -1) return -1;

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

    /* 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", connectdomain);

    return 0;
}
Пример #21
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;
}
Пример #22
0
int tls_start(tls_t *tls)
{
    xmpp_ctx_t *ctx = tls->ctx;
    ULONG ctxtreq = 0, ctxtattr = 0;
    SecBufferDesc sbdin, sbdout;
    SecBuffer sbin[2], sbout[1];
    SECURITY_STATUS ret;
    int sent;
    char *name = NULL;

    /* search the ctx's conns for our sock, and use the domain there as our
     * name */
    {
	list_t *listentry = list_get_first(ctx->connlist);

	while (listentry) {
	    xmpp_conn_t *conn = (xmpp_conn_t *)listentry->data;

	    if (conn->sock == tls->sock) {
		name = xmpp_strdup(ctx, conn->domain);
		listentry = NULL;
	    } else {
		listentry = list_get_next(tls->ctx->connlist, listentry);
	    }
	}
    }

    ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT
	    | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR
	    | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM
	    | ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY;

    memset(&(sbout[0]), 0, sizeof(sbout[0]));
    sbout[0].BufferType = SECBUFFER_TOKEN;

    memset(&sbdout, 0, sizeof(sbdout));
    sbdout.ulVersion = SECBUFFER_VERSION;
    sbdout.cBuffers = 1;
    sbdout.pBuffers = sbout;

    memset(&(sbin[0]), 0, sizeof(sbin[0]));
    sbin[0].BufferType = SECBUFFER_TOKEN;
    sbin[0].pvBuffer = xmpp_alloc(ctx, tls->spi->cbMaxToken);
    sbin[0].cbBuffer = tls->spi->cbMaxToken;

    memset(&(sbin[1]), 0, sizeof(sbin[1]));
    sbin[1].BufferType = SECBUFFER_EMPTY;

    memset(&sbdin, 0, sizeof(sbdin));
    sbdin.ulVersion = SECBUFFER_VERSION;
    sbdin.cBuffers = 2;
    sbdin.pBuffers = sbin;

    ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), NULL, name, ctxtreq, 0, 0,
					  NULL, 0, &(tls->hctxt), &sbdout,
					  &ctxtattr, NULL);

    while (ret == SEC_I_CONTINUE_NEEDED
	   || ret == SEC_I_INCOMPLETE_CREDENTIALS) {
	unsigned char *p = sbin[0].pvBuffer;
	int len = 0, inbytes = 0;

	if (sbdout.pBuffers[0].cbBuffer) {
	    unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
	    unsigned int writelen = sbdout.pBuffers[0].cbBuffer;

	    sent = sock_write(tls->sock, writebuff, writelen);
	    if (sent == -1) {
		tls->lasterror = sock_error();
	    }
	    else
	    {
		writebuff += sent;
		writelen -= sent;
	    }
	    tls->sft->FreeContextBuffer(sbdout.pBuffers[0].pvBuffer);
	    sbdout.pBuffers[0].pvBuffer = NULL;
	    sbdout.pBuffers[0].cbBuffer = 0;
	}

	/* poll for a bit until the remote server stops sending data, ie it
	 * finishes sending the token */
	inbytes = 1;
	{
	    fd_set fds;
	    struct timeval tv;

	    tv.tv_sec = 2;
	    tv.tv_usec = 0;

	    FD_ZERO(&fds);
	    FD_SET(tls->sock, &fds);

	    select(tls->sock, &fds, NULL, NULL, &tv);
	}

	while (inbytes > 0) {
	    fd_set fds;
	    struct timeval tv;

	    tv.tv_sec = 0;
	    tv.tv_usec = 1000;

	    FD_ZERO(&fds);
	    FD_SET(tls->sock, &fds);

	    select(tls->sock, &fds, NULL, NULL, &tv);

	    inbytes = sock_read(tls->sock, p, tls->spi->cbMaxToken - len);

	    if (inbytes > 0) {
		len += inbytes;
		p += inbytes;
	    }
	    else
	    {
	        tls->lasterror = sock_error();
	    }

	}

	sbin[0].cbBuffer = len;

	ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), &(tls->hctxt), name,
					      ctxtreq, 0, 0, &sbdin, 0,
					      &(tls->hctxt), &sbdout,
					      &ctxtattr, NULL);
    }

    if (ret == SEC_E_OK) {
	if (sbdout.pBuffers[0].cbBuffer) {
	    unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
	    unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
	    sent = sock_write(tls->sock, writebuff, writelen);
	    if (sent == -1) {
		tls->lasterror = sock_error();
	    }
	    else
	    {
		writebuff += sent;
		writelen -= sent;
	    }
	    tls->sft->FreeContextBuffer(sbdout.pBuffers[0].pvBuffer);
	    sbdout.pBuffers[0].pvBuffer = NULL;
	    sbdout.pBuffers[0].cbBuffer = 0;
	}
    }

    /* free resources */
    xmpp_free(ctx, sbin[0].pvBuffer);
    if (name != NULL) {
        xmpp_free(ctx, name);
    }

    if (ret != SEC_E_OK) {
	tls->lasterror = ret;
	return 0;
    }

    tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES,
				&(tls->spcss));

    tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
			    + tls->spcss.cbTrailer;
    tls->recvbuffer       = xmpp_alloc(ctx, tls->recvbuffermaxlen);
    tls->recvbufferpos    = 0;

    tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
			    + tls->spcss.cbTrailer;
    tls->sendbuffer       = xmpp_alloc(ctx, tls->sendbuffermaxlen);
    tls->sendbufferpos    = 0;
    tls->sendbufferlen    = 0;

    tls->readybuffer      = xmpp_alloc(ctx, tls->spcss.cbMaximumMessage);
    tls->readybufferpos   = 0;
    tls->readybufferlen   = 0;

    return 1;
}
Пример #23
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;
}
Пример #24
0
/** Set the password used to authenticate the connection.
 *  If any password was previously set, it will be discarded.  The function
 *  will make a copy of the password string.
 * 
 *  @param conn a Strophe connection object
 *  @param pass the password
 *
 *  @ingroup Connections
 */
void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass)
{
    if (conn->pass) xmpp_free(conn->ctx, conn->pass);
    conn->pass = xmpp_strdup(conn->ctx, pass);
}
Пример #25
0
/** Set the JID of the user that will be bound to the connection.
 *  If any JID was previously set, it will be discarded.  This should not be 
 *  be used after a connection is created.  The function will make a copy of
 *  the JID string.  If the supllied JID is missing the node, SASL
 *  ANONYMOUS authentication will be used.
 *
 *  @param conn a Strophe connection object
 *  @param jid a full or bare JID
 *
 *  @ingroup Connections
 */
void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid)
{
    if (conn->jid) xmpp_free(conn->ctx, conn->jid);
    conn->jid = xmpp_strdup(conn->ctx, jid);
}
Пример #26
0
/* add a stanza handler */
static void _handler_add(xmpp_conn_t * const conn,
			 xmpp_handler handler,
			 const char * const ns,
			 const char * const name,
			 const char * const type,
			 void * const userdata, int user_handler)
{
    xmpp_handlist_t *item, *tail;

    /* check if handler already in list */
    for (item = conn->handlers; item; item = item->next) {
	if (item->handler == (void *)handler)
	    break;
    }
    if (item) return;

    /* build new item */
    item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
    if (!item) return;

    item->user_handler = user_handler;
    item->handler = (void *)handler;
    item->userdata = userdata;
    item->enabled = 0;
    item->next = NULL;
    
    if (ns) {
	item->ns = xmpp_strdup(conn->ctx, ns);
	if (!item->ns) {
	    xmpp_free(conn->ctx, item);
	    return;
	}
    } else
	item->ns = NULL;
    if (name) {
	item->name = xmpp_strdup(conn->ctx, name);
	if (!item->name) {
	    if (item->ns) xmpp_free(conn->ctx, item->ns);
	    xmpp_free(conn->ctx, item);
	    return;
	}
    } else
	item->name = NULL;
    if (type) {
	item->type = xmpp_strdup(conn->ctx, type);
	if (!item->type) {
	    if (item->ns) xmpp_free(conn->ctx, item->ns);
	    if (item->name) xmpp_free(conn->ctx, item->name);
	    xmpp_free(conn->ctx, item);
	}
    } else
	item->type = NULL;

    /* append to list */
    if (!conn->handlers)
	conn->handlers = item;
    else {
	tail = conn->handlers;
	while (tail->next) 
	    tail = tail->next;
	tail->next = item;
    }
}
Пример #27
0
char* parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
{
    return xmpp_strdup(ctx, nsname);
}
Пример #28
0
/** generate auth response string for the SASL DIGEST-MD5 mechanism */
char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
			const char *jid, const char *password) {
    hash_t *table;
    char *result = NULL;
    char *node, *domain, *realm;
    char *value;
    char *response;
    int rlen;
    struct MD5Context MD5;
    unsigned char digest[16], HA1[16], HA2[16];
    char hex[32];
    char cnonce[13];

    /* our digest response is
	Hex( KD( HEX(MD5(A1)),
	  nonce ':' nc ':' cnonce ':' qop ':' HEX(MD5(A2))
	))

       where KD(k, s) = MD5(k ':' s),
	A1 = MD5( node ':' realm ':' password ) ':' nonce ':' cnonce
	A2 = "AUTHENTICATE" ':' "xmpp/" domain

       If there is an authzid it is ':'-appended to A1 */

    /* parse the challenge */
    table = _parse_digest_challenge(ctx, challenge);
    if (table == NULL) {
	xmpp_error(ctx, "SASL", "couldn't parse digest challenge");
	return NULL;
    }

    node = xmpp_jid_node(ctx, jid);
    domain = xmpp_jid_domain(ctx, jid);

    /* generate default realm of domain if one didn't come from the
       server */
    realm = hash_get(table, "realm");
    if (realm == NULL || strlen(realm) == 0) {
	hash_add(table, "realm", xmpp_strdup(ctx, domain));
	realm = hash_get(table, "realm");
    }

    /* add our response fields */
    hash_add(table, "username", xmpp_strdup(ctx, node));
    xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
    hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
    hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
    hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
    value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
    memcpy(value, "xmpp/", 5);
    memcpy(value+5, domain, strlen(domain));
    value[5+strlen(domain)] = '\0';
    hash_add(table, "digest-uri", value);

    /* generate response */

    /* construct MD5(node : realm : password) */
    MD5Init(&MD5);
    MD5Update(&MD5, (unsigned char *)node, strlen(node));
    MD5Update(&MD5, (unsigned char *)":", 1);
    MD5Update(&MD5, (unsigned char *)realm, strlen(realm));
    MD5Update(&MD5, (unsigned char *)":", 1);
    MD5Update(&MD5, (unsigned char *)password, strlen(password));
    MD5Final(digest, &MD5);

    /* digest now contains the first field of A1 */

    MD5Init(&MD5);
    MD5Update(&MD5, digest, 16);
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "nonce");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "cnonce");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Final(digest, &MD5);

    /* now digest is MD5(A1) */
    memcpy(HA1, digest, 16);

    /* construct MD5(A2) */
    MD5Init(&MD5);
    MD5Update(&MD5, (unsigned char *)"AUTHENTICATE:", 13);
    value = hash_get(table, "digest-uri");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    if (strcmp(hash_get(table, "qop"), "auth") != 0) {
	MD5Update(&MD5, (unsigned char *)":00000000000000000000000000000000",
		  33);
    }
    MD5Final(digest, &MD5);

    memcpy(HA2, digest, 16);

    /* construct response */
    MD5Init(&MD5);
    _digest_to_hex((char *)HA1, hex);
    MD5Update(&MD5, (unsigned char *)hex, 32);
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "nonce");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "nc");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "cnonce");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "qop");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    _digest_to_hex((char *)HA2, hex);
    MD5Update(&MD5, (unsigned char *)hex, 32);
    MD5Final(digest, &MD5);

    response = xmpp_alloc(ctx, 32+1);
    _digest_to_hex((char *)digest, hex);
    memcpy(response, hex, 32);
    response[32] = '\0';
    hash_add(table, "response", response);

    /* construct reply */
    result = NULL;
    rlen = 0;
    result = _add_key(ctx, table, "username", result, &rlen, 1);
    result = _add_key(ctx, table, "realm", result, &rlen, 1);
    result = _add_key(ctx, table, "nonce", result, &rlen, 1);
    result = _add_key(ctx, table, "cnonce", result, &rlen, 1);
    result = _add_key(ctx, table, "nc", result, &rlen, 0);
    result = _add_key(ctx, table, "qop", result, &rlen, 0);
    result = _add_key(ctx, table, "digest-uri", result, &rlen, 1);
    result = _add_key(ctx, table, "response", result, &rlen, 0);
    result = _add_key(ctx, table, "charset", result, &rlen, 0);

    xmpp_free(ctx, node);
    xmpp_free(ctx, domain);
    hash_release(table); /* also frees value strings */

    /* reuse response for the base64 encode of our result */
    response = xmpp_base64_encode(ctx, (unsigned char *)result, strlen(result));
    xmpp_free(ctx, result);

    return response;
}
Пример #29
0
/** generate auth response string for the SASL SCRAM-SHA-1 mechanism */
char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
                      const char *first_bare, const char *jid,
                      const char *password)
{
    uint8_t key[SHA1_DIGEST_SIZE];
    uint8_t sign[SHA1_DIGEST_SIZE];
    char *r = NULL;
    char *s = NULL;
    char *i = NULL;
    unsigned char *sval;
    size_t sval_len;
    long ival;
    char *tmp;
    char *ptr;
    char *saveptr = NULL;
    char *response;
    char *auth;
    char *response_b64;
    char *sign_b64;
    char *result = NULL;
    size_t response_len;
    size_t auth_len;
    int j;

    tmp = xmpp_strdup(ctx, challenge);
    if (!tmp) {
        return NULL;
    }

    ptr = strtok_r(tmp, ",", &saveptr);
    while (ptr) {
        if (strncmp(ptr, "r=", 2) == 0) {
            r = ptr;
        } else if (strncmp(ptr, "s=", 2) == 0) {
            s = ptr + 2;
        } else if (strncmp(ptr, "i=", 2) == 0) {
            i = ptr + 2;
        }
        ptr = strtok_r(NULL, ",", &saveptr);
    }

    if (!r || !s || !i) {
        goto out;
    }

    xmpp_base64_decode_bin(ctx, s, strlen(s), &sval, &sval_len);
    if (!sval) {
        goto out;
    }
    ival = strtol(i, &saveptr, 10);

    auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge);
    auth = xmpp_alloc(ctx, auth_len);
    if (!auth) {
        goto out_sval;
    }

    response_len = 39 + strlen(r);
    response = xmpp_alloc(ctx, response_len);
    if (!response) {
        goto out_auth;
    }

    xmpp_snprintf(response, response_len, "c=biws,%s", r);
    xmpp_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge,
                  response);

    SCRAM_SHA1_ClientKey((uint8_t *)password, strlen(password),
                         (uint8_t *)sval, sval_len, (uint32_t)ival, key);
    SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
    for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
        sign[j] ^= key[j];
    }

    sign_b64 = xmpp_base64_encode(ctx, sign, sizeof(sign));
    if (!sign_b64) {
        goto out_response;
    }

    if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
        xmpp_free(ctx, sign_b64);
        goto out_response;
    }
    strcat(response, ",p=");
    strcat(response, sign_b64);
    xmpp_free(ctx, sign_b64);

    response_b64 = xmpp_base64_encode(ctx, (unsigned char *)response,
                                      strlen(response));
    if (!response_b64) {
        goto out_response;
    }
    result = response_b64;

out_response:
    xmpp_free(ctx, response);
out_auth:
    xmpp_free(ctx, auth);
out_sval:
    xmpp_free(ctx, sval);
out:
    xmpp_free(ctx, tmp);
    return result;
}