Exemple #1
0
int test_jid(xmpp_ctx_t *ctx)
{
    char *node;
    char *domain;
    char *resource;

    node = xmpp_jid_node(ctx, jid1);
    domain = xmpp_jid_domain(ctx, jid1);
    resource = xmpp_jid_resource(ctx, jid1);
    printf("jid '%s' parsed to %s, %s, %s\n",
	jid1, node, domain, resource);
    if (strcmp(node, "foo")) return 1;
    if (strcmp(domain, "bar.com")) return 1;
    if (resource != NULL) return 1;
    if (node) xmpp_free(ctx, node);
    if (domain) xmpp_free(ctx, domain);
    if (resource) xmpp_free(ctx, resource);

    node = xmpp_jid_node(ctx, jid2);
    domain = xmpp_jid_domain(ctx, jid2);
    resource = xmpp_jid_resource(ctx, jid2);
    printf("jid '%s' parsed to %s, %s, %s\n",
	jid2, node, domain, resource);
    if (strcmp(node, "anyone")) return 1;
    if (strcmp(domain, "example.com")) return 1;
    if (strcmp(resource, "hullo")) return 1;
    if (node) xmpp_free(ctx, node);
    if (domain) xmpp_free(ctx, domain);
    if (resource) xmpp_free(ctx, resource);

    node = xmpp_jid_node(ctx, jid3);
    domain = xmpp_jid_domain(ctx, jid3);
    resource = xmpp_jid_resource(ctx, jid3);
    printf("jid '%s' parsed to %s, %s, %s\n",
	jid3, node, domain, resource);
    if (strcmp(node, "manic.porter")) return 1;
    if (strcmp(domain, "xyz.net")) return 1;
    if (strcmp(resource, "frob")) return 1;
    if (node) xmpp_free(ctx, node);
    if (domain) xmpp_free(ctx, domain);
    if (resource) xmpp_free(ctx, resource);

    node = xmpp_jid_node(ctx, jid4);
    domain = xmpp_jid_domain(ctx, jid4);
    resource = xmpp_jid_resource(ctx, jid4);
    printf("jid '%s' parsed to %s, %s, %s\n",
	jid4, node, domain, resource);
    if (node != NULL) return 1;
    if (strcmp(domain, "domain.tld")) return 1;
    if (resource != NULL) return 1;
    if (node) xmpp_free(ctx, node);
    if (domain) xmpp_free(ctx, domain);
    if (resource) xmpp_free(ctx, resource);

    return 0;
}
Exemple #2
0
/** Initiate a 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 to connect to
 *  are usually determined by an SRV lookup for the xmpp-client service at
 *  the domain specified in the JID.  If SRV lookup fails, altdomain and 
 *  altport will be used instead if specified.
 *
 *  @param conn a Strophe connection object
 *  @param altdomain a string with domain to use if SRV lookup fails.  If this
 *      is NULL, the domain from the JID will be used.
 *  @param altport an integer port number to use if SRV lookup fails.  If this
 *      is 0, the default port (5222) 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_client(xmpp_conn_t * const conn, 
			  const char * const altdomain,
			  unsigned short altport,
			  xmpp_conn_handler callback,
			  void * const userdata)
{
    char connectdomain[2048];
    int connectport;
    const char * domain;

    conn->type = XMPP_CLIENT;

    conn->domain = xmpp_jid_domain(conn->ctx, conn->jid);
    if (!conn->domain) return -1;

    if (altdomain) {
        xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain.");
        strcpy(connectdomain, altdomain);
        connectport = altport ? altport : 5222;
    } else if (!sock_srv_lookup("xmpp-client", "tcp", conn->domain,
                                connectdomain, 2048, &connectport)) {
	    xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed.");
	    if (!altdomain)
		    domain = conn->domain;
	    else
		    domain = altdomain;
	    xmpp_debug(conn->ctx, "xmpp", "Using alternate domain %s, port %d",
                   altdomain, altport);
	    strcpy(connectdomain, domain);
	    connectport = altport ? altport : 5222;
    }
    conn->sock = sock_connect(connectdomain, connectport);
    xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d",
               connectdomain, connectport, conn->sock);
    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);

    if (conn->xev)
        conn_ev_add_connect_handler(conn->xev);
    
    return 0;
}
Exemple #3
0
/** Initiate a connection to the XMPP server.
 *  This function returns immediately after starting the connection
 *  process to the XMPP server, and notifications of connection state changes
 *  will be sent to the callback function.  The domain and port to connect to
 *  are usually determined by an SRV lookup for the xmpp-client service at
 *  the domain specified in the JID.  If SRV lookup fails, altdomain and 
 *  altport will be used instead if specified.
 *
 *  @param conn a Strophe connection object
 *  @param altdomain a string with domain to use if SRV lookup fails.  If this
 *      is NULL, the domain from the JID will be used.
 *  @param altport an integer port number to use if SRV lookup fails.  If this
 *      is 0, the default port 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 XMPP_EOK (0) on success or a number less than 0 on failure
 *
 *  @ingroup Connections
 */
