summaryrefslogtreecommitdiff
path: root/main/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/manager.c')
-rw-r--r--main/manager.c267
1 files changed, 263 insertions, 4 deletions
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;