From ef8d1c7198d632e0dc8cef95e7590c8028d50ac6 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Fri, 4 Dec 2015 17:44:53 -0500 Subject: [PATCH] FS-8619 [mod_rayo] reply with conflict stanza error if bind is attempted with duplicate JID. Improve error handling when 'ready' callback fails. --- src/mod/event_handlers/mod_rayo/mod_rayo.c | 35 ++++--- .../event_handlers/mod_rayo/xmpp_streams.c | 95 +++++++++++-------- .../event_handlers/mod_rayo/xmpp_streams.h | 7 +- 3 files changed, 84 insertions(+), 53 deletions(-) diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index 11828ce328..c865dd5070 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -4199,11 +4199,31 @@ static struct rayo_actor *xmpp_stream_client_locate(struct xmpp_stream *stream, return actor; } +/** + * Handle stream resource binding + * @param stream the new stream + */ +static int on_xmpp_stream_bind(struct xmpp_stream *stream) +{ + if (!xmpp_stream_is_s2s(stream)) { + /* client belongs to stream */ + struct rayo_client *client = rayo_client_create(xmpp_stream_get_jid(stream), xmpp_stream_get_jid(stream), PS_OFFLINE, rayo_client_send, NULL); + if (client) { + xmpp_stream_set_private(stream, client); + } else { + /* this went really bad... */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to create client entity!\n"); + return 0; + } + } + return 1; +} + /** * Handle new stream creation * @param stream the new stream */ -static void on_xmpp_stream_ready(struct xmpp_stream *stream) +static int on_xmpp_stream_ready(struct xmpp_stream *stream) { if (xmpp_stream_is_s2s(stream)) { if (xmpp_stream_is_incoming(stream)) { @@ -4214,6 +4234,7 @@ static void on_xmpp_stream_ready(struct xmpp_stream *stream) } else { /* this went really bad... */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to create peer server entity!\n"); + return 0; } } else { /* send directed presence to domain */ @@ -4227,16 +4248,8 @@ static void on_xmpp_stream_ready(struct xmpp_stream *stream) iks_insert_cdata(x, "chat", 4); RAYO_SEND_MESSAGE(globals.server, xmpp_stream_get_jid(stream), presence); } - } else { - /* client belongs to stream */ - struct rayo_client *client = rayo_client_create(xmpp_stream_get_jid(stream), xmpp_stream_get_jid(stream), PS_OFFLINE, rayo_client_send, NULL); - if (client) { - xmpp_stream_set_private(stream, client); - } else { - /* this went really bad... */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to create client entity!\n"); - } } + return 1; } /** @@ -4486,7 +4499,7 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing shared secret for %s domain. Server dialback will not work\n", name); } - globals.xmpp_context = xmpp_stream_context_create(name, shared_secret, on_xmpp_stream_ready, on_xmpp_stream_recv, on_xmpp_stream_destroy); + globals.xmpp_context = xmpp_stream_context_create(name, shared_secret, on_xmpp_stream_bind, on_xmpp_stream_ready, on_xmpp_stream_recv, on_xmpp_stream_destroy); globals.server = rayo_server_create(name); /* set up TLS */ diff --git a/src/mod/event_handlers/mod_rayo/xmpp_streams.c b/src/mod/event_handlers/mod_rayo/xmpp_streams.c index 23a7387db6..fcc3c76213 100644 --- a/src/mod/event_handlers/mod_rayo/xmpp_streams.c +++ b/src/mod/event_handlers/mod_rayo/xmpp_streams.c @@ -1,6 +1,6 @@ /* * mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2013, Grasshopper + * Copyright (C) 2013-2015, Grasshopper * * Version: MPL 1.1 * @@ -55,6 +55,8 @@ struct xmpp_stream_context { switch_hash_t *users; /** shared secret for server dialback */ const char *dialback_secret; + /** callback when a new resource is bound */ + xmpp_stream_bind_callback bind_callback; /** callback when a new stream is ready */ xmpp_stream_ready_callback ready_callback; /** callback when a stream is destroyed */ @@ -539,17 +541,19 @@ static iks *on_iq_set_xmpp_session(struct xmpp_stream *stream, iks *node) switch(stream->state) { case XSS_RESOURCE_BOUND: { - reply = iks_new_iq_result(node); - stream->state = XSS_READY; + if (context->ready_callback && !context->ready_callback(stream)) { + reply = iks_new_error(node, STANZA_ERROR_INTERNAL_SERVER_ERROR); + stream->state = XSS_ERROR; + } else { + reply = iks_new_iq_result(node); + stream->state = XSS_READY; - /* add to available streams */ - switch_mutex_lock(context->streams_mutex); - switch_core_hash_insert(context->routes, stream->jid, stream); - switch_mutex_unlock(context->streams_mutex); - - if (context->ready_callback) { - context->ready_callback(stream); + /* add to available streams */ + switch_mutex_lock(context->streams_mutex); + switch_core_hash_insert(context->routes, stream->jid, stream); + switch_mutex_unlock(context->streams_mutex); } + break; } case XSS_AUTHENTICATED: @@ -574,6 +578,7 @@ static iks *on_iq_set_xmpp_bind(struct xmpp_stream *stream, iks *node) switch(stream->state) { case XSS_AUTHENTICATED: { + struct xmpp_stream_context *context = stream->context; iks *bind = iks_find(node, "bind"); iks *x; /* get optional client resource ID */ @@ -585,14 +590,19 @@ static iks *on_iq_set_xmpp_bind(struct xmpp_stream *stream, iks *node) switch_uuid_str(resource_id_buf, sizeof(resource_id_buf)); resource_id = switch_core_strdup(stream->pool, resource_id_buf); } - stream->jid = switch_core_sprintf(stream->pool, "%s/%s", stream->jid, resource_id); - stream->state = XSS_RESOURCE_BOUND; - /* create reply */ - reply = iks_new_iq_result(node); - x = iks_insert(reply, "bind"); - iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_BIND); - iks_insert_cdata(iks_insert(x, "jid"), stream->jid, strlen(stream->jid)); + stream->jid = switch_core_sprintf(stream->pool, "%s/%s", stream->jid, resource_id); + if (context->bind_callback && !context->bind_callback(stream)) { + stream->jid = NULL; + reply = iks_new_error(node, STANZA_ERROR_CONFLICT); + } else { + stream->state = XSS_RESOURCE_BOUND; + + reply = iks_new_iq_result(node); + x = iks_insert(reply, "bind"); + iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_BIND); + iks_insert_cdata(iks_insert(x, "jid"), stream->jid, strlen(stream->jid)); + } break; } default: @@ -732,16 +742,16 @@ static void on_stream_dialback_result_valid(struct xmpp_stream *stream, iks *nod /* TODO check domain pair and allow access if pending request exists */ switch_log_printf(SWITCH_CHANNEL_UUID_LOG(stream->id), SWITCH_LOG_DEBUG, "%s, %s:%i, valid dialback result\n", stream->jid, stream->address, stream->port); - /* this stream is routable */ - stream->state = XSS_READY; + if (context->ready_callback && !context->ready_callback(stream)) { + stream->state = XSS_ERROR; + } else { + /* this stream is routable */ + stream->state = XSS_READY; - /* add to available streams */ - switch_mutex_lock(context->streams_mutex); - switch_core_hash_insert(context->routes, stream->jid, stream); - switch_mutex_unlock(context->streams_mutex); - - if (context->ready_callback) { - context->ready_callback(stream); + /* add to available streams */ + switch_mutex_lock(context->streams_mutex); + switch_core_hash_insert(context->routes, stream->jid, stream); + switch_mutex_unlock(context->streams_mutex); } } @@ -816,6 +826,18 @@ static void on_stream_dialback_result_key(struct xmpp_stream *stream, iks *node) return; } + /* this stream is not routable */ + stream->state = XSS_READY; + stream->jid = switch_core_strdup(stream->pool, from); + + if (context->ready_callback && !context->ready_callback(stream)) { + iks *error = iks_new_error(node, STANZA_ERROR_INTERNAL_SERVER_ERROR); + iks_send(stream->parser, error); + iks_delete(error); + stream->state = XSS_ERROR; + return; + } + /* TODO validate key */ reply = iks_new("db:result"); iks_insert_attrib(reply, "from", to); @@ -823,14 +845,6 @@ static void on_stream_dialback_result_key(struct xmpp_stream *stream, iks *node) iks_insert_attrib(reply, "type", "valid"); iks_send(stream->parser, reply); iks_delete(reply); - - /* this stream is not routable */ - stream->state = XSS_READY; - stream->jid = switch_core_strdup(stream->pool, from); - - if (context->ready_callback) { - context->ready_callback(stream); - } } /** @@ -1014,6 +1028,11 @@ static void on_inbound_server_stream_start(struct xmpp_stream *stream, iks *node case XSS_SECURE: break; case XSS_AUTHENTICATED: { + if (context->ready_callback && !context->ready_callback(stream)) { + stream->state = XSS_ERROR; + break; + } + /* all set */ xmpp_send_server_header_features(stream); stream->state = XSS_READY; @@ -1022,10 +1041,6 @@ static void on_inbound_server_stream_start(struct xmpp_stream *stream, iks *node switch_mutex_lock(context->streams_mutex); switch_core_hash_insert(context->routes, stream->jid, stream); switch_mutex_unlock(context->streams_mutex); - - if (context->ready_callback) { - context->ready_callback(stream); - } break; } case XSS_SHUTDOWN: @@ -1745,12 +1760,13 @@ void xmpp_stream_context_dump(struct xmpp_stream_context *context, switch_stream * Create a new XMPP stream context * @param domain for new streams * @param domain_secret domain shared secret for server dialback + * @param bind_cb callback function when a resource is bound to a new stream * @param ready callback function when new stream is ready * @param recv callback function when a new stanza is received * @param destroy callback function when a stream is destroyed * @return the context */ -struct xmpp_stream_context *xmpp_stream_context_create(const char *domain, const char *domain_secret, xmpp_stream_ready_callback ready, xmpp_stream_recv_callback recv, xmpp_stream_destroy_callback destroy) +struct xmpp_stream_context *xmpp_stream_context_create(const char *domain, const char *domain_secret, xmpp_stream_bind_callback bind_cb, xmpp_stream_ready_callback ready, xmpp_stream_recv_callback recv, xmpp_stream_destroy_callback destroy) { switch_memory_pool_t *pool; struct xmpp_stream_context *context; @@ -1762,6 +1778,7 @@ struct xmpp_stream_context *xmpp_stream_context_create(const char *domain, const switch_core_hash_init(&context->routes); switch_core_hash_init(&context->streams); context->dialback_secret = switch_core_strdup(context->pool, domain_secret); + context->bind_callback = bind_cb; context->ready_callback = ready; context->destroy_callback = destroy; context->recv_callback = recv; diff --git a/src/mod/event_handlers/mod_rayo/xmpp_streams.h b/src/mod/event_handlers/mod_rayo/xmpp_streams.h index a07c75d025..242f392543 100644 --- a/src/mod/event_handlers/mod_rayo/xmpp_streams.h +++ b/src/mod/event_handlers/mod_rayo/xmpp_streams.h @@ -1,6 +1,6 @@ /* * mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2013, Grasshopper + * Copyright (C) 2013-2015, Grasshopper * * Version: MPL 1.1 * @@ -32,11 +32,12 @@ struct xmpp_stream; struct xmpp_stream_context; -typedef void (* xmpp_stream_ready_callback)(struct xmpp_stream *stream); +typedef int (* xmpp_stream_bind_callback)(struct xmpp_stream *stream); +typedef int (* xmpp_stream_ready_callback)(struct xmpp_stream *stream); typedef void (* xmpp_stream_recv_callback)(struct xmpp_stream *stream, iks *stanza); typedef void (* xmpp_stream_destroy_callback)(struct xmpp_stream *stream); -extern struct xmpp_stream_context *xmpp_stream_context_create(const char *domain, const char *domain_secret, xmpp_stream_ready_callback ready, xmpp_stream_recv_callback recv, xmpp_stream_destroy_callback destroy); +extern struct xmpp_stream_context *xmpp_stream_context_create(const char *domain, const char *domain_secret, xmpp_stream_bind_callback bind_cb, xmpp_stream_ready_callback ready, xmpp_stream_recv_callback recv, xmpp_stream_destroy_callback destroy); extern void xmpp_stream_context_add_cert(struct xmpp_stream_context *context, const char *cert_pem_file); extern void xmpp_stream_context_add_key(struct xmpp_stream_context *context, const char *key_pem_file); extern void xmpp_stream_context_add_user(struct xmpp_stream_context *context, const char *user, const char *password);