diff options
author | Jonathan Rose <jrose@digium.com> | 2013-05-17 17:36:10 +0000 |
---|---|---|
committer | Jonathan Rose <jrose@digium.com> | 2013-05-17 17:36:10 +0000 |
commit | b90bba7a303bf57c3c874a1c8f506d39d4e78a9c (patch) | |
tree | 56e6ca0d885b1e9e11856a6be44b4b92582f5606 /main | |
parent | 15945a7185187a3d79c7c7247a297bf92b49c139 (diff) |
Stasis: Update security events to use Stasis
Also moves ACL messages to the security topic and gets rid of the
ACL topic
(closes issue ASTERISK-21103)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2496/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@388975 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r-- | main/asterisk.c | 7 | ||||
-rw-r--r-- | main/json.c | 44 | ||||
-rw-r--r-- | main/manager.c | 8 | ||||
-rw-r--r-- | main/named_acl.c | 20 | ||||
-rw-r--r-- | main/security_events.c | 231 |
5 files changed, 211 insertions, 99 deletions
diff --git a/main/asterisk.c b/main/asterisk.c index 9308230fb..933aae63d 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -242,6 +242,7 @@ int daemon(int, int); /* defined in libresolv of all places */ #include "asterisk/sorcery.h" #include "asterisk/stasis.h" #include "asterisk/json.h" +#include "asterisk/security_events.h" #include "asterisk/stasis_endpoints.h" #include "../defaults.h" @@ -4263,6 +4264,12 @@ int main(int argc, char *argv[]) exit(1); } + if (ast_security_stasis_init()) { /* Initialize Security Stasis Topic and Events */ + ast_security_stasis_cleanup(); + printf("%s", term_quit()); + exit(1); + } + if (ast_named_acl_init()) { /* Initialize the Named ACL system */ printf("%s", term_quit()); exit(1); diff --git a/main/json.c b/main/json.c index 87971f04a..5b69ccbaa 100644 --- a/main/json.c +++ b/main/json.c @@ -527,6 +527,50 @@ struct ast_json *ast_json_timeval(const struct timeval tv, const char *zone) return ast_json_string_create(buf); } +struct ast_json *ast_json_ipaddr(const struct ast_sockaddr *addr, enum ast_transport transport_type) +{ + struct ast_str *string = ast_str_alloca(64); + + if (!string) { + return NULL; + } + + ast_str_set(&string, 0, (ast_sockaddr_is_ipv4(addr) || + ast_sockaddr_is_ipv4_mapped(addr)) ? "IPV4/" : "IPV6/"); + + if (transport_type) { + char *transport_string = NULL; + + /* NOTE: None will be applied if multiple transport types are specified in transport_type */ + switch(transport_type) { + case AST_TRANSPORT_UDP: + transport_string = "UDP"; + break; + case AST_TRANSPORT_TCP: + transport_string = "TCP"; + break; + case AST_TRANSPORT_TLS: + transport_string = "TLS"; + break; + case AST_TRANSPORT_WS: + transport_string = "WS"; + break; + case AST_TRANSPORT_WSS: + transport_string = "WSS"; + break; + } + + if (transport_string) { + ast_str_append(&string, 0, "%s/", transport_string); + } + } + + ast_str_append(&string, 0, "%s", ast_sockaddr_stringify_addr(addr)); + ast_str_append(&string, 0, "/%s", ast_sockaddr_stringify_port(addr)); + + return ast_json_string_create(ast_str_buffer(string)); +} + void ast_json_init(void) { /* Setup to use Asterisk custom allocators */ diff --git a/main/manager.c b/main/manager.c index 6e7ea1e20..4d2923eb5 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1070,7 +1070,7 @@ static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, st static void acl_change_stasis_subscribe(void) { if (!acl_change_sub) { - acl_change_sub = stasis_subscribe(ast_acl_topic(), + acl_change_sub = stasis_subscribe(ast_security_topic(), acl_change_stasis_cb, NULL); } } @@ -2361,10 +2361,10 @@ static int set_eventmask(struct mansession *s, const char *eventmask) return maskint; } -static enum ast_security_event_transport_type mansession_get_transport(const struct mansession *s) +static enum ast_transport mansession_get_transport(const struct mansession *s) { - return s->tcptls_session->parent->tls_cfg ? AST_SECURITY_EVENT_TRANSPORT_TLS : - AST_SECURITY_EVENT_TRANSPORT_TCP; + return s->tcptls_session->parent->tls_cfg ? AST_TRANSPORT_TLS : + AST_TRANSPORT_TCP; } static void report_invalid_user(const struct mansession *s, const char *username) diff --git a/main/named_acl.c b/main/named_acl.c index afcd0692f..092aa94a6 100644 --- a/main/named_acl.c +++ b/main/named_acl.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/paths.h" #include "asterisk/stasis.h" #include "asterisk/json.h" +#include "asterisk/security_events.h" #define NACL_CONFIG "acl.conf" #define ACL_FAMILY "acls" @@ -356,16 +357,11 @@ struct ast_ha *ast_named_acl_find(const char *name, int *is_realtime, int *is_un return ha; } -/*! \brief Topic for ACLs */ -static struct stasis_topic *acl_topic; - /*! \brief Message type for named ACL changes */ STASIS_MESSAGE_TYPE_DEFN(ast_named_acl_change_type); static void acl_stasis_shutdown(void) { - ao2_cleanup(acl_topic); - acl_topic = NULL; STASIS_MESSAGE_TYPE_CLEANUP(ast_named_acl_change_type); } @@ -376,22 +372,16 @@ static void acl_stasis_shutdown(void) static void ast_acl_stasis_init(void) { ast_register_atexit(acl_stasis_shutdown); - acl_topic = stasis_topic_create("ast_acl"); STASIS_MESSAGE_TYPE_INIT(ast_named_acl_change_type); } -struct stasis_topic *ast_acl_topic(void) -{ - return acl_topic; -} - /*! * \internal * \brief Sends a stasis message corresponding to a given named ACL that has changed or * that all ACLs have been updated and old copies must be refreshed. Consumers of - * named ACLs should subscribe to the ast_acl_topic and respond to messages of the - * ast_named_acl_change_type stasis message type in order to be able to accomodate - * changes to named ACLs. + * named ACLs should subscribe to the ast_security_topic and respond to messages + * of the ast_named_acl_change_type stasis message type in order to be able to + * accommodate changes to named ACLs. * * \param name Name of the ACL that has changed. May be an empty string (but not NULL) * If name is an empty string, then all ACLs must be refreshed. @@ -423,7 +413,7 @@ static int publish_acl_change(const char *name) goto publish_failure; } - stasis_publish(ast_acl_topic(), msg); + stasis_publish(ast_security_topic(), msg); return 0; diff --git a/main/security_events.c b/main/security_events.c index bdb9b21c8..d42bea64a 100644 --- a/main/security_events.c +++ b/main/security_events.c @@ -37,9 +37,49 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/network.h" #include "asterisk/security_events.h" #include "asterisk/netsock2.h" +#include "asterisk/stasis.h" +#include "asterisk/json.h" +#include "asterisk/astobj2.h" static const size_t TIMESTAMP_STR_LEN = 32; +/*! \brief Security Topic */ +static struct stasis_topic *security_topic; + +struct stasis_topic *ast_security_topic(void) +{ + return security_topic; +} + +/*! \brief Message type for security events */ +STASIS_MESSAGE_TYPE_DEFN(ast_security_event_type); + +int ast_security_stasis_init(void) +{ + security_topic = stasis_topic_create("ast_security"); + if (!security_topic) { + return -1; + } + + if (STASIS_MESSAGE_TYPE_INIT(ast_security_event_type)) { + return -1; + } + + if (ast_register_atexit(ast_security_stasis_cleanup)) { + return -1; + } + + return 0; +} + +void ast_security_stasis_cleanup(void) +{ + STASIS_MESSAGE_TYPE_CLEANUP(ast_security_event_type); + + ao2_cleanup(security_topic); + security_topic = NULL; +} + static const struct { const char *name; uint32_t version; @@ -464,72 +504,17 @@ const struct ast_security_event_ie_type *ast_security_event_get_optional_ies( return sec_events[event_type].optional_ies; } -static void encode_timestamp(struct ast_str **str, const struct timeval *tv) -{ - ast_str_set(str, 0, "%u-%u", - (unsigned int) tv->tv_sec, - (unsigned int) tv->tv_usec); -} - -static struct ast_event *alloc_event(const struct ast_security_event_common *sec) -{ - struct ast_str *str = ast_str_alloca(TIMESTAMP_STR_LEN); - struct timeval tv = ast_tvnow(); - const char *severity_str; - - if (check_event_type(sec->event_type)) { - return NULL; - } - - encode_timestamp(&str, &tv); - - severity_str = S_OR( - ast_security_event_severity_get_name(sec_events[sec->event_type].severity), - "Unknown" - ); - - return ast_event_new(AST_EVENT_SECURITY, - AST_EVENT_IE_SECURITY_EVENT, AST_EVENT_IE_PLTYPE_UINT, sec->event_type, - AST_EVENT_IE_EVENT_VERSION, AST_EVENT_IE_PLTYPE_UINT, sec->version, - AST_EVENT_IE_EVENT_TV, AST_EVENT_IE_PLTYPE_STR, ast_str_buffer(str), - AST_EVENT_IE_SERVICE, AST_EVENT_IE_PLTYPE_STR, sec->service, - AST_EVENT_IE_SEVERITY, AST_EVENT_IE_PLTYPE_STR, severity_str, - AST_EVENT_IE_END); -} - -static int add_timeval_ie(struct ast_event **event, enum ast_event_ie_type ie_type, - const struct timeval *tv) -{ - struct ast_str *str = ast_str_alloca(TIMESTAMP_STR_LEN); - - encode_timestamp(&str, tv); - - return ast_event_append_ie_str(event, ie_type, ast_str_buffer(str)); -} - -static int add_ip_ie(struct ast_event **event, enum ast_event_ie_type ie_type, +static int add_ip_json_object(struct ast_json *json, enum ast_event_ie_type ie_type, const struct ast_security_event_ip_addr *addr) { - struct ast_str *str = ast_str_alloca(64); + struct ast_json *json_ip; - ast_str_set(&str, 0, (ast_sockaddr_is_ipv4(addr->addr) || ast_sockaddr_is_ipv4_mapped(addr->addr)) ? "IPV4/" : "IPV6/"); - - switch (addr->transport) { - case AST_SECURITY_EVENT_TRANSPORT_UDP: - ast_str_append(&str, 0, "UDP/"); - break; - case AST_SECURITY_EVENT_TRANSPORT_TCP: - ast_str_append(&str, 0, "TCP/"); - break; - case AST_SECURITY_EVENT_TRANSPORT_TLS: - ast_str_append(&str, 0, "TLS/"); - break; + json_ip = ast_json_ipaddr(addr->addr, addr->transport); + if (!json_ip) { + return -1; } - ast_str_append(&str, 0, "%s", ast_sockaddr_stringify_addr(addr->addr)); - ast_str_append(&str, 0, "/%s", ast_sockaddr_stringify_port(addr->addr)); - - return ast_event_append_ie_str(event, ie_type, ast_str_buffer(str)); + return ast_json_object_set(json, ast_event_get_ie_type_name(ie_type), json_ip); } enum ie_required { @@ -537,7 +522,7 @@ enum ie_required { REQUIRED }; -static int add_ie(struct ast_event **event, const struct ast_security_event_common *sec, +static int add_json_object(struct ast_json *json, const struct ast_security_event_common *sec, const struct ast_security_event_ie_type *ie_type, enum ie_required req) { int res = 0; @@ -559,6 +544,7 @@ static int add_ie(struct ast_event **event, const struct ast_security_event_comm case AST_EVENT_IE_ATTEMPTED_TRANSPORT: { const char *str; + struct ast_json *json_string; str = *((const char **)(((const char *) sec) + ie_type->offset)); @@ -567,20 +553,36 @@ static int add_ie(struct ast_event **event, const struct ast_security_event_comm "type '%d' not present\n", ie_type->ie_type, sec->event_type); res = -1; + break; } - if (str) { - res = ast_event_append_ie_str(event, ie_type->ie_type, str); + if (!str) { + break; } + json_string = ast_json_string_create(str); + if (!json_string) { + res = -1; + break; + } + + res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string); break; } case AST_EVENT_IE_EVENT_VERSION: case AST_EVENT_IE_USING_PASSWORD: { + struct ast_json *json_string; uint32_t val; val = *((const uint32_t *)(((const char *) sec) + ie_type->offset)); - res = ast_event_append_ie_uint(event, ie_type->ie_type, val); + + json_string = ast_json_stringf("%d", val); + if (!json_string) { + res = -1; + break; + } + + res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string); break; } case AST_EVENT_IE_LOCAL_ADDR: @@ -599,8 +601,9 @@ static int add_ie(struct ast_event **event, const struct ast_security_event_comm } if (addr->addr) { - res = add_ip_ie(event, ie_type->ie_type, addr); + res = add_ip_json_object(json, ie_type->ie_type, addr); } + break; } case AST_EVENT_IE_SESSION_TV: @@ -617,7 +620,12 @@ static int add_ie(struct ast_event **event, const struct ast_security_event_comm } if (tval) { - add_timeval_ie(event, ie_type->ie_type, tval); + struct ast_json *json_tval = ast_json_timeval(*tval, NULL); + if (!json_tval) { + res = -1; + break; + } + res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_tval); } break; @@ -635,20 +643,78 @@ static int add_ie(struct ast_event **event, const struct ast_security_event_comm return res; } +static struct ast_json *alloc_security_event_json_object(const struct ast_security_event_common *sec) +{ + struct timeval tv = ast_tvnow(); + const char *severity_str; + struct ast_json *json_temp; + RAII_VAR(struct ast_json *, json_object, ast_json_object_create(), ast_json_unref); + + if (!json_object) { + return NULL; + } + + /* NOTE: Every time ast_json_object_set is used, json_temp becomes a stale pointer since the reference is taken. + * This is true even if ast_json_object_set fails. + */ + + /* AST_EVENT_IE_SECURITY_EVENT */ + json_temp = ast_json_integer_create(sec->event_type); + if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SECURITY_EVENT), json_temp)) { + return NULL; + } + + /* AST_EVENT_IE_EVENT_VERSION */ + json_temp = ast_json_stringf("%d", sec->version); + if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_VERSION), json_temp)) { + return NULL; + } + + /* AST_EVENT_IE_EVENT_TV */ + json_temp = ast_json_timeval(tv, NULL); + if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_TV), json_temp)) { + return NULL; + } + + /* AST_EVENT_IE_SERVICE */ + json_temp = ast_json_string_create(sec->service); + if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SERVICE), json_temp)) { + return NULL; + } + + /* AST_EVENT_IE_SEVERITY */ + severity_str = S_OR( + ast_security_event_severity_get_name(sec_events[sec->event_type].severity), + "Unknown" + ); + + json_temp = ast_json_string_create(severity_str); + if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SEVERITY), json_temp)) { + return NULL; + } + + return ast_json_ref(json_object); +} + static int handle_security_event(const struct ast_security_event_common *sec) { - struct ast_event *event; + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup); + RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref); + const struct ast_security_event_ie_type *ies; unsigned int i; - if (!(event = alloc_event(sec))) { + json_object = alloc_security_event_json_object(sec); + + if (!json_object) { return -1; } for (ies = ast_security_event_get_required_ies(sec->event_type), i = 0; ies[i].ie_type != AST_EVENT_IE_END; i++) { - if (add_ie(&event, sec, ies + i, REQUIRED)) { + if (add_json_object(json_object, sec, ies + i, REQUIRED)) { goto return_error; } } @@ -656,30 +722,32 @@ static int handle_security_event(const struct ast_security_event_common *sec) for (ies = ast_security_event_get_optional_ies(sec->event_type), i = 0; ies[i].ie_type != AST_EVENT_IE_END; i++) { - if (add_ie(&event, sec, ies + i, NOT_REQUIRED)) { + if (add_json_object(json_object, sec, ies + i, NOT_REQUIRED)) { goto return_error; } } + /* The json blob is ready. Throw it in the payload and send it out over stasis. */ + if (!(json_payload = ast_json_payload_create(json_object))) { + goto return_error; + } + + msg = stasis_message_create(ast_security_event_type(), json_payload); - if (ast_event_queue(event)) { + if (!msg) { goto return_error; } + stasis_publish(ast_security_topic(), msg); + return 0; return_error: - if (event) { - ast_event_destroy(event); - } - return -1; } int ast_security_event_report(const struct ast_security_event_common *sec) { - int res; - if (sec->event_type < 0 || sec->event_type >= AST_SECURITY_EVENT_NUM_TYPES) { ast_log(LOG_ERROR, "Invalid security event type\n"); return -1; @@ -697,9 +765,12 @@ int ast_security_event_report(const struct ast_security_event_common *sec) return -1; } - res = handle_security_event(sec); + if (handle_security_event(sec)) { + ast_log(LOG_ERROR, "Failed to issue security event of type %s.\n", + ast_security_event_get_name(sec->event_type)); + } - return res; + return 0; } |