summaryrefslogtreecommitdiff
path: root/main/security_events.c
diff options
context:
space:
mode:
authorRussell Bryant <russell@russellbryant.com>2009-07-11 19:15:03 +0000
committerRussell Bryant <russell@russellbryant.com>2009-07-11 19:15:03 +0000
commit4cf8a968fd37e4ab72052bf5549072abda81e1be (patch)
tree083f8af40de7b9c624b37fcc20d48f4c7da8ce94 /main/security_events.c
parentc01286976af9db85c775ab7ec003c33664c5e95f (diff)
Add an API for reporting security events, and a security event logging module.
This commit introduces the security events API. This API is to be used by Asterisk components to report events that have security implications. A simple example is when a connection is made but fails authentication. These events can be used by external tools manipulate firewall rules or something similar after detecting unusual activity based on security events. Inside of Asterisk, the events go through the ast_event API. This means that they have a binary encoding, and it is easy to write code to subscribe to these events and do something with them. One module is provided that is a subscriber to these events - res_security_log. This module turns security events into a parseable text format and sends them to the "security" logger level. Using logger.conf, these log entries may be sent to a file, or to syslog. One service, AMI, has been fully updated for reporting security events. AMI was chosen as it was a fairly straight forward service to convert. The next target will be chan_sip. That will be more complicated and will be done as its own project as the next phase of security events work. For more information on the security events framework, see the documentation generated from doc/tex/. "make asterisk.pdf" Review: https://reviewboard.asterisk.org/r/273/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@206021 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/security_events.c')
-rw-r--r--main/security_events.c647
1 files changed, 647 insertions, 0 deletions
diff --git a/main/security_events.c b/main/security_events.c
new file mode 100644
index 000000000..d1e2ac0cc
--- /dev/null
+++ b/main/security_events.c
@@ -0,0 +1,647 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2009, Digium, Inc.
+ *
+ * Russell Bryant <russell@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ *
+ * \brief Security Event Reporting Helpers
+ *
+ * \author Russell Bryant <russell@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/utils.h"
+#include "asterisk/strings.h"
+#include "asterisk/network.h"
+#include "asterisk/security_events.h"
+
+static const size_t TIMESTAMP_STR_LEN = 32;
+
+static const struct {
+ const char *name;
+ uint32_t version;
+ enum ast_security_event_severity severity;
+#define MAX_SECURITY_IES 12
+ struct ast_security_event_ie_type required_ies[MAX_SECURITY_IES];
+ struct ast_security_event_ie_type optional_ies[MAX_SECURITY_IES];
+#undef MAX_SECURITY_IES
+} sec_events[AST_SECURITY_EVENT_NUM_TYPES] = {
+
+#define SEC_EVT_FIELD(e, field) (offsetof(struct ast_security_event_##e, field))
+
+[AST_SECURITY_EVENT_FAILED_ACL] = {
+ .name = "FailedACL",
+ .version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_ACL_NAME, SEC_EVT_FIELD(failed_acl, acl_name) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_INVAL_ACCT_ID] = {
+ .name = "InvalidAccountID",
+ .version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_SESSION_LIMIT] = {
+ .name = "SessionLimit",
+ .version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_MEM_LIMIT] = {
+ .name = "MemoryLimit",
+ .version = AST_SECURITY_EVENT_MEM_LIMIT_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_LOAD_AVG] = {
+ .name = "LoadAverageLimit",
+ .version = AST_SECURITY_EVENT_LOAD_AVG_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_REQ_NO_SUPPORT] = {
+ .name = "RequestNotSupported",
+ .version = AST_SECURITY_EVENT_REQ_NO_SUPPORT_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_no_support, request_type) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_REQ_NOT_ALLOWED] = {
+ .name = "RequestNotAllowed",
+ .version = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_not_allowed, request_type) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_not_allowed, request_params) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED] = {
+ .name = "AuthMethodNotAllowed",
+ .version = AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_AUTH_METHOD, SEC_EVT_FIELD(auth_method_not_allowed, auth_method) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_REQ_BAD_FORMAT] = {
+ .name = "RequestBadFormat",
+ .version = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_bad_format, request_type) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_bad_format, request_params) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_SUCCESSFUL_AUTH] = {
+ .name = "SuccessfulAuth",
+ .version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_INFO,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_UNEXPECTED_ADDR] = {
+ .name = "UnexpectedAddress",
+ .version = AST_SECURITY_EVENT_UNEXPECTED_ADDR_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_EXPECTED_ADDR, SEC_EVT_FIELD(unexpected_addr, expected_addr) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_CHAL_RESP_FAILED] = {
+ .name = "ChallengeResponseFailed",
+ .version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(chal_resp_failed, challenge) },
+ { AST_EVENT_IE_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, response) },
+ { AST_EVENT_IE_EXPECTED_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, expected_response) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+[AST_SECURITY_EVENT_INVAL_PASSWORD] = {
+ .name = "InvalidPassword",
+ .version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
+ .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
+ .required_ies = {
+ { AST_EVENT_IE_EVENT_TV, 0 },
+ { AST_EVENT_IE_SEVERITY, 0 },
+ { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
+ { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
+ { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
+ { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
+ { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
+ { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
+ { AST_EVENT_IE_END, 0 }
+ },
+ .optional_ies = {
+ { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
+ { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
+ { AST_EVENT_IE_END, 0 }
+ },
+},
+
+#undef SEC_EVT_FIELD
+
+};
+
+static const struct {
+ enum ast_security_event_severity severity;
+ const char *str;
+} severities[] = {
+ { AST_SECURITY_EVENT_SEVERITY_INFO, "Informational" },
+ { AST_SECURITY_EVENT_SEVERITY_ERROR, "Error" },
+};
+
+const char *ast_security_event_severity_get_name(
+ const enum ast_security_event_severity severity)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_LEN(severities); i++) {
+ if (severities[i].severity == severity) {
+ return severities[i].str;
+ }
+ }
+
+ return NULL;
+}
+
+static int check_event_type(const enum ast_security_event_type event_type)
+{
+ if (event_type < 0 || event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
+ ast_log(LOG_ERROR, "Invalid security event type %u\n", event_type);
+ return -1;
+ }
+
+ return 0;
+}
+
+const char *ast_security_event_get_name(const enum ast_security_event_type event_type)
+{
+ if (check_event_type(event_type)) {
+ return NULL;
+ }
+
+ return sec_events[event_type].name;
+}
+
+const struct ast_security_event_ie_type *ast_security_event_get_required_ies(
+ const enum ast_security_event_type event_type)
+{
+ if (check_event_type(event_type)) {
+ return NULL;
+ }
+
+ return sec_events[event_type].required_ies;
+}
+
+const struct ast_security_event_ie_type *ast_security_event_get_optional_ies(
+ const enum ast_security_event_type event_type)
+{
+ if (check_event_type(event_type)) {
+ return NULL;
+ }
+
+ 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, str->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_ipv4_ie(struct ast_event **event, enum ast_event_ie_type ie_type,
+ const struct ast_security_event_ipv4_addr *addr)
+{
+ struct ast_str *str = ast_str_alloca(64);
+
+ ast_str_set(&str, 0, "IPV4/");
+
+ 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;
+ }
+
+ ast_str_append(&str, 0, "%s/%hu",
+ ast_inet_ntoa(addr->sin->sin_addr),
+ ntohs(addr->sin->sin_port));
+
+ return ast_event_append_ie_str(event, ie_type, ast_str_buffer(str));
+}
+
+enum ie_required {
+ NOT_REQUIRED,
+ REQUIRED
+};
+
+static int add_ie(struct ast_event **event, const struct ast_security_event_common *sec,
+ const struct ast_security_event_ie_type *ie_type, enum ie_required req)
+{
+ int res = 0;
+
+ switch (ie_type->ie_type) {
+ case AST_EVENT_IE_SERVICE:
+ case AST_EVENT_IE_ACCOUNT_ID:
+ case AST_EVENT_IE_SESSION_ID:
+ case AST_EVENT_IE_MODULE:
+ case AST_EVENT_IE_ACL_NAME:
+ case AST_EVENT_IE_REQUEST_TYPE:
+ case AST_EVENT_IE_REQUEST_PARAMS:
+ case AST_EVENT_IE_AUTH_METHOD:
+ case AST_EVENT_IE_CHALLENGE:
+ case AST_EVENT_IE_RESPONSE:
+ case AST_EVENT_IE_EXPECTED_RESPONSE:
+ {
+ const char *str;
+
+ str = *((const char **)(((const char *) sec) + ie_type->offset));
+
+ if (req && !str) {
+ ast_log(LOG_WARNING, "Required IE '%d' for security event "
+ "type '%d' not present\n", ie_type->ie_type,
+ sec->event_type);
+ res = -1;
+ }
+
+ if (str) {
+ res = ast_event_append_ie_str(event, ie_type->ie_type, str);
+ }
+
+ break;
+ }
+ case AST_EVENT_IE_EVENT_VERSION:
+ {
+ 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);
+ break;
+ }
+ case AST_EVENT_IE_LOCAL_ADDR:
+ case AST_EVENT_IE_REMOTE_ADDR:
+ case AST_EVENT_IE_EXPECTED_ADDR:
+ {
+ const struct ast_security_event_ipv4_addr *addr;
+
+ addr = (const struct ast_security_event_ipv4_addr *)(((const char *) sec) + ie_type->offset);
+
+ if (req && !addr->sin) {
+ ast_log(LOG_WARNING, "Required IE '%d' for security event "
+ "type '%d' not present\n", ie_type->ie_type,
+ sec->event_type);
+ res = -1;
+ }
+
+ if (addr->sin) {
+ res = add_ipv4_ie(event, ie_type->ie_type, addr);
+ }
+ break;
+ }
+ case AST_EVENT_IE_SESSION_TV:
+ {
+ const struct timeval *tval;
+
+ tval = *((const struct timeval **)(((const char *) sec) + ie_type->offset));
+
+ if (req && !tval) {
+ ast_log(LOG_WARNING, "Required IE '%d' for security event "
+ "type '%d' not present\n", ie_type->ie_type,
+ sec->event_type);
+ res = -1;
+ }
+
+ if (tval) {
+ add_timeval_ie(event, ie_type->ie_type, tval);
+ }
+
+ break;
+ }
+ case AST_EVENT_IE_EVENT_TV:
+ case AST_EVENT_IE_SEVERITY:
+ /* Added automatically, nothing to do here. */
+ break;
+ default:
+ ast_log(LOG_WARNING, "Unhandled IE type '%d', this security event "
+ "will be missing data.\n", ie_type->ie_type);
+ break;
+ }
+
+ return res;
+}
+
+static int handle_security_event(const struct ast_security_event_common *sec)
+{
+ struct ast_event *event;
+ const struct ast_security_event_ie_type *ies;
+ unsigned int i;
+
+ if (!(event = alloc_event(sec))) {
+ 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)) {
+ goto return_error;
+ }
+ }
+
+ 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)) {
+ goto return_error;
+ }
+ }
+
+
+ if (ast_event_queue(event)) {
+ goto return_error;
+ }
+
+ 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;
+ }
+
+ if (!sec_events[sec->event_type].name) {
+ ast_log(LOG_WARNING, "Security event type %u not handled\n",
+ sec->event_type);
+ return -1;
+ }
+
+ if (sec->version != sec_events[sec->event_type].version) {
+ ast_log(LOG_WARNING, "Security event %u version mismatch\n",
+ sec->event_type);
+ return -1;
+ }
+
+ res = handle_security_event(sec);
+
+ return res;
+}
+
+