int xmpp_connect_client(xmpp_conn_t * const conn,
                        const char * const altdomain,
                        unsigned short altport,
                        xmpp_conn_handler callback,
                        void * const userdata)
{
    resolver_srv_rr_t *srv_rr_list = NULL;
    resolver_srv_rr_t *rr;
    char *domain;
    const char *host = NULL;
    unsigned short port = 0;
    int found = XMPP_DOMAIN_NOT_FOUND;
    int rc;

    domain = xmpp_jid_domain(conn->ctx, conn->jid);
    if (!domain) return XMPP_EMEM;

    if (altdomain != NULL) {
        xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain.");
        host = altdomain;
        port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
        found = XMPP_DOMAIN_ALTDOMAIN;

    /* SSL tunneled connection on 5223 port is legacy and doesn't
     * have an SRV record. */
    } else if (!conn->tls_legacy_ssl) {
        found = resolver_srv_lookup(conn->ctx, "xmpp-client", "tcp", domain,
                                    &srv_rr_list);
    }

    if (XMPP_DOMAIN_NOT_FOUND == found) {
        xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed, "
                                      "connecting via domain.");
        host = domain;
        port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
        found = XMPP_DOMAIN_ALTDOMAIN;
    }

    rr = srv_rr_list;
    do {
        if (XMPP_DOMAIN_FOUND == found && rr != NULL) {
            host = rr->target;
            port = rr->port;
            rr = rr->next;
        }
        rc = _conn_connect(conn, domain, host, port, XMPP_CLIENT,
                           callback, userdata);
    } while (rc != 0 && rr != NULL);

    xmpp_free(conn->ctx, domain);
    resolver_srv_free(conn->ctx, srv_rr_list);

    return rc;
}
Exemple #4
0
/** Initiate a 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 to connect to
 *  are usually determined by an SRV lookup for the xmpp-client service at
 *  the domain specified in the JID.  If SRV lookup fails, altdomain and 
 *  altport will be used instead if specified.
 *
 *  @param conn a Strophe connection object
 *  @param altdomain a string with domain to use if SRV lookup fails.  If this
 *      is NULL, the domain from the JID will be used.
 *  @param altport an integer port number to use if SRV lookup fails.  If this
 *      is 0, the default port 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_client(xmpp_conn_t * const conn,
                        const char * const altdomain,
                        unsigned short altport,
                        xmpp_conn_handler callback,
                        void * const userdata)
{
    char domain[2048];
    int port;
    const char *prefdomain = NULL;
    int found;

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

    conn->type = XMPP_CLIENT;
    conn->secured = 0;
    conn->tls_failed = 0;
    conn->domain = xmpp_jid_domain(conn->ctx, conn->jid);
    if (!conn->domain) return -1;

    if (altdomain != NULL) {
        xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain.");
        prefdomain = altdomain;
        port = altport ? altport : _conn_default_port(conn);
    } else {
        found = sock_srv_lookup("xmpp-client", "tcp", conn->domain,
                                domain, sizeof(domain), &port);
        if (!found) {
            xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed, "
                                          "connecting via domain.");
            prefdomain = conn->domain;
            port = altport ? altport : _conn_default_port(conn);
        }
        if (conn->tls_legacy_ssl) {
            /* SSL tunneled connection on 5223 port is legacy and doesn't
             * have an SRV record. Force port 5223 here unless altport is
             * specified.
             */
            port = altport ? altport : XMPP_PORT_CLIENT_LEGACY_SSL;
        }
    }
    if (prefdomain != NULL) {
        strncpy(domain, prefdomain, sizeof(domain));
        domain[sizeof(domain) - 1] = '\0';
    }
    conn->sock = sock_connect(domain, port);
    xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d",
               domain, port, conn->sock);
    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", domain);

    return 0;
}
Exemple #5
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;
}