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/event.h"
39 #include "asterisk/security_events.h"
40 #include "asterisk/netsock2.h"
41 #include "asterisk/stasis.h"
42 #include "asterisk/json.h"
43 #include "asterisk/astobj2.h"
45 static const size_t TIMESTAMP_STR_LEN = 32;
46 static const size_t SECURITY_EVENT_BUF_INIT_LEN = 256;
48 /*! \brief Security Topic */
49 static struct stasis_topic *security_topic;
51 struct stasis_topic *ast_security_topic(void)
53 return security_topic;
56 static int append_event_str_single(struct ast_str **str, struct ast_json *json,
57 const enum ast_event_ie_type ie_type)
59 const char *ie_type_key = ast_event_get_ie_type_name(ie_type);
60 struct ast_json *json_string = ast_json_object_get(json, ie_type_key);
62 ast_assert(json_string != NULL);
64 if (ast_str_append(str, 0, "%s: %s\r\n", ie_type_key, ast_json_string_get(json_string)) == -1) {
71 static int append_event_str_from_json(struct ast_str **str, struct ast_json *json,
72 const struct ast_security_event_ie_type *ies)
76 for (i = 0; ies[i].ie_type != AST_EVENT_IE_END; i++) {
77 if (append_event_str_single(str, json, ies[i].ie_type)) {
85 static struct ast_manager_event_blob *security_event_to_ami_blob(struct ast_json *json)
87 RAII_VAR(struct ast_str *, str, NULL, ast_free);
88 struct ast_json *event_type_json;
89 enum ast_security_event_type event_type;
91 event_type_json = ast_json_object_get(json, "SecurityEvent");
92 event_type = ast_json_integer_get(event_type_json);
94 ast_assert(event_type >= 0 && event_type < AST_SECURITY_EVENT_NUM_TYPES);
96 if (!(str = ast_str_create(SECURITY_EVENT_BUF_INIT_LEN))) {
100 if (append_event_str_from_json(&str, json,
101 ast_security_event_get_required_ies(event_type))) {
102 ast_log(LOG_ERROR, "Failed to issue a security event to AMI.\n");
106 return ast_manager_event_blob_create(EVENT_FLAG_SECURITY,
107 ast_security_event_get_name(event_type),
109 ast_str_buffer(str));
112 static struct ast_manager_event_blob *security_event_to_ami(struct stasis_message *message)
114 struct ast_json_payload *payload = stasis_message_data(message);
116 if (stasis_message_type(message) != ast_security_event_type()) {
124 return security_event_to_ami_blob(payload->json);
127 /*! \brief Message type for security events */
128 STASIS_MESSAGE_TYPE_DEFN(ast_security_event_type,
129 .to_ami = security_event_to_ami,
132 static void security_stasis_cleanup(void)
134 ao2_cleanup(security_topic);
135 security_topic = NULL;
137 STASIS_MESSAGE_TYPE_CLEANUP(ast_security_event_type);
140 int ast_security_stasis_init(void)
142 ast_register_cleanup(security_stasis_cleanup);
144 security_topic = stasis_topic_create("ast_security");
145 if (!security_topic) {
149 if (STASIS_MESSAGE_TYPE_INIT(ast_security_event_type)) {
157 static const struct {
160 enum ast_security_event_severity severity;
161 #define MAX_SECURITY_IES 12
162 struct ast_security_event_ie_type required_ies[MAX_SECURITY_IES];
163 struct ast_security_event_ie_type optional_ies[MAX_SECURITY_IES];
164 #undef MAX_SECURITY_IES
165 } sec_events[AST_SECURITY_EVENT_NUM_TYPES] = {
167 #define SEC_EVT_FIELD(e, field) (offsetof(struct ast_security_event_##e, field))
169 [AST_SECURITY_EVENT_FAILED_ACL] = {
171 .version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
172 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
174 { AST_EVENT_IE_EVENT_TV, 0 },
175 { AST_EVENT_IE_SEVERITY, 0 },
176 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
177 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
178 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
179 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
180 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
181 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
182 { AST_EVENT_IE_END, 0 }
185 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
186 { AST_EVENT_IE_ACL_NAME, SEC_EVT_FIELD(failed_acl, acl_name) },
187 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
188 { AST_EVENT_IE_END, 0 }
192 [AST_SECURITY_EVENT_INVAL_ACCT_ID] = {
193 .name = "InvalidAccountID",
194 .version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
195 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
197 { AST_EVENT_IE_EVENT_TV, 0 },
198 { AST_EVENT_IE_SEVERITY, 0 },
199 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
200 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
201 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
202 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
203 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
204 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
205 { AST_EVENT_IE_END, 0 }
208 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
209 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
210 { AST_EVENT_IE_END, 0 }
214 [AST_SECURITY_EVENT_SESSION_LIMIT] = {
215 .name = "SessionLimit",
216 .version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
217 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
219 { AST_EVENT_IE_EVENT_TV, 0 },
220 { AST_EVENT_IE_SEVERITY, 0 },
221 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
222 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
223 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
224 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
225 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
226 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
227 { AST_EVENT_IE_END, 0 }
230 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
231 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
232 { AST_EVENT_IE_END, 0 }
236 [AST_SECURITY_EVENT_MEM_LIMIT] = {
237 .name = "MemoryLimit",
238 .version = AST_SECURITY_EVENT_MEM_LIMIT_VERSION,
239 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
241 { AST_EVENT_IE_EVENT_TV, 0 },
242 { AST_EVENT_IE_SEVERITY, 0 },
243 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
244 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
245 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
246 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
247 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
248 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
249 { AST_EVENT_IE_END, 0 }
252 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
253 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
254 { AST_EVENT_IE_END, 0 }
258 [AST_SECURITY_EVENT_LOAD_AVG] = {
259 .name = "LoadAverageLimit",
260 .version = AST_SECURITY_EVENT_LOAD_AVG_VERSION,
261 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
263 { AST_EVENT_IE_EVENT_TV, 0 },
264 { AST_EVENT_IE_SEVERITY, 0 },
265 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
266 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
267 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
268 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
269 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
270 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
271 { AST_EVENT_IE_END, 0 }
274 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
275 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
276 { AST_EVENT_IE_END, 0 }
280 [AST_SECURITY_EVENT_REQ_NO_SUPPORT] = {
281 .name = "RequestNotSupported",
282 .version = AST_SECURITY_EVENT_REQ_NO_SUPPORT_VERSION,
283 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
285 { AST_EVENT_IE_EVENT_TV, 0 },
286 { AST_EVENT_IE_SEVERITY, 0 },
287 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
288 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
289 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
290 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
291 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
292 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
293 { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_no_support, request_type) },
294 { AST_EVENT_IE_END, 0 }
297 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
298 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
299 { AST_EVENT_IE_END, 0 }
303 [AST_SECURITY_EVENT_REQ_NOT_ALLOWED] = {
304 .name = "RequestNotAllowed",
305 .version = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION,
306 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
308 { AST_EVENT_IE_EVENT_TV, 0 },
309 { AST_EVENT_IE_SEVERITY, 0 },
310 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
311 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
312 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
313 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
314 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
315 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
316 { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_not_allowed, request_type) },
317 { AST_EVENT_IE_END, 0 }
320 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
321 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
322 { AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_not_allowed, request_params) },
323 { AST_EVENT_IE_END, 0 }
327 [AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED] = {
328 .name = "AuthMethodNotAllowed",
329 .version = AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED_VERSION,
330 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
332 { AST_EVENT_IE_EVENT_TV, 0 },
333 { AST_EVENT_IE_SEVERITY, 0 },
334 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
335 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
336 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
337 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
338 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
339 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
340 { AST_EVENT_IE_AUTH_METHOD, SEC_EVT_FIELD(auth_method_not_allowed, auth_method) },
341 { AST_EVENT_IE_END, 0 }
344 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
345 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
346 { AST_EVENT_IE_END, 0 }
350 [AST_SECURITY_EVENT_REQ_BAD_FORMAT] = {
351 .name = "RequestBadFormat",
352 .version = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION,
353 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
355 { AST_EVENT_IE_EVENT_TV, 0 },
356 { AST_EVENT_IE_SEVERITY, 0 },
357 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
358 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
359 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
360 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
361 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
362 { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_bad_format, request_type) },
363 { AST_EVENT_IE_END, 0 }
366 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
367 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
368 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
369 { AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_bad_format, request_params) },
370 { AST_EVENT_IE_END, 0 }
374 [AST_SECURITY_EVENT_SUCCESSFUL_AUTH] = {
375 .name = "SuccessfulAuth",
376 .version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
377 .severity = AST_SECURITY_EVENT_SEVERITY_INFO,
379 { AST_EVENT_IE_EVENT_TV, 0 },
380 { AST_EVENT_IE_SEVERITY, 0 },
381 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
382 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
383 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
384 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
385 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
386 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
387 { AST_EVENT_IE_USING_PASSWORD, SEC_EVT_FIELD(successful_auth, using_password) },
388 { AST_EVENT_IE_END, 0 }
391 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
392 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
393 { AST_EVENT_IE_END, 0 }
397 [AST_SECURITY_EVENT_UNEXPECTED_ADDR] = {
398 .name = "UnexpectedAddress",
399 .version = AST_SECURITY_EVENT_UNEXPECTED_ADDR_VERSION,
400 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
402 { AST_EVENT_IE_EVENT_TV, 0 },
403 { AST_EVENT_IE_SEVERITY, 0 },
404 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
405 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
406 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
407 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
408 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
409 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
410 { AST_EVENT_IE_EXPECTED_ADDR, SEC_EVT_FIELD(unexpected_addr, expected_addr) },
411 { AST_EVENT_IE_END, 0 }
414 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
415 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
416 { AST_EVENT_IE_END, 0 }
420 [AST_SECURITY_EVENT_CHAL_RESP_FAILED] = {
421 .name = "ChallengeResponseFailed",
422 .version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
423 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
425 { AST_EVENT_IE_EVENT_TV, 0 },
426 { AST_EVENT_IE_SEVERITY, 0 },
427 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
428 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
429 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
430 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
431 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
432 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
433 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(chal_resp_failed, challenge) },
434 { AST_EVENT_IE_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, response) },
435 { AST_EVENT_IE_EXPECTED_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, expected_response) },
436 { AST_EVENT_IE_END, 0 }
439 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
440 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
441 { AST_EVENT_IE_END, 0 }
445 [AST_SECURITY_EVENT_INVAL_PASSWORD] = {
446 .name = "InvalidPassword",
447 .version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
448 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
450 { AST_EVENT_IE_EVENT_TV, 0 },
451 { AST_EVENT_IE_SEVERITY, 0 },
452 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
453 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
454 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
455 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
456 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
457 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
458 { AST_EVENT_IE_END, 0 }
461 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
462 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
463 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(inval_password, challenge) },
464 { AST_EVENT_IE_RECEIVED_CHALLENGE, SEC_EVT_FIELD(inval_password, received_challenge) },
465 { AST_EVENT_IE_RECEIVED_HASH, SEC_EVT_FIELD(inval_password, received_hash) },
466 { AST_EVENT_IE_END, 0 }
470 [AST_SECURITY_EVENT_CHAL_SENT] = {
471 .name = "ChallengeSent",
472 .version = AST_SECURITY_EVENT_CHAL_SENT_VERSION,
473 .severity = AST_SECURITY_EVENT_SEVERITY_INFO,
475 { AST_EVENT_IE_EVENT_TV, 0 },
476 { AST_EVENT_IE_SEVERITY, 0 },
477 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
478 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
479 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
480 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
481 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
482 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
483 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(chal_sent, challenge) },
484 { AST_EVENT_IE_END, 0 }
487 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
488 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
489 { AST_EVENT_IE_END, 0 }
493 [AST_SECURITY_EVENT_INVAL_TRANSPORT] = {
494 .name = "InvalidTransport",
495 .version = AST_SECURITY_EVENT_INVAL_TRANSPORT_VERSION,
496 .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
498 { AST_EVENT_IE_EVENT_TV, 0 },
499 { AST_EVENT_IE_SEVERITY, 0 },
500 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
501 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
502 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
503 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
504 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
505 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
506 { AST_EVENT_IE_ATTEMPTED_TRANSPORT, SEC_EVT_FIELD(inval_transport, transport) },
507 { AST_EVENT_IE_END, 0 }
510 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
511 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
512 { AST_EVENT_IE_END, 0 }
520 static const struct {
521 enum ast_security_event_severity severity;
524 { AST_SECURITY_EVENT_SEVERITY_INFO, "Informational" },
525 { AST_SECURITY_EVENT_SEVERITY_ERROR, "Error" },
528 const char *ast_security_event_severity_get_name(
529 const enum ast_security_event_severity severity)
533 for (i = 0; i < ARRAY_LEN(severities); i++) {
534 if (severities[i].severity == severity) {
535 return severities[i].str;
542 static int check_event_type(const enum ast_security_event_type event_type)
544 if (event_type < 0 || event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
545 ast_log(LOG_ERROR, "Invalid security event type %u\n", event_type);
552 const char *ast_security_event_get_name(const enum ast_security_event_type event_type)
554 if (check_event_type(event_type)) {
558 return sec_events[event_type].name;
561 const struct ast_security_event_ie_type *ast_security_event_get_required_ies(
562 const enum ast_security_event_type event_type)
564 if (check_event_type(event_type)) {
568 return sec_events[event_type].required_ies;
571 const struct ast_security_event_ie_type *ast_security_event_get_optional_ies(
572 const enum ast_security_event_type event_type)
574 if (check_event_type(event_type)) {
578 return sec_events[event_type].optional_ies;
581 static int add_ip_json_object(struct ast_json *json, enum ast_event_ie_type ie_type,
582 const struct ast_security_event_ip_addr *addr)
584 struct ast_json *json_ip;
586 json_ip = ast_json_ipaddr(addr->addr, addr->transport);
591 return ast_json_object_set(json, ast_event_get_ie_type_name(ie_type), json_ip);
599 static int add_json_object(struct ast_json *json, const struct ast_security_event_common *sec,
600 const struct ast_security_event_ie_type *ie_type, enum ie_required req)
604 switch (ie_type->ie_type) {
605 case AST_EVENT_IE_SERVICE:
606 case AST_EVENT_IE_ACCOUNT_ID:
607 case AST_EVENT_IE_SESSION_ID:
608 case AST_EVENT_IE_MODULE:
609 case AST_EVENT_IE_ACL_NAME:
610 case AST_EVENT_IE_REQUEST_TYPE:
611 case AST_EVENT_IE_REQUEST_PARAMS:
612 case AST_EVENT_IE_AUTH_METHOD:
613 case AST_EVENT_IE_CHALLENGE:
614 case AST_EVENT_IE_RESPONSE:
615 case AST_EVENT_IE_EXPECTED_RESPONSE:
616 case AST_EVENT_IE_RECEIVED_CHALLENGE:
617 case AST_EVENT_IE_RECEIVED_HASH:
618 case AST_EVENT_IE_ATTEMPTED_TRANSPORT:
621 struct ast_json *json_string;
623 str = *((const char **)(((const char *) sec) + ie_type->offset));
626 ast_log(LOG_WARNING, "Required IE '%d' (%s) for security event "
627 "type '%d' (%s) not present\n", ie_type->ie_type,
628 ast_event_get_ie_type_name(ie_type->ie_type),
629 sec->event_type, ast_security_event_get_name(sec->event_type));
638 json_string = ast_json_string_create(str);
644 res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string);
647 case AST_EVENT_IE_EVENT_VERSION:
648 case AST_EVENT_IE_USING_PASSWORD:
650 struct ast_json *json_string;
652 val = *((const uint32_t *)(((const char *) sec) + ie_type->offset));
654 json_string = ast_json_stringf("%d", val);
660 res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string);
663 case AST_EVENT_IE_LOCAL_ADDR:
664 case AST_EVENT_IE_REMOTE_ADDR:
665 case AST_EVENT_IE_EXPECTED_ADDR:
667 const struct ast_security_event_ip_addr *addr;
669 addr = (const struct ast_security_event_ip_addr *)(((const char *) sec) + ie_type->offset);
671 if (req && !addr->addr) {
672 ast_log(LOG_WARNING, "Required IE '%d' (%s) for security event "
673 "type '%d' (%s) not present\n", ie_type->ie_type,
674 ast_event_get_ie_type_name(ie_type->ie_type),
675 sec->event_type, ast_security_event_get_name(sec->event_type));
680 res = add_ip_json_object(json, ie_type->ie_type, addr);
685 case AST_EVENT_IE_SESSION_TV:
687 const struct timeval *tval;
689 tval = *((const struct timeval **)(((const char *) sec) + ie_type->offset));
692 ast_log(LOG_WARNING, "Required IE '%d' (%s) for security event "
693 "type '%d' (%s) not present\n", ie_type->ie_type,
694 ast_event_get_ie_type_name(ie_type->ie_type),
695 sec->event_type, ast_security_event_get_name(sec->event_type));
700 struct ast_json *json_tval = ast_json_timeval(*tval, NULL);
705 res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_tval);
710 case AST_EVENT_IE_EVENT_TV:
711 case AST_EVENT_IE_SEVERITY:
712 /* Added automatically, nothing to do here. */
715 ast_log(LOG_WARNING, "Unhandled IE type '%d' (%s), this security event "
716 "will be missing data.\n", ie_type->ie_type,
717 ast_event_get_ie_type_name(ie_type->ie_type));
724 static struct ast_json *alloc_security_event_json_object(const struct ast_security_event_common *sec)
726 struct timeval tv = ast_tvnow();
727 const char *severity_str;
728 struct ast_json *json_temp;
729 RAII_VAR(struct ast_json *, json_object, ast_json_object_create(), ast_json_unref);
735 /* NOTE: Every time ast_json_object_set is used, json_temp becomes a stale pointer since the reference is taken.
736 * This is true even if ast_json_object_set fails.
739 json_temp = ast_json_integer_create(sec->event_type);
740 if (!json_temp || ast_json_object_set(json_object, "SecurityEvent", json_temp)) {
744 json_temp = ast_json_stringf("%d", sec->version);
745 if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_VERSION), json_temp)) {
749 /* AST_EVENT_IE_EVENT_TV */
750 json_temp = ast_json_timeval(tv, NULL);
751 if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_TV), json_temp)) {
755 /* AST_EVENT_IE_SERVICE */
756 json_temp = ast_json_string_create(sec->service);
757 if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SERVICE), json_temp)) {
761 /* AST_EVENT_IE_SEVERITY */
763 ast_security_event_severity_get_name(sec_events[sec->event_type].severity),
767 json_temp = ast_json_string_create(severity_str);
768 if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SEVERITY), json_temp)) {
772 return ast_json_ref(json_object);
775 static int handle_security_event(const struct ast_security_event_common *sec)
777 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
778 RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup);
779 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
781 const struct ast_security_event_ie_type *ies;
784 json_object = alloc_security_event_json_object(sec);
790 for (ies = ast_security_event_get_required_ies(sec->event_type), i = 0;
791 ies[i].ie_type != AST_EVENT_IE_END;
793 if (add_json_object(json_object, sec, ies + i, REQUIRED)) {
798 for (ies = ast_security_event_get_optional_ies(sec->event_type), i = 0;
799 ies[i].ie_type != AST_EVENT_IE_END;
801 if (add_json_object(json_object, sec, ies + i, NOT_REQUIRED)) {
806 /* The json blob is ready. Throw it in the payload and send it out over stasis. */
807 if (!(json_payload = ast_json_payload_create(json_object))) {
811 msg = stasis_message_create(ast_security_event_type(), json_payload);
817 stasis_publish(ast_security_topic(), msg);
825 int ast_security_event_report(const struct ast_security_event_common *sec)
827 if (sec->event_type < 0 || sec->event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
828 ast_log(LOG_ERROR, "Invalid security event type\n");
832 if (!sec_events[sec->event_type].name) {
833 ast_log(LOG_WARNING, "Security event type %u not handled\n",
838 if (sec->version != sec_events[sec->event_type].version) {
839 ast_log(LOG_WARNING, "Security event %u version mismatch\n",
844 if (handle_security_event(sec)) {
845 ast_log(LOG_ERROR, "Failed to issue security event of type %s.\n",
846 ast_security_event_get_name(sec->event_type));