2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2012, Digium, Inc.
6 * Russell Bryant <russell@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
22 * \brief Security Event Reporting Helpers
24 * \author Russell Bryant <russell@digium.com>
28 <support_level>core</support_level>
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35 #include "asterisk/utils.h"
36 #include "asterisk/strings.h"
37 #include "asterisk/network.h"
38 #include "asterisk/security_events.h"
39 #include "asterisk/netsock2.h"
40 #include "asterisk/stasis.h"
41 #include "asterisk/json.h"
42 #include "asterisk/astobj2.h"
44 static const size_t TIMESTAMP_STR_LEN = 32;
45 static const size_t SECURITY_EVENT_BUF_INIT_LEN = 256;
47 /*! \brief Security Topic */
48 static struct stasis_topic *security_topic;
50 struct stasis_topic *ast_security_topic(void)
52 return security_topic;
55 static int append_event_str_single(struct ast_str **str, struct ast_json *json,
56 const enum ast_event_ie_type ie_type)
58 const char *ie_type_key = ast_event_get_ie_type_name(ie_type);
59 struct ast_json *json_string = ast_json_object_get(json, ie_type_key);
61 ast_assert(json_string != NULL);
63 if (ast_str_append(str, 0, "%s: %s\r\n", ie_type_key, ast_json_string_get(json_string)) == -1) {
70 static int append_event_str_from_json(struct ast_str **str, struct ast_json *json,
71 const struct ast_security_event_ie_type *ies)
75 for (i = 0; ies[i].ie_type != AST_EVENT_IE_END; i++) {
76 if (append_event_str_single(str, json, ies[i].ie_type)) {
84 static struct ast_manager_event_blob *security_event_to_ami_blob(struct ast_json *json)
86 RAII_VAR(struct ast_str *, str, NULL, ast_free);
87 struct ast_json *event_type_json;
88 enum ast_security_event_type event_type;
90 event_type_json = ast_json_object_get(json, "SecurityEvent");
91 event_type = ast_json_integer_get(event_type_json);
93 ast_assert(event_type >= 0 && event_type < AST_SECURITY_EVENT_NUM_TYPES);
95 if (!(str = ast_str_create(SECURITY_EVENT_BUF_INIT_LEN))) {
99 if (append_event_str_from_json(&str, json,
100 ast_security_event_get_required_ies(event_type))) {
101 ast_log(LOG_ERROR, "Failed to issue a security event to AMI.\n");
105 return ast_manager_event_blob_create(EVENT_FLAG_SECURITY,
106 ast_security_event_get_name(event_type),
108 ast_str_buffer(str));
111 static struct ast_manager_event_blob *security_event_to_ami(struct stasis_message *message)
113 struct ast_json_payload *payload = stasis_message_data(message);
115 if (stasis_message_type(message) != ast_security_event_type()) {
123 return security_event_to_ami_blob(payload->json);
126 /*! \brief Message type for security events */
127 STASIS_MESSAGE_TYPE_DEFN(ast_security_event_type,
128 .to_ami = security_event_to_ami,
131 static void security_stasis_cleanup(void)
133 ao2_cleanup(security_topic);
134 security_topic = NULL;
136 STASIS_MESSAGE_TYPE_CLEANUP(ast_security_event_type);
139 int ast_security_stasis_init(void)
141 ast_register_cleanup(security_stasis_cleanup);
143 security_topic = stasis_topic_create("ast_security");
144 if (!security_topic) {
148 if (STASIS_MESSAGE_TYPE_INIT(ast_security_event_type)) {
156 static const struct {
159 enum ast_security_event_severity severity;
160 #define MAX_SECURITY_IES 12
161 struct ast_security_event_ie_type required_ies[MAX_SECURITY_IES];
162 struct ast_security_event_ie_type optional_ies[MAX_SECURITY_IES];
163 #undef MAX_SECURITY_IES
164 } sec_events[AST_SECURITY_EVENT_NUM_TYPES] = {
166 #define SEC_EVT_FIELD(e, field) (offsetof(struct ast_security_event_##e, field))
168 [AST_SECURITY_EVENT_FAILED_ACL] = {
170 .version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
171 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
173 { AST_EVENT_IE_EVENT_TV, 0 },
174 { AST_EVENT_IE_SEVERITY, 0 },
175 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
176 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
177 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
178 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
179 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
180 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
181 { AST_EVENT_IE_END, 0 }
184 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
185 { AST_EVENT_IE_ACL_NAME, SEC_EVT_FIELD(failed_acl, acl_name) },
186 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
187 { AST_EVENT_IE_END, 0 }
191 [AST_SECURITY_EVENT_INVAL_ACCT_ID] = {
192 .name = "InvalidAccountID",
193 .version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
194 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
196 { AST_EVENT_IE_EVENT_TV, 0 },
197 { AST_EVENT_IE_SEVERITY, 0 },
198 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
199 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
200 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
201 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
202 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
203 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
204 { AST_EVENT_IE_END, 0 }
207 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
208 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
209 { AST_EVENT_IE_END, 0 }
213 [AST_SECURITY_EVENT_SESSION_LIMIT] = {
214 .name = "SessionLimit",
215 .version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
216 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
218 { AST_EVENT_IE_EVENT_TV, 0 },
219 { AST_EVENT_IE_SEVERITY, 0 },
220 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
221 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
222 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
223 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
224 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
225 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
226 { AST_EVENT_IE_END, 0 }
229 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
230 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
231 { AST_EVENT_IE_END, 0 }
235 [AST_SECURITY_EVENT_MEM_LIMIT] = {
236 .name = "MemoryLimit",
237 .version = AST_SECURITY_EVENT_MEM_LIMIT_VERSION,
238 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
240 { AST_EVENT_IE_EVENT_TV, 0 },
241 { AST_EVENT_IE_SEVERITY, 0 },
242 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
243 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
244 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
245 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
246 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
247 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
248 { AST_EVENT_IE_END, 0 }
251 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
252 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
253 { AST_EVENT_IE_END, 0 }
257 [AST_SECURITY_EVENT_LOAD_AVG] = {
258 .name = "LoadAverageLimit",
259 .version = AST_SECURITY_EVENT_LOAD_AVG_VERSION,
260 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
262 { AST_EVENT_IE_EVENT_TV, 0 },
263 { AST_EVENT_IE_SEVERITY, 0 },
264 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
265 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
266 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
267 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
268 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
269 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
270 { AST_EVENT_IE_END, 0 }
273 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
274 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
275 { AST_EVENT_IE_END, 0 }
279 [AST_SECURITY_EVENT_REQ_NO_SUPPORT] = {
280 .name = "RequestNotSupported",
281 .version = AST_SECURITY_EVENT_REQ_NO_SUPPORT_VERSION,
282 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
284 { AST_EVENT_IE_EVENT_TV, 0 },
285 { AST_EVENT_IE_SEVERITY, 0 },
286 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
287 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
288 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
289 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
290 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
291 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
292 { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_no_support, request_type) },
293 { AST_EVENT_IE_END, 0 }
296 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
297 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
298 { AST_EVENT_IE_END, 0 }
302 [AST_SECURITY_EVENT_REQ_NOT_ALLOWED] = {
303 .name = "RequestNotAllowed",
304 .version = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION,
305 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
307 { AST_EVENT_IE_EVENT_TV, 0 },
308 { AST_EVENT_IE_SEVERITY, 0 },
309 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
310 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
311 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
312 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
313 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
314 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
315 { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_not_allowed, request_type) },
316 { AST_EVENT_IE_END, 0 }
319 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
320 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
321 { AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_not_allowed, request_params) },
322 { AST_EVENT_IE_END, 0 }
326 [AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED] = {
327 .name = "AuthMethodNotAllowed",
328 .version = AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED_VERSION,
329 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
331 { AST_EVENT_IE_EVENT_TV, 0 },
332 { AST_EVENT_IE_SEVERITY, 0 },
333 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
334 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
335 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
336 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
337 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
338 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
339 { AST_EVENT_IE_AUTH_METHOD, SEC_EVT_FIELD(auth_method_not_allowed, auth_method) },
340 { AST_EVENT_IE_END, 0 }
343 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
344 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
345 { AST_EVENT_IE_END, 0 }
349 [AST_SECURITY_EVENT_REQ_BAD_FORMAT] = {
350 .name = "RequestBadFormat",
351 .version = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION,
352 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
354 { AST_EVENT_IE_EVENT_TV, 0 },
355 { AST_EVENT_IE_SEVERITY, 0 },
356 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
357 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
358 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
359 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
360 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
361 { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_bad_format, request_type) },
362 { AST_EVENT_IE_END, 0 }
365 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
366 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
367 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
368 { AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_bad_format, request_params) },
369 { AST_EVENT_IE_END, 0 }
373 [AST_SECURITY_EVENT_SUCCESSFUL_AUTH] = {
374 .name = "SuccessfulAuth",
375 .version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
376 .severity = AST_SECURITY_EVENT_SEVERITY_INFO,
378 { AST_EVENT_IE_EVENT_TV, 0 },
379 { AST_EVENT_IE_SEVERITY, 0 },
380 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
381 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
382 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
383 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
384 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
385 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
386 { AST_EVENT_IE_USING_PASSWORD, SEC_EVT_FIELD(successful_auth, using_password) },
387 { AST_EVENT_IE_END, 0 }
390 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
391 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
392 { AST_EVENT_IE_END, 0 }
396 [AST_SECURITY_EVENT_UNEXPECTED_ADDR] = {
397 .name = "UnexpectedAddress",
398 .version = AST_SECURITY_EVENT_UNEXPECTED_ADDR_VERSION,
399 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
401 { AST_EVENT_IE_EVENT_TV, 0 },
402 { AST_EVENT_IE_SEVERITY, 0 },
403 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
404 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
405 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
406 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
407 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
408 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
409 { AST_EVENT_IE_EXPECTED_ADDR, SEC_EVT_FIELD(unexpected_addr, expected_addr) },
410 { AST_EVENT_IE_END, 0 }
413 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
414 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
415 { AST_EVENT_IE_END, 0 }
419 [AST_SECURITY_EVENT_CHAL_RESP_FAILED] = {
420 .name = "ChallengeResponseFailed",
421 .version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
422 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
424 { AST_EVENT_IE_EVENT_TV, 0 },
425 { AST_EVENT_IE_SEVERITY, 0 },
426 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
427 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
428 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
429 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
430 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
431 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
432 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(chal_resp_failed, challenge) },
433 { AST_EVENT_IE_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, response) },
434 { AST_EVENT_IE_EXPECTED_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, expected_response) },
435 { AST_EVENT_IE_END, 0 }
438 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
439 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
440 { AST_EVENT_IE_END, 0 }
444 [AST_SECURITY_EVENT_INVAL_PASSWORD] = {
445 .name = "InvalidPassword",
446 .version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
447 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
449 { AST_EVENT_IE_EVENT_TV, 0 },
450 { AST_EVENT_IE_SEVERITY, 0 },
451 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
452 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
453 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
454 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
455 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
456 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
457 { AST_EVENT_IE_END, 0 }
460 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
461 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
462 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(inval_password, challenge) },
463 { AST_EVENT_IE_RECEIVED_CHALLENGE, SEC_EVT_FIELD(inval_password, received_challenge) },
464 { AST_EVENT_IE_RECEIVED_HASH, SEC_EVT_FIELD(inval_password, received_hash) },
465 { AST_EVENT_IE_END, 0 }
469 [AST_SECURITY_EVENT_CHAL_SENT] = {
470 .name = "ChallengeSent",
471 .version = AST_SECURITY_EVENT_CHAL_SENT_VERSION,
472 .severity = AST_SECURITY_EVENT_SEVERITY_INFO,
474 { AST_EVENT_IE_EVENT_TV, 0 },
475 { AST_EVENT_IE_SEVERITY, 0 },
476 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
477 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
478 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
479 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
480 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
481 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
482 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(chal_sent, challenge) },
483 { AST_EVENT_IE_END, 0 }
486 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
487 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
488 { AST_EVENT_IE_END, 0 }
492 [AST_SECURITY_EVENT_INVAL_TRANSPORT] = {
493 .name = "InvalidTransport",
494 .version = AST_SECURITY_EVENT_INVAL_TRANSPORT_VERSION,
495 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
497 { AST_EVENT_IE_EVENT_TV, 0 },
498 { AST_EVENT_IE_SEVERITY, 0 },
499 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
500 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
501 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
502 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
503 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
504 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
505 { AST_EVENT_IE_ATTEMPTED_TRANSPORT, SEC_EVT_FIELD(inval_transport, transport) },
506 { AST_EVENT_IE_END, 0 }
509 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
510 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
511 { AST_EVENT_IE_END, 0 }
519 static const struct {
520 enum ast_security_event_severity severity;
523 { AST_SECURITY_EVENT_SEVERITY_INFO, "Informational" },
524 { AST_SECURITY_EVENT_SEVERITY_ERROR, "Error" },
527 const char *ast_security_event_severity_get_name(
528 const enum ast_security_event_severity severity)
532 for (i = 0; i < ARRAY_LEN(severities); i++) {
533 if (severities[i].severity == severity) {
534 return severities[i].str;
541 static int check_event_type(const enum ast_security_event_type event_type)
543 if (event_type < 0 || event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
544 ast_log(LOG_ERROR, "Invalid security event type %u\n", event_type);
551 const char *ast_security_event_get_name(const enum ast_security_event_type event_type)
553 if (check_event_type(event_type)) {
557 return sec_events[event_type].name;
560 const struct ast_security_event_ie_type *ast_security_event_get_required_ies(
561 const enum ast_security_event_type event_type)
563 if (check_event_type(event_type)) {
567 return sec_events[event_type].required_ies;
570 const struct ast_security_event_ie_type *ast_security_event_get_optional_ies(
571 const enum ast_security_event_type event_type)
573 if (check_event_type(event_type)) {
577 return sec_events[event_type].optional_ies;
580 static int add_ip_json_object(struct ast_json *json, enum ast_event_ie_type ie_type,
581 const struct ast_security_event_ip_addr *addr)
583 struct ast_json *json_ip;
585 json_ip = ast_json_ipaddr(addr->addr, addr->transport);
590 return ast_json_object_set(json, ast_event_get_ie_type_name(ie_type), json_ip);
598 static int add_json_object(struct ast_json *json, const struct ast_security_event_common *sec,
599 const struct ast_security_event_ie_type *ie_type, enum ie_required req)
603 switch (ie_type->ie_type) {
604 case AST_EVENT_IE_SERVICE:
605 case AST_EVENT_IE_ACCOUNT_ID:
606 case AST_EVENT_IE_SESSION_ID:
607 case AST_EVENT_IE_MODULE:
608 case AST_EVENT_IE_ACL_NAME:
609 case AST_EVENT_IE_REQUEST_TYPE:
610 case AST_EVENT_IE_REQUEST_PARAMS:
611 case AST_EVENT_IE_AUTH_METHOD:
612 case AST_EVENT_IE_CHALLENGE:
613 case AST_EVENT_IE_RESPONSE:
614 case AST_EVENT_IE_EXPECTED_RESPONSE:
615 case AST_EVENT_IE_RECEIVED_CHALLENGE:
616 case AST_EVENT_IE_RECEIVED_HASH:
617 case AST_EVENT_IE_ATTEMPTED_TRANSPORT:
620 struct ast_json *json_string;
622 str = *((const char **)(((const char *) sec) + ie_type->offset));
625 ast_log(LOG_WARNING, "Required IE '%d' for security event "
626 "type '%d' not present\n", ie_type->ie_type,
636 json_string = ast_json_string_create(str);
642 res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string);
645 case AST_EVENT_IE_EVENT_VERSION:
646 case AST_EVENT_IE_USING_PASSWORD:
648 struct ast_json *json_string;
650 val = *((const uint32_t *)(((const char *) sec) + ie_type->offset));
652 json_string = ast_json_stringf("%d", val);
658 res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string);
661 case AST_EVENT_IE_LOCAL_ADDR:
662 case AST_EVENT_IE_REMOTE_ADDR:
663 case AST_EVENT_IE_EXPECTED_ADDR:
665 const struct ast_security_event_ip_addr *addr;
667 addr = (const struct ast_security_event_ip_addr *)(((const char *) sec) + ie_type->offset);
669 if (req && !addr->addr) {
670 ast_log(LOG_WARNING, "Required IE '%d' for security event "
671 "type '%d' not present\n", ie_type->ie_type,
677 res = add_ip_json_object(json, ie_type->ie_type, addr);
682 case AST_EVENT_IE_SESSION_TV:
684 const struct timeval *tval;
686 tval = *((const struct timeval **)(((const char *) sec) + ie_type->offset));
689 ast_log(LOG_WARNING, "Required IE '%d' for security event "
690 "type '%d' not present\n", ie_type->ie_type,
696 struct ast_json *json_tval = ast_json_timeval(*tval, NULL);
701 res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_tval);
706 case AST_EVENT_IE_EVENT_TV:
707 case AST_EVENT_IE_SEVERITY:
708 /* Added automatically, nothing to do here. */
711 ast_log(LOG_WARNING, "Unhandled IE type '%d', this security event "
712 "will be missing data.\n", ie_type->ie_type);
719 static struct ast_json *alloc_security_event_json_object(const struct ast_security_event_common *sec)
721 struct timeval tv = ast_tvnow();
722 const char *severity_str;
723 struct ast_json *json_temp;
724 RAII_VAR(struct ast_json *, json_object, ast_json_object_create(), ast_json_unref);
730 /* NOTE: Every time ast_json_object_set is used, json_temp becomes a stale pointer since the reference is taken.
731 * This is true even if ast_json_object_set fails.
734 json_temp = ast_json_integer_create(sec->event_type);
735 if (!json_temp || ast_json_object_set(json_object, "SecurityEvent", json_temp)) {
739 json_temp = ast_json_stringf("%d", sec->version);
740 if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_VERSION), json_temp)) {
744 /* AST_EVENT_IE_EVENT_TV */
745 json_temp = ast_json_timeval(tv, NULL);
746 if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_TV), json_temp)) {
750 /* AST_EVENT_IE_SERVICE */
751 json_temp = ast_json_string_create(sec->service);
752 if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SERVICE), json_temp)) {
756 /* AST_EVENT_IE_SEVERITY */
758 ast_security_event_severity_get_name(sec_events[sec->event_type].severity),
762 json_temp = ast_json_string_create(severity_str);
763 if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SEVERITY), json_temp)) {
767 return ast_json_ref(json_object);
770 static int handle_security_event(const struct ast_security_event_common *sec)
772 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
773 RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup);
774 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
776 const struct ast_security_event_ie_type *ies;
779 json_object = alloc_security_event_json_object(sec);
785 for (ies = ast_security_event_get_required_ies(sec->event_type), i = 0;
786 ies[i].ie_type != AST_EVENT_IE_END;
788 if (add_json_object(json_object, sec, ies + i, REQUIRED)) {
793 for (ies = ast_security_event_get_optional_ies(sec->event_type), i = 0;
794 ies[i].ie_type != AST_EVENT_IE_END;
796 if (add_json_object(json_object, sec, ies + i, NOT_REQUIRED)) {
801 /* The json blob is ready. Throw it in the payload and send it out over stasis. */
802 if (!(json_payload = ast_json_payload_create(json_object))) {
806 msg = stasis_message_create(ast_security_event_type(), json_payload);
812 stasis_publish(ast_security_topic(), msg);
820 int ast_security_event_report(const struct ast_security_event_common *sec)
822 if (sec->event_type < 0 || sec->event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
823 ast_log(LOG_ERROR, "Invalid security event type\n");
827 if (!sec_events[sec->event_type].name) {
828 ast_log(LOG_WARNING, "Security event type %u not handled\n",
833 if (sec->version != sec_events[sec->event_type].version) {
834 ast_log(LOG_WARNING, "Security event %u version mismatch\n",
839 if (handle_security_event(sec)) {
840 ast_log(LOG_ERROR, "Failed to issue security event of type %s.\n",
841 ast_security_event_get_name(sec->event_type));