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; }
static int _handle_features_sasl(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_stanza_t *bind, *session, *iq, *res, *text; char *resource; /* remove missing features handler */ xmpp_timed_handler_delete(conn, _handle_missing_features_sasl); /* we are expecting <bind/> and <session/> since this is a XMPP style connection */ bind = xmpp_stanza_get_child_by_name(stanza, "bind"); if (bind && strcmp(xmpp_stanza_get_ns(bind), XMPP_NS_BIND) == 0) { /* resource binding is required */ conn->bind_required = 1; } session = xmpp_stanza_get_child_by_name(stanza, "session"); if (session && strcmp(xmpp_stanza_get_ns(session), XMPP_NS_SESSION) == 0) { /* session establishment required */ conn->session_required = 1; } /* if bind is required, go ahead and start it */ if (conn->bind_required) { /* bind resource */ /* setup response handlers */ handler_add_id(conn, _handle_bind, "_xmpp_bind1", NULL); handler_add_timed(conn, _handle_missing_bind, BIND_TIMEOUT, NULL); /* send bind request */ iq = xmpp_stanza_new(conn->ctx); if (!iq) { disconnect_mem_error(conn); return 0; } xmpp_stanza_set_name(iq, "iq"); xmpp_stanza_set_type(iq, "set"); xmpp_stanza_set_id(iq, "_xmpp_bind1"); bind = xmpp_stanza_copy(bind); if (!bind) { xmpp_stanza_release(iq); disconnect_mem_error(conn); return 0; } /* request a specific resource if we have one */ resource = xmpp_jid_resource(conn->ctx, conn->jid); if ((resource != NULL) && (strlen(resource) == 0)) { /* jabberd2 doesn't handle an empty resource */ xmpp_free(conn->ctx, resource); resource = NULL; } /* if we have a resource to request, do it. otherwise the server will assign us one */ if (resource) { res = xmpp_stanza_new(conn->ctx); if (!res) { xmpp_stanza_release(bind); xmpp_stanza_release(iq); disconnect_mem_error(conn); return 0; } xmpp_stanza_set_name(res, "resource"); text = xmpp_stanza_new(conn->ctx); if (!text) { xmpp_stanza_release(res); xmpp_stanza_release(bind); xmpp_stanza_release(iq); disconnect_mem_error(conn); return 0; } xmpp_stanza_set_text(text, resource); xmpp_stanza_add_child(res, text); xmpp_stanza_release(text); xmpp_stanza_add_child(bind, res); xmpp_stanza_release(res); xmpp_free(conn->ctx, resource); } xmpp_stanza_add_child(iq, bind); xmpp_stanza_release(bind); /* send bind request */ xmpp_send(conn, iq); xmpp_stanza_release(iq); } else { /* can't bind, disconnect */ xmpp_error(conn->ctx, "xmpp", "Stream features does not allow "\ "resource bind."); xmpp_disconnect(conn); } return 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); } }