From 099cd07887a1af2ead77a60f744658b7077ed58f Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 3 Jan 2013 15:40:21 +0000 Subject: [PATCH] Prevent exhaustion of system resources through exploitation of event cache This patch changes res_xmpp to no longer cache events under certain circumstances. (issue ASTERISK-20175) Reported by: Russell Bryant, Leif Madsen, Joshua Colp Tested by: kmoore ........ Merged revisions 378411 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@378412 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- res/res_xmpp.c | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index d490ee516e..1e130e7715 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -928,7 +928,7 @@ static iks* xmpp_pubsub_iq_create(struct ast_xmpp_client *client, const char *ty * \return iks * */ static iks* xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, const char *node, - const char *event_type) + const char *event_type, unsigned int cachable) { RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); iks *request, *pubsub, *publish, *item; @@ -944,6 +944,22 @@ static iks* xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, c item = iks_insert(publish, "item"); iks_insert_attrib(item, "id", node); + if (cachable == AST_DEVSTATE_NOT_CACHABLE) { + iks *options, *x, *field_form_type, *field_persist; + + options = iks_insert(pubsub, "publish-options"); + x = iks_insert(options, "x"); + iks_insert_attrib(x, "xmlns", "jabber:x:data"); + iks_insert_attrib(x, "type", "submit"); + field_form_type = iks_insert(x, "field"); + iks_insert_attrib(field_form_type, "var", "FORM_TYPE"); + iks_insert_attrib(field_form_type, "type", "hidden"); + iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0); + field_persist = iks_insert(x, "field"); + iks_insert_attrib(field_persist, "var", "pubsub#persist_items"); + iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1); + } + return item; } @@ -1120,7 +1136,7 @@ static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char * snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context); - if (!(request = xmpp_pubsub_build_publish_skeleton(client, full_mailbox, "message_waiting"))) { + if (!(request = xmpp_pubsub_build_publish_skeleton(client, full_mailbox, "message_waiting", AST_DEVSTATE_CACHABLE))) { return; } @@ -1144,13 +1160,13 @@ static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char * * \return void */ static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, const char *device, - const char *device_state) + const char *device_state, unsigned int cachable) { RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); iks *request, *state; - char eid_str[20]; + char eid_str[20], cachable_str[2]; - if (!cfg || !cfg->global || !(request = xmpp_pubsub_build_publish_skeleton(client, device, "device_state"))) { + if (!cfg || !cfg->global || !(request = xmpp_pubsub_build_publish_skeleton(client, device, "device_state", cachable))) { return; } @@ -1166,6 +1182,8 @@ static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, con state = iks_insert(request, "state"); iks_insert_attrib(state, "xmlns", "http://asterisk.org"); iks_insert_attrib(state, "eid", eid_str); + snprintf(cachable_str, sizeof(cachable_str), "%u", cachable); + iks_insert_attrib(state, "cachable", cachable_str); iks_insert_cdata(state, device_state, strlen(device_state)); ast_xmpp_client_send(client, iks_root(request)); iks_delete(request); @@ -1208,6 +1226,7 @@ static void xmpp_pubsub_devstate_cb(const struct ast_event *ast_event, void *dat { struct ast_xmpp_client *client = data; const char *device, *device_state; + unsigned int cachable; if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) { /* If the event didn't originate from this server, don't send it back out. */ @@ -1217,7 +1236,8 @@ static void xmpp_pubsub_devstate_cb(const struct ast_event *ast_event, void *dat device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE); device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE)); - xmpp_pubsub_publish_device_state(client, device, device_state); + cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE); + xmpp_pubsub_publish_device_state(client, device, device_state, cachable); } /*! @@ -1301,11 +1321,12 @@ static void xmpp_pubsub_subscribe(struct ast_xmpp_client *client, const char *no */ static int xmpp_pubsub_handle_event(void *data, ikspak *pak) { - char *item_id, *device_state, *context; + char *item_id, *device_state, *context, *cachable_str; int oldmsgs, newmsgs; iks *item, *item_content; struct ast_eid pubsub_eid; struct ast_event *event; + unsigned int cachable = AST_DEVSTATE_CACHABLE; item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item"); if (!item) { ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n"); @@ -1320,6 +1341,9 @@ static int xmpp_pubsub_handle_event(void *data, ikspak *pak) } if (!strcasecmp(iks_name(item_content), "state")) { device_state = iks_find_cdata(item, "state"); + if ((cachable_str = iks_find_cdata(item, "cachable"))) { + sscanf(cachable_str, "%30d", &cachable); + } if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE, AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID, @@ -1344,7 +1368,13 @@ static int xmpp_pubsub_handle_event(void *data, ikspak *pak) iks_name(item_content)); return IKS_FILTER_EAT; } - ast_event_queue_and_cache(event); + + if (cachable == AST_DEVSTATE_CACHABLE) { + ast_event_queue_and_cache(event); + } else { + ast_event_queue(event); + } + return IKS_FILTER_EAT; }