Beispiel #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;
}
Beispiel #2
0
/* returns the correct auth id for a component or a client.
 * returned string must be freed by caller */
static char *_get_authid(xmpp_conn_t * const conn)
{
    char *authid = NULL;

    if (conn->type == XMPP_CLIENT) {
	/* authid is the node portion of jid */
	if (!conn->jid) return NULL;
	authid = xmpp_jid_node(conn->ctx, conn->jid);
    }

    return authid;
}
Beispiel #3
0
static char *_make_scram_sha1_init_msg(xmpp_conn_t * const conn)
{
    size_t message_len;
    char *node;
    char *message;
    char nonce[32];

    node = xmpp_jid_node(conn->ctx, conn->jid);
    if (!node) {
        return NULL;
    }
    xmpp_rand_nonce(conn->ctx, nonce, sizeof(nonce));
    message_len = strlen(node) + strlen(nonce) + 8 + 1;
    message = xmpp_alloc(conn->ctx, message_len);
    if (message) {
        xmpp_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce);
    }
    xmpp_free(conn->ctx, node);

    return message;
}
Beispiel #4
0
/* authenticate the connection
 * this may get called multiple times.  if any auth method fails,
 * this will get called again until one auth method succeeds or every
 * method fails
 */
static void _auth(xmpp_conn_t * const conn)
{
    xmpp_stanza_t *auth, *authdata, *query, *child, *iq;
    char *str, *authid;
    char *scram_init;
    int anonjid;

    /* if there is no node in conn->jid, we assume anonymous connect */
    str = xmpp_jid_node(conn->ctx, conn->jid);
    if (str == NULL) {
	anonjid = 1;
    } else {
	xmpp_free(conn->ctx, str);
	anonjid = 0;
    }

    if (conn->tls_support)
    {
	tls_t *tls = tls_new(conn->ctx, conn->sock);

	/* If we couldn't init tls, it isn't there, so go on */
	if (!tls)
	{
	    conn->tls_support = 0;
	    _auth(conn);
	    return;
	}
	else
	{
	    tls_free(tls);
	}

	auth = _make_starttls(conn);

	if (!auth) {
	    disconnect_mem_error(conn);
	    return;
	}

	handler_add(conn, _handle_proceedtls_default,
		    XMPP_NS_TLS, NULL, NULL, NULL);

	xmpp_send(conn, auth);
	xmpp_stanza_release(auth);

	/* TLS was tried, unset flag */
	conn->tls_support = 0;
    } else if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) {
	/* some crap here */
	auth = _make_sasl_auth(conn, "ANONYMOUS");
	if (!auth) {
	    disconnect_mem_error(conn);
	    return;
	}

	handler_add(conn, _handle_sasl_result, XMPP_NS_SASL,
	            NULL, NULL, "ANONYMOUS");

	xmpp_send(conn, auth);
	xmpp_stanza_release(auth);

	/* SASL ANONYMOUS was tried, unset flag */
	conn->sasl_support &= ~SASL_MASK_ANONYMOUS;
    } else if (anonjid) {
	xmpp_error(conn->ctx, "auth",
		   "No node in JID, and SASL ANONYMOUS unsupported.");
	xmpp_disconnect(conn);
    } else if (conn->sasl_support & SASL_MASK_SCRAMSHA1) {
        auth = _make_sasl_auth(conn, "SCRAM-SHA-1");
        if (!auth) {
            disconnect_mem_error(conn);
            return;
        }

        /* don't free scram_init on success */
        scram_init = _make_scram_sha1_init_msg(conn);
        if (!scram_init) {
            xmpp_stanza_release(auth);
            disconnect_mem_error(conn);
            return;
        }

        str = (char *)base64_encode(conn->ctx, (unsigned char *)scram_init,
                                    strlen(scram_init));
        if (!str) {
            xmpp_free(conn->ctx, scram_init);
            xmpp_stanza_release(auth);
            disconnect_mem_error(conn);
            return;
        }

        authdata = xmpp_stanza_new(conn->ctx);
        if (!authdata) {
            xmpp_free(conn->ctx, str);
            xmpp_free(conn->ctx, scram_init);
            xmpp_stanza_release(auth);
            disconnect_mem_error(conn);
            return;
        }
        xmpp_stanza_set_text(authdata, str);
        xmpp_free(conn->ctx, str);
        xmpp_stanza_add_child(auth, authdata);
        xmpp_stanza_release(authdata);

        handler_add(conn, _handle_scram_sha1_challenge,
                    XMPP_NS_SASL, NULL, NULL, (void *)scram_init);

        xmpp_send(conn, auth);
        xmpp_stanza_release(auth);

        /* SASL SCRAM-SHA-1 was tried, unset flag */
        conn->sasl_support &= ~SASL_MASK_SCRAMSHA1;
    } else if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
	auth = _make_sasl_auth(conn, "DIGEST-MD5");
	if (!auth) {
	    disconnect_mem_error(conn);
	    return;

	}

	handler_add(conn, _handle_digestmd5_challenge,
		    XMPP_NS_SASL, NULL, NULL, NULL);

	xmpp_send(conn, auth);
	xmpp_stanza_release(auth);

	/* SASL DIGEST-MD5 was tried, unset flag */
	conn->sasl_support &= ~SASL_MASK_DIGESTMD5;
    } else if (conn->sasl_support & SASL_MASK_PLAIN) {
	auth = _make_sasl_auth(conn, "PLAIN");
	if (!auth) {
	    disconnect_mem_error(conn);
	    return;
	}
	authdata = xmpp_stanza_new(conn->ctx);
	if (!authdata) {
	    disconnect_mem_error(conn);
	    return;
	}
	authid = _get_authid(conn);
	if (!authid) {
	    disconnect_mem_error(conn);
	    return;
	}
	str = sasl_plain(conn->ctx, authid, conn->pass);
	if (!str) {
	    disconnect_mem_error(conn);
	    return;
	}
	xmpp_stanza_set_text(authdata, str);
	xmpp_free(conn->ctx, str);
	xmpp_free(conn->ctx, authid);

	xmpp_stanza_add_child(auth, authdata);
	xmpp_stanza_release(authdata);

	handler_add(conn, _handle_sasl_result,
		    XMPP_NS_SASL, NULL, NULL, "PLAIN");

	xmpp_send(conn, auth);
	xmpp_stanza_release(auth);

	/* SASL PLAIN was tried */
	conn->sasl_support &= ~SASL_MASK_PLAIN;
    } else if (conn->type == XMPP_CLIENT) {
	/* legacy client authentication */

	iq = xmpp_stanza_new(conn->ctx);
	if (!iq) {
	    disconnect_mem_error(conn);
	    return;
	}
	xmpp_stanza_set_name(iq, "iq");
	xmpp_stanza_set_type(iq, "set");
	xmpp_stanza_set_id(iq, "_xmpp_auth1");

	query = xmpp_stanza_new(conn->ctx);
	if (!query) {
	    xmpp_stanza_release(iq);
	    disconnect_mem_error(conn);
	    return;
	}
	xmpp_stanza_set_name(query, "query");
	xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
	xmpp_stanza_add_child(iq, query);
	xmpp_stanza_release(query);

	child = xmpp_stanza_new(conn->ctx);
	if (!child) {
	    xmpp_stanza_release(iq);
	    disconnect_mem_error(conn);
	    return;
	}
	xmpp_stanza_set_name(child, "username");
	xmpp_stanza_add_child(query, child);
	xmpp_stanza_release(child);

	authdata = xmpp_stanza_new(conn->ctx);
	if (!authdata) {
	    xmpp_stanza_release(iq);
	    disconnect_mem_error(conn);
	    return;
	}
	str = xmpp_jid_node(conn->ctx, conn->jid);
	xmpp_stanza_set_text(authdata, str);
	xmpp_free(conn->ctx, str);
	xmpp_stanza_add_child(child, authdata);
	xmpp_stanza_release(authdata);

	child = xmpp_stanza_new(conn->ctx);
	if (!child) {
	    xmpp_stanza_release(iq);
	    disconnect_mem_error(conn);
	    return;
	}
	xmpp_stanza_set_name(child, "password");
	xmpp_stanza_add_child(query, child);
	xmpp_stanza_release(child);

	authdata = xmpp_stanza_new(conn->ctx);
	if (!authdata) {
	    xmpp_stanza_release(iq);
	    disconnect_mem_error(conn);
	    return;
	}
	xmpp_stanza_set_text(authdata, conn->pass);
	xmpp_stanza_add_child(child, authdata);
	xmpp_stanza_release(authdata);

	child = xmpp_stanza_new(conn->ctx);
	if (!child) {
	    xmpp_stanza_release(iq);
	    disconnect_mem_error(conn);
	    return;
	}
	xmpp_stanza_set_name(child, "resource");
	xmpp_stanza_add_child(query, child);
	xmpp_stanza_release(child);

	authdata = xmpp_stanza_new(conn->ctx);
	if (!authdata) {
	    xmpp_stanza_release(iq);
	    disconnect_mem_error(conn);
	    return;
	}
	str = xmpp_jid_resource(conn->ctx, conn->jid);
	if (str) {
	    xmpp_stanza_set_text(authdata, str);
	    xmpp_free(conn->ctx, str);
	} else {
	    xmpp_stanza_release(authdata);
	    xmpp_stanza_release(iq);
	    xmpp_error(conn->ctx, "auth",
		       "Cannot authenticate without resource");
	    xmpp_disconnect(conn);
	    return;
	}
	xmpp_stanza_add_child(child, authdata);
	xmpp_stanza_release(authdata);

	handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
	handler_add_timed(conn, _handle_missing_legacy,
			  LEGACY_TIMEOUT, NULL);

	xmpp_send(conn, iq);
	xmpp_stanza_release(iq);
    }
}
Beispiel #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;
}
Beispiel #6
0
/** registration at connections
 *
 *  @param conn a Strophe connection object
 */
