summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/event.c156
-rw-r--r--main/manager.c267
-rw-r--r--main/security_events.c647
3 files changed, 992 insertions, 78 deletions
diff --git a/main/event.c b/main/event.c
index 6a70a6741..44c65714d 100644
--- a/main/event.c
+++ b/main/event.c
@@ -183,63 +183,77 @@ static struct {
};
/*!
- * The index of each entry _must_ match the event type number!
+ * \brief Event Names
*/
-static struct event_name {
- enum ast_event_type type;
- const char *name;
-} event_names[] = {
- { 0, "" },
- { AST_EVENT_CUSTOM, "Custom" },
- { AST_EVENT_MWI, "MWI" },
- { AST_EVENT_SUB, "Subscription" },
- { AST_EVENT_UNSUB, "Unsubscription" },
- { AST_EVENT_DEVICE_STATE, "DeviceState" },
- { AST_EVENT_DEVICE_STATE_CHANGE, "DeviceStateChange" },
- { AST_EVENT_CEL, "CEL" },
+static const char * const event_names[AST_EVENT_TOTAL] = {
+ [AST_EVENT_CUSTOM] = "Custom",
+ [AST_EVENT_MWI] = "MWI",
+ [AST_EVENT_SUB] = "Subscription",
+ [AST_EVENT_UNSUB] = "Unsubscription",
+ [AST_EVENT_DEVICE_STATE] = "DeviceState",
+ [AST_EVENT_DEVICE_STATE_CHANGE] = "DeviceStateChange",
+ [AST_EVENT_CEL] = "CEL",
+ [AST_EVENT_SECURITY] = "Security",
};
/*!
- * The index of each entry _must_ match the event ie number!
+ * \brief IE payload types and names
*/
-static struct ie_map {
- enum ast_event_ie_type ie_type;
+static const struct ie_map {
enum ast_event_ie_pltype ie_pltype;
const char *name;
-} ie_maps[] = {
- { 0, 0, "" },
- { AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
- { AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
- { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, "Mailbox" },
- { AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
- { AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, "EventType" },
- { AST_EVENT_IE_EXISTS, AST_EVENT_IE_PLTYPE_UINT, "Exists" },
- { AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "Device" },
- { AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, "State" },
- { AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, "Context" },
- { AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, "EntityID" },
- { AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, "CELEventType" },
- { AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, "CELEventTime" },
- { AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, "CELEventTimeUSec" },
- { AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_UINT, "CELUserEventName" },
- { AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, "CELCIDName" },
- { AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, "CELCIDNum" },
- { AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, "CELExten" },
- { AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, "CELContext" },
- { AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, "CELChanName" },
- { AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, "CELAppName" },
- { AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, "CELAppData" },
- { AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_STR, "CELAMAFlags" },
- { AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_UINT, "CELAcctCode" },
- { AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, "CELUniqueID" },
- { AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, "CELUserField" },
- { AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR, "CELCIDani" },
- { AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR, "CELCIDrdnis" },
- { AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR, "CELCIDdnid" },
- { AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, "CELPeer" },
- { AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, "CELLinkedID" },
- { AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, "CELPeerAcct" },
- { AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, "CELExtra" },
+} ie_maps[AST_EVENT_IE_TOTAL] = {
+ [AST_EVENT_IE_NEWMSGS] = { AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
+ [AST_EVENT_IE_OLDMSGS] = { AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
+ [AST_EVENT_IE_MAILBOX] = { AST_EVENT_IE_PLTYPE_STR, "Mailbox" },
+ [AST_EVENT_IE_UNIQUEID] = { AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
+ [AST_EVENT_IE_EVENTTYPE] = { AST_EVENT_IE_PLTYPE_UINT, "EventType" },
+ [AST_EVENT_IE_EXISTS] = { AST_EVENT_IE_PLTYPE_UINT, "Exists" },
+ [AST_EVENT_IE_DEVICE] = { AST_EVENT_IE_PLTYPE_STR, "Device" },
+ [AST_EVENT_IE_STATE] = { AST_EVENT_IE_PLTYPE_UINT, "State" },
+ [AST_EVENT_IE_CONTEXT] = { AST_EVENT_IE_PLTYPE_STR, "Context" },
+ [AST_EVENT_IE_EID] = { AST_EVENT_IE_PLTYPE_RAW, "EntityID" },
+ [AST_EVENT_IE_CEL_EVENT_TYPE] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventType" },
+ [AST_EVENT_IE_CEL_EVENT_TIME] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventTime" },
+ [AST_EVENT_IE_CEL_EVENT_TIME_USEC] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventTimeUSec" },
+ [AST_EVENT_IE_CEL_USEREVENT_NAME] = { AST_EVENT_IE_PLTYPE_UINT, "CELUserEventName" },
+ [AST_EVENT_IE_CEL_CIDNAME] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDName" },
+ [AST_EVENT_IE_CEL_CIDNUM] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDNum" },
+ [AST_EVENT_IE_CEL_EXTEN] = { AST_EVENT_IE_PLTYPE_STR, "CELExten" },
+ [AST_EVENT_IE_CEL_CONTEXT] = { AST_EVENT_IE_PLTYPE_STR, "CELContext" },
+ [AST_EVENT_IE_CEL_CHANNAME] = { AST_EVENT_IE_PLTYPE_STR, "CELChanName" },
+ [AST_EVENT_IE_CEL_APPNAME] = { AST_EVENT_IE_PLTYPE_STR, "CELAppName" },
+ [AST_EVENT_IE_CEL_APPDATA] = { AST_EVENT_IE_PLTYPE_STR, "CELAppData" },
+ [AST_EVENT_IE_CEL_AMAFLAGS] = { AST_EVENT_IE_PLTYPE_STR, "CELAMAFlags" },
+ [AST_EVENT_IE_CEL_ACCTCODE] = { AST_EVENT_IE_PLTYPE_UINT, "CELAcctCode" },
+ [AST_EVENT_IE_CEL_UNIQUEID] = { AST_EVENT_IE_PLTYPE_STR, "CELUniqueID" },
+ [AST_EVENT_IE_CEL_USERFIELD] = { AST_EVENT_IE_PLTYPE_STR, "CELUserField" },
+ [AST_EVENT_IE_CEL_CIDANI] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDani" },
+ [AST_EVENT_IE_CEL_CIDRDNIS] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDrdnis" },
+ [AST_EVENT_IE_CEL_CIDDNID] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDdnid" },
+ [AST_EVENT_IE_CEL_PEER] = { AST_EVENT_IE_PLTYPE_STR, "CELPeer" },
+ [AST_EVENT_IE_CEL_LINKEDID] = { AST_EVENT_IE_PLTYPE_STR, "CELLinkedID" },
+ [AST_EVENT_IE_CEL_PEERACCT] = { AST_EVENT_IE_PLTYPE_STR, "CELPeerAcct" },
+ [AST_EVENT_IE_CEL_EXTRA] = { AST_EVENT_IE_PLTYPE_STR, "CELExtra" },
+ [AST_EVENT_IE_SECURITY_EVENT] = { AST_EVENT_IE_PLTYPE_STR, "SecurityEvent" },
+ [AST_EVENT_IE_EVENT_VERSION] = { AST_EVENT_IE_PLTYPE_UINT, "EventVersion" },
+ [AST_EVENT_IE_SERVICE] = { AST_EVENT_IE_PLTYPE_STR, "Service" },
+ [AST_EVENT_IE_MODULE] = { AST_EVENT_IE_PLTYPE_STR, "Module" },
+ [AST_EVENT_IE_ACCOUNT_ID] = { AST_EVENT_IE_PLTYPE_STR, "AccountID" },
+ [AST_EVENT_IE_SESSION_ID] = { AST_EVENT_IE_PLTYPE_STR, "SessionID" },
+ [AST_EVENT_IE_SESSION_TV] = { AST_EVENT_IE_PLTYPE_STR, "SessionTV" },
+ [AST_EVENT_IE_ACL_NAME] = { AST_EVENT_IE_PLTYPE_STR, "ACLName" },
+ [AST_EVENT_IE_LOCAL_ADDR] = { AST_EVENT_IE_PLTYPE_STR, "LocalAddress" },
+ [AST_EVENT_IE_REMOTE_ADDR] = { AST_EVENT_IE_PLTYPE_STR, "RemoteAddress" },
+ [AST_EVENT_IE_EVENT_TV] = { AST_EVENT_IE_PLTYPE_STR, "EventTV" },
+ [AST_EVENT_IE_REQUEST_TYPE] = { AST_EVENT_IE_PLTYPE_STR, "RequestType" },
+ [AST_EVENT_IE_REQUEST_PARAMS] = { AST_EVENT_IE_PLTYPE_STR, "RequestParams" },
+ [AST_EVENT_IE_AUTH_METHOD] = { AST_EVENT_IE_PLTYPE_STR, "AuthMethod" },
+ [AST_EVENT_IE_SEVERITY] = { AST_EVENT_IE_PLTYPE_STR, "Severity" },
+ [AST_EVENT_IE_EXPECTED_ADDR] = { AST_EVENT_IE_PLTYPE_STR, "ExpectedAddress" },
+ [AST_EVENT_IE_CHALLENGE] = { AST_EVENT_IE_PLTYPE_STR, "Challenge" },
+ [AST_EVENT_IE_RESPONSE] = { AST_EVENT_IE_PLTYPE_STR, "Response" },
+ [AST_EVENT_IE_EXPECTED_RESPONSE] = { AST_EVENT_IE_PLTYPE_STR, "ExpectedResponse" },
};
const char *ast_event_get_type_name(const struct ast_event *event)
@@ -248,12 +262,12 @@ const char *ast_event_get_type_name(const struct ast_event *event)
type = ast_event_get_type(event);
- if (type >= AST_EVENT_TOTAL || type < 0) {
+ if (type < 0 || type >= ARRAY_LEN(event_names)) {
ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type);
return "";
}
- return event_names[type].name;
+ return event_names[type];
}
int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type)
@@ -261,10 +275,11 @@ int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type
int i;
for (i = 0; i < ARRAY_LEN(event_names); i++) {
- if (strcasecmp(event_names[i].name, str))
+ if (strcasecmp(event_names[i], str)) {
continue;
+ }
- *event_type = event_names[i].type;
+ *event_type = i;
return 0;
}
@@ -273,31 +288,21 @@ int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type
const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
{
- if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
+ if (ie_type <= 0 || ie_type >= ARRAY_LEN(ie_maps)) {
ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
return "";
}
- if (ie_maps[ie_type].ie_type != ie_type) {
- ast_log(LOG_ERROR, "The ie type passed in does not match the ie type defined in the ie table.\n");
- return "";
- }
-
return ie_maps[ie_type].name;
}
enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
{
- if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
+ if (ie_type <= 0 || ie_type >= ARRAY_LEN(ie_maps)) {
ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
return AST_EVENT_IE_PLTYPE_UNKNOWN;
}
- if (ie_maps[ie_type].ie_type != ie_type) {
- ast_log(LOG_ERROR, "The ie type passed in does not match the ie type defined in the ie table.\n");
- return AST_EVENT_IE_PLTYPE_UNKNOWN;
- }
-
return ie_maps[ie_type].ie_pltype;
}
@@ -306,10 +311,11 @@ int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type)
int i;
for (i = 0; i < ARRAY_LEN(ie_maps); i++) {
- if (strcasecmp(ie_maps[i].name, str))
+ if (strcasecmp(ie_maps[i].name, str)) {
continue;
+ }
- *ie_type = ie_maps[i].ie_type;
+ *ie_type = i;
return 0;
}
@@ -661,7 +667,7 @@ int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
{
struct ast_event_ie_val *ie_val;
- if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
+ if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
return -1;
}
@@ -683,11 +689,13 @@ int ast_event_sub_append_ie_bitflags(struct ast_event_sub *sub,
{
struct ast_event_ie_val *ie_val;
- if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
+ if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
return -1;
+ }
- if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
+ if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
return -1;
+ }
ie_val->ie_type = ie_type;
ie_val->payload.uint = flags;
@@ -703,7 +711,7 @@ int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
{
struct ast_event_ie_val *ie_val;
- if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
+ if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
return -1;
}
@@ -724,7 +732,7 @@ int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
{
struct ast_event_ie_val *ie_val;
- if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
+ if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
return -1;
}
@@ -752,7 +760,7 @@ int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
{
struct ast_event_ie_val *ie_val;
- if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
+ if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
return -1;
}
diff --git a/main/manager.c b/main/manager.c
index 0670da36d..c7e4ce4c6 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -74,6 +74,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/term.h"
#include "asterisk/astobj2.h"
#include "asterisk/features.h"
+#include "asterisk/security_events.h"
/*** DOCUMENTATION
<manager name="Ping" language="en_US">
@@ -807,6 +808,7 @@ struct mansession_session {
pthread_t waiting_thread; /*!< Sleeping thread using this descriptor */
uint32_t managerid; /*!< Unique manager identifier, 0 for AMI sessions */
time_t sessionstart; /*!< Session start time */
+ struct timeval sessionstart_tv; /*!< Session start time */
time_t sessiontimeout; /*!< Session timeout if HTTP */
char username[80]; /*!< Logged in username */
char challenge[10]; /*!< Authentication challenge */
@@ -834,6 +836,7 @@ struct mansession_session {
*/
struct mansession {
struct mansession_session *session;
+ struct ast_tcptls_session_instance *tcptls_session;
FILE *f;
int fd;
ast_mutex_t lock;
@@ -1735,6 +1738,241 @@ 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)
+{
+ return s->tcptls_session->parent->tls_cfg ? AST_SECURITY_EVENT_TRANSPORT_TLS :
+ AST_SECURITY_EVENT_TRANSPORT_TCP;
+}
+
+static struct sockaddr_in *mansession_encode_sin_local(const struct mansession *s,
+ struct sockaddr_in *sin_local)
+{
+ *sin_local = s->tcptls_session->parent->local_address;
+
+ return sin_local;
+}
+
+static void report_invalid_user(const struct mansession *s, const char *username)
+{
+ struct sockaddr_in sin_local;
+ char session_id[32];
+ struct ast_security_event_inval_acct_id inval_acct_id = {
+ .common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID,
+ .common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
+ .common.service = "AMI",
+ .common.account_id = username,
+ .common.session_tv = &s->session->sessionstart_tv,
+ .common.local_addr = {
+ .sin = mansession_encode_sin_local(s, &sin_local),
+ .transport = mansession_get_transport(s),
+ },
+ .common.remote_addr = {
+ .sin = &s->session->sin,
+ .transport = mansession_get_transport(s),
+ },
+ .common.session_id = session_id,
+ };
+
+ snprintf(session_id, sizeof(session_id), "%p", s);
+
+ ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
+}
+
+static void report_failed_acl(const struct mansession *s, const char *username)
+{
+ struct sockaddr_in sin_local;
+ char session_id[32];
+ struct ast_security_event_failed_acl failed_acl_event = {
+ .common.event_type = AST_SECURITY_EVENT_FAILED_ACL,
+ .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
+ .common.service = "AMI",
+ .common.account_id = username,
+ .common.session_tv = &s->session->sessionstart_tv,
+ .common.local_addr = {
+ .sin = mansession_encode_sin_local(s, &sin_local),
+ .transport = mansession_get_transport(s),
+ },
+ .common.remote_addr = {
+ .sin = &s->session->sin,
+ .transport = mansession_get_transport(s),
+ },
+ .common.session_id = session_id,
+ };
+
+ snprintf(session_id, sizeof(session_id), "%p", s->session);
+
+ ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
+}
+
+static void report_inval_password(const struct mansession *s, const char *username)
+{
+ struct sockaddr_in sin_local;
+ char session_id[32];
+ struct ast_security_event_inval_password inval_password = {
+ .common.event_type = AST_SECURITY_EVENT_INVAL_PASSWORD,
+ .common.version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
+ .common.service = "AMI",
+ .common.account_id = username,
+ .common.session_tv = &s->session->sessionstart_tv,
+ .common.local_addr = {
+ .sin = mansession_encode_sin_local(s, &sin_local),
+ .transport = mansession_get_transport(s),
+ },
+ .common.remote_addr = {
+ .sin = &s->session->sin,
+ .transport = mansession_get_transport(s),
+ },
+ .common.session_id = session_id,
+ };
+
+ snprintf(session_id, sizeof(session_id), "%p", s->session);
+
+ ast_security_event_report(AST_SEC_EVT(&inval_password));
+}
+
+static void report_auth_success(const struct mansession *s)
+{
+ struct sockaddr_in sin_local;
+ char session_id[32];
+ struct ast_security_event_successful_auth successful_auth = {
+ .common.event_type = AST_SECURITY_EVENT_SUCCESSFUL_AUTH,
+ .common.version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
+ .common.service = "AMI",
+ .common.account_id = s->session->username,
+ .common.session_tv = &s->session->sessionstart_tv,
+ .common.local_addr = {
+ .sin = mansession_encode_sin_local(s, &sin_local),
+ .transport = mansession_get_transport(s),
+ },
+ .common.remote_addr = {
+ .sin = &s->session->sin,
+ .transport = mansession_get_transport(s),
+ },
+ .common.session_id = session_id,
+ };
+
+ snprintf(session_id, sizeof(session_id), "%p", s->session);
+
+ ast_security_event_report(AST_SEC_EVT(&successful_auth));
+}
+
+static void report_req_not_allowed(const struct mansession *s, const char *action)
+{
+ struct sockaddr_in sin_local;
+ char session_id[32];
+ char request_type[64];
+ struct ast_security_event_req_not_allowed req_not_allowed = {
+ .common.event_type = AST_SECURITY_EVENT_REQ_NOT_ALLOWED,
+ .common.version = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION,
+ .common.service = "AMI",
+ .common.account_id = s->session->username,
+ .common.session_tv = &s->session->sessionstart_tv,
+ .common.local_addr = {
+ .sin = mansession_encode_sin_local(s, &sin_local),
+ .transport = mansession_get_transport(s),
+ },
+ .common.remote_addr = {
+ .sin = &s->session->sin,
+ .transport = mansession_get_transport(s),
+ },
+ .common.session_id = session_id,
+
+ .request_type = request_type,
+ };
+
+ snprintf(session_id, sizeof(session_id), "%p", s->session);
+ snprintf(request_type, sizeof(request_type), "Action: %s", action);
+
+ ast_security_event_report(AST_SEC_EVT(&req_not_allowed));
+}
+
+static void report_req_bad_format(const struct mansession *s, const char *action)
+{
+ struct sockaddr_in sin_local;
+ char session_id[32];
+ char request_type[64];
+ struct ast_security_event_req_bad_format req_bad_format = {
+ .common.event_type = AST_SECURITY_EVENT_REQ_BAD_FORMAT,
+ .common.version = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION,
+ .common.service = "AMI",
+ .common.account_id = s->session->username,
+ .common.session_tv = &s->session->sessionstart_tv,
+ .common.local_addr = {
+ .sin = mansession_encode_sin_local(s, &sin_local),
+ .transport = mansession_get_transport(s),
+ },
+ .common.remote_addr = {
+ .sin = &s->session->sin,
+ .transport = mansession_get_transport(s),
+ },
+ .common.session_id = session_id,
+
+ .request_type = request_type,
+ };
+
+ snprintf(session_id, sizeof(session_id), "%p", s->session);
+ snprintf(request_type, sizeof(request_type), "Action: %s", action);
+
+ ast_security_event_report(AST_SEC_EVT(&req_bad_format));
+}
+
+static void report_failed_challenge_response(const struct mansession *s,
+ const char *response, const char *expected_response)
+{
+ struct sockaddr_in sin_local;
+ char session_id[32];
+ struct ast_security_event_chal_resp_failed chal_resp_failed = {
+ .common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED,
+ .common.version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
+ .common.service = "AMI",
+ .common.account_id = s->session->username,
+ .common.session_tv = &s->session->sessionstart_tv,
+ .common.local_addr = {
+ .sin = mansession_encode_sin_local(s, &sin_local),
+ .transport = mansession_get_transport(s),
+ },
+ .common.remote_addr = {
+ .sin = &s->session->sin,
+ .transport = mansession_get_transport(s),
+ },
+ .common.session_id = session_id,
+
+ .challenge = s->session->challenge,
+ .response = response,
+ .expected_response = expected_response,
+ };
+
+ snprintf(session_id, sizeof(session_id), "%p", s->session);
+
+ ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
+}
+
+static void report_session_limit(const struct mansession *s)
+{
+ struct sockaddr_in sin_local;
+ char session_id[32];
+ struct ast_security_event_session_limit session_limit = {
+ .common.event_type = AST_SECURITY_EVENT_SESSION_LIMIT,
+ .common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
+ .common.service = "AMI",
+ .common.account_id = s->session->username,
+ .common.session_tv = &s->session->sessionstart_tv,
+ .common.local_addr = {
+ .sin = mansession_encode_sin_local(s, &sin_local),
+ .transport = mansession_get_transport(s),
+ },
+ .common.remote_addr = {
+ .sin = &s->session->sin,
+ .transport = mansession_get_transport(s),
+ },
+ .common.session_id = session_id,
+ };
+
+ snprintf(session_id, sizeof(session_id), "%p", s->session);
+
+ ast_security_event_report(AST_SEC_EVT(&session_limit));
+}
+
/*
* Here we start with action_ handlers for AMI actions,
* and the internal functions used by them.
@@ -1757,8 +1995,10 @@ static int authenticate(struct mansession *s, const struct message *m)
AST_RWLIST_WRLOCK(&users);
if (!(user = get_manager_by_name_locked(username))) {
+ report_invalid_user(s, username);
ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
} else if (user->ha && !ast_apply_ha(user->ha, &(s->session->sin))) {
+ report_failed_acl(s, username);
ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
} else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
const char *key = astman_get_header(m, "Key");
@@ -1777,13 +2017,19 @@ static int authenticate(struct mansession *s, const struct message *m)
len += sprintf(md5key + len, "%2.2x", digest[x]);
if (!strcmp(md5key, key)) {
error = 0;
+ } else {
+ report_failed_challenge_response(s, key, md5key);
}
} else {
ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
S_OR(s->session->challenge, ""));
}
- } else if (password && user->secret && !strcmp(password, user->secret)) {
- error = 0;
+ } else if (user->secret) {
+ if (!strcmp(password, user->secret)) {
+ error = 0;
+ } else {
+ report_inval_password(s, username);
+ }
}
if (error) {
@@ -1799,8 +2045,11 @@ static int authenticate(struct mansession *s, const struct message *m)
s->session->writeperm = user->writeperm;
s->session->writetimeout = user->writetimeout;
s->session->sessionstart = time(NULL);
+ s->session->sessionstart_tv = ast_tvnow();
set_eventmask(s, astman_get_header(m, "Events"));
+ report_auth_success(s);
+
AST_RWLIST_UNLOCK(&users);
return 0;
}
@@ -3550,6 +3799,7 @@ static int process_message(struct mansession *s, const struct message *m)
ast_copy_string(action, __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY), sizeof(action));
if (ast_strlen_zero(action)) {
+ report_req_bad_format(s, "NONE");
mansession_lock(s);
astman_send_error(s, m, "Missing action in request");
mansession_unlock(s);
@@ -3557,6 +3807,9 @@ static int process_message(struct mansession *s, const struct message *m)
}
if (!s->session->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
+ if (!s->session->authenticated) {
+ report_req_not_allowed(s, action);
+ }
mansession_lock(s);
astman_send_error(s, m, "Permission denied");
mansession_unlock(s);
@@ -3566,6 +3819,7 @@ static int process_message(struct mansession *s, const struct message *m)
if (!allowmultiplelogin && !s->session->authenticated && user &&
(!strcasecmp(action, "Login") || !strcasecmp(action, "Challenge"))) {
if (check_manager_session_inuse(user)) {
+ report_session_limit(s);
sleep(1);
mansession_lock(s);
astman_send_error(s, m, "Login Already In Use");
@@ -3583,7 +3837,7 @@ static int process_message(struct mansession *s, const struct message *m)
call_func = tmp->func;
} else {
astman_send_error(s, m, "Permission denied");
- tmp = NULL;
+ report_req_not_allowed(s, action);
}
break;
}
@@ -3595,6 +3849,9 @@ static int process_message(struct mansession *s, const struct message *m)
ret = call_func(s, m);
} else {
char buf[512];
+ if (!tmp) {
+ report_req_bad_format(s, action);
+ }
snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
mansession_lock(s);
astman_send_error(s, m, buf);
@@ -3733,7 +3990,9 @@ static void *session_do(void *data)
{
struct ast_tcptls_session_instance *ser = data;
struct mansession_session *session = build_mansession(ser->remote_address);
- struct mansession s = { NULL, };
+ struct mansession s = {
+ .tcptls_session = data,
+ };
int flags;
int res;
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;
+}
+
+