XEP-0114: external component authentication
New API xmpp_connect_component() introduced.
This commit is contained in:
committed by
Dmitry Podgorny
parent
37a40dec23
commit
5d76e052ec
123
src/auth.c
123
src/auth.c
@@ -18,6 +18,10 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Added by Milan Kubik. <email@kubikmilan.sk>
|
||||
* Needed for component handshake handler (xep-0114) to compute SHA1 digest. */
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "sasl.h"
|
||||
@@ -52,9 +56,21 @@
|
||||
*/
|
||||
#define LEGACY_TIMEOUT 15000 /* 15 seconds */
|
||||
#endif
|
||||
#ifndef HANDSHAKE_TIMEOUT
|
||||
/** @def HANDSHAKE_TIMEOUT
|
||||
* Time to wait for component authentication to complete
|
||||
*/
|
||||
#define HANDSHAKE_TIMEOUT 15000 /* 15 seconds */
|
||||
#endif
|
||||
|
||||
static void _auth(xmpp_conn_t * const conn);
|
||||
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
||||
|
||||
static int _handle_component_auth(xmpp_conn_t * const conn);
|
||||
static int _handle_component_hs_response(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata);
|
||||
|
||||
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
static int _handle_legacy(xmpp_conn_t * const conn,
|
||||
@@ -89,6 +105,8 @@ static int _handle_session(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
static int _handle_missing_session(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
static int _handle_missing_handshake(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
|
||||
/* stream:error handler */
|
||||
static int _handle_error(xmpp_conn_t * const conn,
|
||||
@@ -1148,3 +1166,108 @@ static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void auth_handle_component_open(xmpp_conn_t * const conn)
|
||||
{
|
||||
/* reset all timed handlers */
|
||||
handler_reset_timed(conn, 0);
|
||||
|
||||
/* Handler for component accept */
|
||||
|
||||
handler_add(conn, _handle_error,
|
||||
NULL, "stream:error", NULL, NULL);
|
||||
|
||||
handler_add(conn, _handle_component_hs_response, NULL,
|
||||
"handshake", NULL, NULL);
|
||||
|
||||
handler_add_timed(conn, _handle_missing_handshake,
|
||||
HANDSHAKE_TIMEOUT, NULL);
|
||||
|
||||
_handle_component_auth(conn);
|
||||
}
|
||||
|
||||
/* Will compute SHA1 and authenticate the component to the server */
|
||||
int _handle_component_auth(xmpp_conn_t * const conn)
|
||||
{
|
||||
unsigned char md_value[EVP_MAX_MD_SIZE];
|
||||
EVP_MD_CTX *mdctx;
|
||||
const EVP_MD *md;
|
||||
char *digest;
|
||||
unsigned int md_len, i;
|
||||
|
||||
/* Feed the session id and passphrase to the algorithm.
|
||||
* We need to compute SHA1(session_id + passphrase)
|
||||
*/
|
||||
md = EVP_get_digestbyname("sha1");
|
||||
mdctx = EVP_MD_CTX_create();
|
||||
EVP_DigestInit_ex(mdctx, md, NULL);
|
||||
|
||||
/* Feed in the data. */
|
||||
EVP_DigestUpdate(mdctx, conn->stream_id, strlen(conn->stream_id));
|
||||
EVP_DigestUpdate(mdctx, conn->pass, strlen(conn->pass));
|
||||
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
|
||||
digest = malloc(2*md_len+1);
|
||||
if (digest) {
|
||||
memset(digest, 0, 2*md_len+1);
|
||||
/* convert the digest into string representation */
|
||||
for (i = 0; i < md_len; i++)
|
||||
snprintf(digest+i*2, 3,"%02x", md_value[i]);
|
||||
|
||||
xmpp_debug(conn->ctx, "auth", "Digest: %s, len: %d", (char *) digest, strlen((char *)digest));
|
||||
|
||||
/* Send the digest to the server */
|
||||
xmpp_send_raw_string(conn, "<handshake xmlns='%s'>%s</handshake>",
|
||||
XMPP_NS_COMPONENT, digest);
|
||||
xmpp_debug(conn->ctx, "auth", "Sent component handshake to the server.");
|
||||
free(digest);
|
||||
} else {
|
||||
xmpp_debug(conn->ctx, "auth", "Couldn't allocate memory for component handshake digest.");
|
||||
xmpp_disconnect(conn);
|
||||
return XMPP_EMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _handle_component_hs_response(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
/* Check if the received stanza is <handshake/> and set auth to true
|
||||
* and fire connection handler.
|
||||
*/
|
||||
|
||||
char * name;
|
||||
|
||||
xmpp_timed_handler_delete(conn, _handle_missing_handshake);
|
||||
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
|
||||
if (strcmp(name, "handshake") != 0) {
|
||||
char *msg;
|
||||
size_t msg_size;
|
||||
xmpp_stanza_to_text(stanza, &msg, &msg_size);
|
||||
|
||||
xmpp_debug(conn->ctx, "auth", "Handshake failed: %s",
|
||||
msg);
|
||||
xmpp_disconnect(conn);
|
||||
free(msg);
|
||||
return XMPP_EINT;
|
||||
} else {
|
||||
conn->authenticated = 1;
|
||||
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
|
||||
}
|
||||
|
||||
/* We don't need this handler anymore, return 0 so it can be deleted
|
||||
* from the list of handlers.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _handle_missing_handshake(xmpp_conn_t * const conn, void * const userdata)
|
||||
{
|
||||
xmpp_error(conn->ctx, "xmpp", "Server did not reply to handshake request.");
|
||||
xmpp_disconnect(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -264,6 +264,7 @@ void disconnect_mem_error(xmpp_conn_t * const conn);
|
||||
|
||||
/* auth functions */
|
||||
void auth_handle_open(xmpp_conn_t * const conn);
|
||||
void auth_handle_component_open(xmpp_conn_t * const conn);
|
||||
|
||||
/* replacement snprintf and vsnprintf */
|
||||
int xmpp_snprintf (char *str, size_t count, const char *fmt, ...);
|
||||
|
||||
69
src/conn.c
69
src/conn.c
@@ -439,6 +439,73 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
||||
return 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;
|
||||
|
||||
conn->type = XMPP_COMPONENT;
|
||||
/* 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 : 5347;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/** Cleanly disconnect the connection.
|
||||
* This function is only called by the stream parser when </stream:stream>
|
||||
* is received, and it not intended to be called by code outside of Strophe.
|
||||
@@ -740,7 +807,7 @@ static void _handle_stream_start(char *name, char **attrs,
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* call stream open handler */
|
||||
conn->open_handler(conn);
|
||||
}
|
||||
|
||||
@@ -222,9 +222,10 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
||||
xmpp_conn_handler callback,
|
||||
void * const userdata);
|
||||
|
||||
/*
|
||||
int xmpp_connect_component(conn, name)
|
||||
*/
|
||||
int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
|
||||
unsigned short port, xmpp_conn_handler callback,
|
||||
void * const userdata);
|
||||
|
||||
void xmpp_disconnect(xmpp_conn_t * const conn);
|
||||
|
||||
void xmpp_send(xmpp_conn_t * const conn,
|
||||
|
||||
Reference in New Issue
Block a user