static void _register(xmpp_conn_t * const conn)
{
    char *str;

    xmpp_stanza_t *iq, *q, *child, *regdata;

    iq = xmpp_stanza_new(conn->ctx);
    if (!iq) {
	disconnect_mem_error(conn);
	return;
    }

    xmpp_stanza_set_name(iq, "iq");
    xmpp_stanza_set_type(iq, "set");
    xmpp_stanza_set_id(iq, "_xmpp_reg1");

    q = xmpp_stanza_new(conn->ctx);
    if (!q) {
	xmpp_stanza_release(iq);
	disconnect_mem_error(conn);
	return;
    }
    xmpp_stanza_set_name(q, "query");
    xmpp_stanza_set_ns(q, XMPP_NS_REGISTER);
    xmpp_stanza_add_child(iq, q);
    xmpp_stanza_release(q);

    child = xmpp_stanza_new(conn->ctx);
    if (!child) {
	xmpp_stanza_release(iq);
	disconnect_mem_error(conn);
	return;
    }
    xmpp_stanza_set_name(child, "registered");
    xmpp_stanza_add_child(q, child);
    xmpp_stanza_release(child);

    child = xmpp_stanza_new(conn->ctx);
    if (!child) {
	xmpp_stanza_release(iq);
	disconnect_mem_error(conn);
	return;
    }
    xmpp_stanza_set_name(child, "username");
    xmpp_stanza_add_child(q, child);
    xmpp_stanza_release(child);

    regdata = xmpp_stanza_new(conn->ctx);
    if (!regdata) {
	xmpp_stanza_release(iq);
	disconnect_mem_error(conn);
	return;
    }
    str = xmpp_jid_node(conn->ctx, conn->jid);
    xmpp_stanza_set_text(regdata, str);
    xmpp_free(conn->ctx, str);
    xmpp_stanza_add_child(child, regdata);
    xmpp_stanza_release(regdata);

    child = xmpp_stanza_new(conn->ctx);
    if (!child) {
	xmpp_stanza_release(iq);
	disconnect_mem_error(conn);
	return;
    }
    xmpp_stanza_set_name(child, "password");
    xmpp_stanza_add_child(q, child);
    xmpp_stanza_release(child);

    regdata = xmpp_stanza_new(conn->ctx);
    if (!regdata) {
	xmpp_stanza_release(iq);
	disconnect_mem_error(conn);
	return;
    }
    xmpp_stanza_set_text(regdata, conn->pass);
    xmpp_stanza_add_child(child, regdata);
    xmpp_stanza_release(regdata);

    child = xmpp_stanza_new(conn->ctx);
    if (!child) {
	xmpp_stanza_release(iq);
	disconnect_mem_error(conn);
	return;
    }
    xmpp_stanza_set_name(child, "email");
    xmpp_stanza_add_child(q, child);
    xmpp_stanza_release(child);

    regdata = xmpp_stanza_new(conn->ctx);
    if (!regdata) {
	xmpp_stanza_release(iq);
	disconnect_mem_error(conn);
	return;
    }
    str = xmpp_jid_node(conn->ctx, conn->jid);
    xmpp_stanza_set_text(regdata, str);
    xmpp_free(conn->ctx, str);
    xmpp_stanza_add_child(child, regdata);
    xmpp_stanza_release(regdata);

    handler_add_id(conn, _handle_register, "_xmpp_reg1", NULL);
    handler_add_timed(conn, _handle_missing_register, 
		      LAZY_REGISTRATION_TIMEOUT, NULL);

    xmpp_send(conn, iq);
    xmpp_stanza_release(iq);
}