Avoid unnecessary cleanups during immediate shutdown
[asterisk/asterisk.git] / main / security_events.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Russell Bryant <russell@digium.com>
7  *
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.
13  *
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.
17  */
18
19 /*!
20  * \file
21  *
22  * \brief Security Event Reporting Helpers
23  *
24  * \author Russell Bryant <russell@digium.com>
25  */
26
27 /*** MODULEINFO
28         <support_level>core</support_level>
29  ***/
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
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"
43
44 static const size_t TIMESTAMP_STR_LEN = 32;
45
46 /*! \brief Security Topic */
47 static struct stasis_topic *security_topic;
48
49 struct stasis_topic *ast_security_topic(void)
50 {
51         return security_topic;
52 }
53
54 /*! \brief Message type for security events */
55 STASIS_MESSAGE_TYPE_DEFN(ast_security_event_type);
56
57 static void security_stasis_cleanup(void)
58 {
59         ao2_cleanup(security_topic);
60         security_topic = NULL;
61
62         STASIS_MESSAGE_TYPE_CLEANUP(ast_security_event_type);
63 }
64
65 int ast_security_stasis_init(void)
66 {
67         ast_register_cleanup(security_stasis_cleanup);
68
69         security_topic = stasis_topic_create("ast_security");
70         if (!security_topic) {
71                 return -1;
72         }
73
74         if (STASIS_MESSAGE_TYPE_INIT(ast_security_event_type)) {
75                 return -1;
76         }
77
78
79         return 0;
80 }
81
82 static const struct {
83         const char *name;
84         uint32_t version;
85         enum ast_security_event_severity severity;
86 #define MAX_SECURITY_IES 12
87         struct ast_security_event_ie_type required_ies[MAX_SECURITY_IES];
88         struct ast_security_event_ie_type optional_ies[MAX_SECURITY_IES];
89 #undef MAX_SECURITY_IES
90 } sec_events[AST_SECURITY_EVENT_NUM_TYPES] = {
91
92 #define SEC_EVT_FIELD(e, field) (offsetof(struct ast_security_event_##e, field))
93
94 [AST_SECURITY_EVENT_FAILED_ACL] = {
95         .name     = "FailedACL",
96         .version  = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
97         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
98         .required_ies = {
99                 { AST_EVENT_IE_EVENT_TV, 0 },
100                 { AST_EVENT_IE_SEVERITY, 0 },
101                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
102                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
103                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
104                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
105                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
106                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
107                 { AST_EVENT_IE_END, 0 }
108         },
109         .optional_ies = {
110                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
111                 { AST_EVENT_IE_ACL_NAME, SEC_EVT_FIELD(failed_acl, acl_name) },
112                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
113                 { AST_EVENT_IE_END, 0 }
114         },
115 },
116
117 [AST_SECURITY_EVENT_INVAL_ACCT_ID] = {
118         .name     = "InvalidAccountID",
119         .version  = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
120         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
121         .required_ies = {
122                 { AST_EVENT_IE_EVENT_TV, 0 },
123                 { AST_EVENT_IE_SEVERITY, 0 },
124                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
125                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
126                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
127                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
128                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
129                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
130                 { AST_EVENT_IE_END, 0 }
131         },
132         .optional_ies = {
133                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
134                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
135                 { AST_EVENT_IE_END, 0 }
136         },
137 },
138
139 [AST_SECURITY_EVENT_SESSION_LIMIT] = {
140         .name     = "SessionLimit",
141         .version  = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
142         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
143         .required_ies = {
144                 { AST_EVENT_IE_EVENT_TV, 0 },
145                 { AST_EVENT_IE_SEVERITY, 0 },
146                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
147                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
148                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
149                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
150                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
151                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
152                 { AST_EVENT_IE_END, 0 }
153         },
154         .optional_ies = {
155                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
156                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
157                 { AST_EVENT_IE_END, 0 }
158         },
159 },
160
161 [AST_SECURITY_EVENT_MEM_LIMIT] = {
162         .name     = "MemoryLimit",
163         .version  = AST_SECURITY_EVENT_MEM_LIMIT_VERSION,
164         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
165         .required_ies = {
166                 { AST_EVENT_IE_EVENT_TV, 0 },
167                 { AST_EVENT_IE_SEVERITY, 0 },
168                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
169                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
170                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
171                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
172                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
173                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
174                 { AST_EVENT_IE_END, 0 }
175         },
176         .optional_ies = {
177                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
178                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
179                 { AST_EVENT_IE_END, 0 }
180         },
181 },
182
183 [AST_SECURITY_EVENT_LOAD_AVG] = {
184         .name     = "LoadAverageLimit",
185         .version  = AST_SECURITY_EVENT_LOAD_AVG_VERSION,
186         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
187         .required_ies = {
188                 { AST_EVENT_IE_EVENT_TV, 0 },
189                 { AST_EVENT_IE_SEVERITY, 0 },
190                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
191                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
192                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
193                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
194                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
195                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
196                 { AST_EVENT_IE_END, 0 }
197         },
198         .optional_ies = {
199                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
200                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
201                 { AST_EVENT_IE_END, 0 }
202         },
203 },
204
205 [AST_SECURITY_EVENT_REQ_NO_SUPPORT] = {
206         .name     = "RequestNotSupported",
207         .version  = AST_SECURITY_EVENT_REQ_NO_SUPPORT_VERSION,
208         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
209         .required_ies = {
210                 { AST_EVENT_IE_EVENT_TV, 0 },
211                 { AST_EVENT_IE_SEVERITY, 0 },
212                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
213                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
214                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
215                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
216                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
217                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
218                 { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_no_support, request_type) },
219                 { AST_EVENT_IE_END, 0 }
220         },
221         .optional_ies = {
222                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
223                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
224                 { AST_EVENT_IE_END, 0 }
225         },
226 },
227
228 [AST_SECURITY_EVENT_REQ_NOT_ALLOWED] = {
229         .name     = "RequestNotAllowed",
230         .version  = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION,
231         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
232         .required_ies = {
233                 { AST_EVENT_IE_EVENT_TV, 0 },
234                 { AST_EVENT_IE_SEVERITY, 0 },
235                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
236                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
237                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
238                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
239                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
240                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
241                 { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_not_allowed, request_type) },
242                 { AST_EVENT_IE_END, 0 }
243         },
244         .optional_ies = {
245                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
246                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
247                 { AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_not_allowed, request_params) },
248                 { AST_EVENT_IE_END, 0 }
249         },
250 },
251
252 [AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED] = {
253         .name     = "AuthMethodNotAllowed",
254         .version  = AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED_VERSION,
255         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
256         .required_ies = {
257                 { AST_EVENT_IE_EVENT_TV, 0 },
258                 { AST_EVENT_IE_SEVERITY, 0 },
259                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
260                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
261                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
262                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
263                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
264                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
265                 { AST_EVENT_IE_AUTH_METHOD, SEC_EVT_FIELD(auth_method_not_allowed, auth_method) },
266                 { AST_EVENT_IE_END, 0 }
267         },
268         .optional_ies = {
269                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
270                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
271                 { AST_EVENT_IE_END, 0 }
272         },
273 },
274
275 [AST_SECURITY_EVENT_REQ_BAD_FORMAT] = {
276         .name     = "RequestBadFormat",
277         .version  = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION,
278         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
279         .required_ies = {
280                 { AST_EVENT_IE_EVENT_TV, 0 },
281                 { AST_EVENT_IE_SEVERITY, 0 },
282                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
283                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
284                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
285                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
286                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
287                 { AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_bad_format, request_type) },
288                 { AST_EVENT_IE_END, 0 }
289         },
290         .optional_ies = {
291                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
292                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
293                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
294                 { AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_bad_format, request_params) },
295                 { AST_EVENT_IE_END, 0 }
296         },
297 },
298
299 [AST_SECURITY_EVENT_SUCCESSFUL_AUTH] = {
300         .name     = "SuccessfulAuth",
301         .version  = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
302         .severity = AST_SECURITY_EVENT_SEVERITY_INFO,
303         .required_ies = {
304                 { AST_EVENT_IE_EVENT_TV, 0 },
305                 { AST_EVENT_IE_SEVERITY, 0 },
306                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
307                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
308                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
309                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
310                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
311                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
312                 { AST_EVENT_IE_USING_PASSWORD, SEC_EVT_FIELD(successful_auth, using_password) },
313                 { AST_EVENT_IE_END, 0 }
314         },
315         .optional_ies = {
316                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
317                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
318                 { AST_EVENT_IE_END, 0 }
319         },
320 },
321
322 [AST_SECURITY_EVENT_UNEXPECTED_ADDR] = {
323         .name     = "UnexpectedAddress",
324         .version  = AST_SECURITY_EVENT_UNEXPECTED_ADDR_VERSION,
325         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
326         .required_ies = {
327                 { AST_EVENT_IE_EVENT_TV, 0 },
328                 { AST_EVENT_IE_SEVERITY, 0 },
329                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
330                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
331                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
332                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
333                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
334                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
335                 { AST_EVENT_IE_EXPECTED_ADDR, SEC_EVT_FIELD(unexpected_addr, expected_addr) },
336                 { AST_EVENT_IE_END, 0 }
337         },
338         .optional_ies = {
339                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
340                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
341                 { AST_EVENT_IE_END, 0 }
342         },
343 },
344
345 [AST_SECURITY_EVENT_CHAL_RESP_FAILED] = {
346         .name     = "ChallengeResponseFailed",
347         .version  = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
348         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
349         .required_ies = {
350                 { AST_EVENT_IE_EVENT_TV, 0 },
351                 { AST_EVENT_IE_SEVERITY, 0 },
352                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
353                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
354                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
355                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
356                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
357                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
358                 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(chal_resp_failed, challenge) },
359                 { AST_EVENT_IE_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, response) },
360                 { AST_EVENT_IE_EXPECTED_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, expected_response) },
361                 { AST_EVENT_IE_END, 0 }
362         },
363         .optional_ies = {
364                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
365                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
366                 { AST_EVENT_IE_END, 0 }
367         },
368 },
369
370 [AST_SECURITY_EVENT_INVAL_PASSWORD] = {
371         .name     = "InvalidPassword",
372         .version  = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
373         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
374         .required_ies = {
375                 { AST_EVENT_IE_EVENT_TV, 0 },
376                 { AST_EVENT_IE_SEVERITY, 0 },
377                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
378                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
379                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
380                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
381                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
382                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
383                 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(inval_password, challenge) },
384                 { AST_EVENT_IE_RECEIVED_CHALLENGE, SEC_EVT_FIELD(inval_password, received_challenge) },
385                 { AST_EVENT_IE_RECEIVED_HASH, SEC_EVT_FIELD(inval_password, received_hash) },
386                 { AST_EVENT_IE_END, 0 }
387         },
388         .optional_ies = {
389                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
390                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
391                 { AST_EVENT_IE_END, 0 }
392         },
393 },
394
395 [AST_SECURITY_EVENT_CHAL_SENT] = {
396         .name     = "ChallengeSent",
397         .version  = AST_SECURITY_EVENT_CHAL_SENT_VERSION,
398         .severity = AST_SECURITY_EVENT_SEVERITY_INFO,
399         .required_ies = {
400                 { AST_EVENT_IE_EVENT_TV, 0 },
401                 { AST_EVENT_IE_SEVERITY, 0 },
402                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
403                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
404                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
405                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
406                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
407                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
408                 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(chal_sent, challenge) },
409                 { AST_EVENT_IE_END, 0 }
410         },
411         .optional_ies = {
412                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
413                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
414                 { AST_EVENT_IE_END, 0 }
415         },
416 },
417
418 [AST_SECURITY_EVENT_INVAL_TRANSPORT] = {
419         .name     = "InvalidTransport",
420         .version  = AST_SECURITY_EVENT_INVAL_TRANSPORT_VERSION,
421         .severity = AST_SECURITY_EVENT_SEVERITY_ERROR,
422         .required_ies = {
423                 { AST_EVENT_IE_EVENT_TV, 0 },
424                 { AST_EVENT_IE_SEVERITY, 0 },
425                 { AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) },
426                 { AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) },
427                 { AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) },
428                 { AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) },
429                 { AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) },
430                 { AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) },
431                 { AST_EVENT_IE_ATTEMPTED_TRANSPORT, SEC_EVT_FIELD(inval_transport, transport) },
432                 { AST_EVENT_IE_END, 0 }
433         },
434         .optional_ies = {
435                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
436                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
437                 { AST_EVENT_IE_END, 0 }
438         },
439 },
440
441 #undef SEC_EVT_FIELD
442
443 };
444
445 static const struct {
446         enum ast_security_event_severity severity;
447         const char *str;
448 } severities[] = {
449         { AST_SECURITY_EVENT_SEVERITY_INFO,  "Informational" },
450         { AST_SECURITY_EVENT_SEVERITY_ERROR, "Error" },
451 };
452
453 const char *ast_security_event_severity_get_name(
454                 const enum ast_security_event_severity severity)
455 {
456         unsigned int i;
457
458         for (i = 0; i < ARRAY_LEN(severities); i++) {
459                 if (severities[i].severity == severity) {
460                         return severities[i].str;
461                 }
462         }
463
464         return NULL;
465 }
466
467 static int check_event_type(const enum ast_security_event_type event_type)
468 {
469         if (event_type < 0 || event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
470                 ast_log(LOG_ERROR, "Invalid security event type %u\n", event_type);
471                 return -1;
472         }
473
474         return 0;
475 }
476
477 const char *ast_security_event_get_name(const enum ast_security_event_type event_type)
478 {
479         if (check_event_type(event_type)) {
480                 return NULL;
481         }
482
483         return sec_events[event_type].name;
484 }
485
486 const struct ast_security_event_ie_type *ast_security_event_get_required_ies(
487                 const enum ast_security_event_type event_type)
488 {
489         if (check_event_type(event_type)) {
490                 return NULL;
491         }
492
493         return sec_events[event_type].required_ies;
494 }
495
496 const struct ast_security_event_ie_type *ast_security_event_get_optional_ies(
497                 const enum ast_security_event_type event_type)
498 {
499         if (check_event_type(event_type)) {
500                 return NULL;
501         }
502
503         return sec_events[event_type].optional_ies;
504 }
505
506 static int add_ip_json_object(struct ast_json *json, enum ast_event_ie_type ie_type,
507                 const struct ast_security_event_ip_addr *addr)
508 {
509         struct ast_json *json_ip;
510
511         json_ip = ast_json_ipaddr(addr->addr, addr->transport);
512         if (!json_ip) {
513                 return -1;
514         }
515
516         return ast_json_object_set(json, ast_event_get_ie_type_name(ie_type), json_ip);
517 }
518
519 enum ie_required {
520         NOT_REQUIRED,
521         REQUIRED
522 };
523
524 static int add_json_object(struct ast_json *json, const struct ast_security_event_common *sec,
525                 const struct ast_security_event_ie_type *ie_type, enum ie_required req)
526 {
527         int res = 0;
528
529         switch (ie_type->ie_type) {
530         case AST_EVENT_IE_SERVICE:
531         case AST_EVENT_IE_ACCOUNT_ID:
532         case AST_EVENT_IE_SESSION_ID:
533         case AST_EVENT_IE_MODULE:
534         case AST_EVENT_IE_ACL_NAME:
535         case AST_EVENT_IE_REQUEST_TYPE:
536         case AST_EVENT_IE_REQUEST_PARAMS:
537         case AST_EVENT_IE_AUTH_METHOD:
538         case AST_EVENT_IE_CHALLENGE:
539         case AST_EVENT_IE_RESPONSE:
540         case AST_EVENT_IE_EXPECTED_RESPONSE:
541         case AST_EVENT_IE_RECEIVED_CHALLENGE:
542         case AST_EVENT_IE_RECEIVED_HASH:
543         case AST_EVENT_IE_ATTEMPTED_TRANSPORT:
544         {
545                 const char *str;
546                 struct ast_json *json_string;
547
548                 str = *((const char **)(((const char *) sec) + ie_type->offset));
549
550                 if (req && !str) {
551                         ast_log(LOG_WARNING, "Required IE '%d' for security event "
552                                         "type '%d' not present\n", ie_type->ie_type,
553                                         sec->event_type);
554                         res = -1;
555                         break;
556                 }
557
558                 if (!str) {
559                         break;
560                 }
561
562                 json_string = ast_json_string_create(str);
563                 if (!json_string) {
564                         res = -1;
565                         break;
566                 }
567
568                 res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string);
569                 break;
570         }
571         case AST_EVENT_IE_EVENT_VERSION:
572         case AST_EVENT_IE_USING_PASSWORD:
573         {
574                 struct ast_json *json_string;
575                 uint32_t val;
576                 val = *((const uint32_t *)(((const char *) sec) + ie_type->offset));
577
578                 json_string = ast_json_stringf("%d", val);
579                 if (!json_string) {
580                         res = -1;
581                         break;
582                 }
583
584                 res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string);
585                 break;
586         }
587         case AST_EVENT_IE_LOCAL_ADDR:
588         case AST_EVENT_IE_REMOTE_ADDR:
589         case AST_EVENT_IE_EXPECTED_ADDR:
590         {
591                 const struct ast_security_event_ip_addr *addr;
592
593                 addr = (const struct ast_security_event_ip_addr *)(((const char *) sec) + ie_type->offset);
594
595                 if (req && !addr->addr) {
596                         ast_log(LOG_WARNING, "Required IE '%d' for security event "
597                                         "type '%d' not present\n", ie_type->ie_type,
598                                         sec->event_type);
599                         res = -1;
600                 }
601
602                 if (addr->addr) {
603                         res = add_ip_json_object(json, ie_type->ie_type, addr);
604                 }
605
606                 break;
607         }
608         case AST_EVENT_IE_SESSION_TV:
609         {
610                 const struct timeval *tval;
611
612                 tval = *((const struct timeval **)(((const char *) sec) + ie_type->offset));
613
614                 if (req && !tval) {
615                         ast_log(LOG_WARNING, "Required IE '%d' for security event "
616                                         "type '%d' not present\n", ie_type->ie_type,
617                                         sec->event_type);
618                         res = -1;
619                 }
620
621                 if (tval) {
622                         struct ast_json *json_tval = ast_json_timeval(*tval, NULL);
623                         if (!json_tval) {
624                                 res = -1;
625                                 break;
626                         }
627                         res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_tval);
628                 }
629
630                 break;
631         }
632         case AST_EVENT_IE_EVENT_TV:
633         case AST_EVENT_IE_SEVERITY:
634                 /* Added automatically, nothing to do here. */
635                 break;
636         default:
637                 ast_log(LOG_WARNING, "Unhandled IE type '%d', this security event "
638                                 "will be missing data.\n", ie_type->ie_type);
639                 break;
640         }
641
642         return res;
643 }
644
645 static struct ast_json *alloc_security_event_json_object(const struct ast_security_event_common *sec)
646 {
647         struct timeval tv = ast_tvnow();
648         const char *severity_str;
649         struct ast_json *json_temp;
650         RAII_VAR(struct ast_json *, json_object, ast_json_object_create(), ast_json_unref);
651
652         if (!json_object) {
653                 return NULL;
654         }
655
656         /* NOTE: Every time ast_json_object_set is used, json_temp becomes a stale pointer since the reference is taken.
657          *       This is true even if ast_json_object_set fails.
658          */
659
660         /* AST_EVENT_IE_SECURITY_EVENT */
661         json_temp = ast_json_integer_create(sec->event_type);
662         if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SECURITY_EVENT), json_temp)) {
663                 return NULL;
664         }
665
666         /* AST_EVENT_IE_EVENT_VERSION */
667         json_temp = ast_json_stringf("%d", sec->version);
668         if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_VERSION), json_temp)) {
669                 return NULL;
670         }
671
672         /* AST_EVENT_IE_EVENT_TV */
673         json_temp  = ast_json_timeval(tv, NULL);
674         if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_TV), json_temp)) {
675                 return NULL;
676         }
677
678         /* AST_EVENT_IE_SERVICE */
679         json_temp = ast_json_string_create(sec->service);
680         if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SERVICE), json_temp)) {
681                 return NULL;
682         }
683
684         /* AST_EVENT_IE_SEVERITY */
685         severity_str = S_OR(
686                 ast_security_event_severity_get_name(sec_events[sec->event_type].severity),
687                 "Unknown"
688         );
689
690         json_temp = ast_json_string_create(severity_str);
691         if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SEVERITY), json_temp)) {
692                 return NULL;
693         }
694
695         return ast_json_ref(json_object);
696 }
697
698 static int handle_security_event(const struct ast_security_event_common *sec)
699 {
700         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
701         RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup);
702         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
703
704         const struct ast_security_event_ie_type *ies;
705         unsigned int i;
706
707         json_object = alloc_security_event_json_object(sec);
708
709         if (!json_object) {
710                 return -1;
711         }
712
713         for (ies = ast_security_event_get_required_ies(sec->event_type), i = 0;
714                         ies[i].ie_type != AST_EVENT_IE_END;
715                         i++) {
716                 if (add_json_object(json_object, sec, ies + i, REQUIRED)) {
717                         goto return_error;
718                 }
719         }
720
721         for (ies = ast_security_event_get_optional_ies(sec->event_type), i = 0;
722                         ies[i].ie_type != AST_EVENT_IE_END;
723                         i++) {
724                 if (add_json_object(json_object, sec, ies + i, NOT_REQUIRED)) {
725                         goto return_error;
726                 }
727         }
728
729         /* The json blob is ready.  Throw it in the payload and send it out over stasis. */
730         if (!(json_payload = ast_json_payload_create(json_object))) {
731                 goto return_error;
732         }
733
734         msg = stasis_message_create(ast_security_event_type(), json_payload);
735
736         if (!msg) {
737                 goto return_error;
738         }
739
740         stasis_publish(ast_security_topic(), msg);
741
742         return 0;
743
744 return_error:
745         return -1;
746 }
747
748 int ast_security_event_report(const struct ast_security_event_common *sec)
749 {
750         if (sec->event_type < 0 || sec->event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
751                 ast_log(LOG_ERROR, "Invalid security event type\n");
752                 return -1;
753         }
754
755         if (!sec_events[sec->event_type].name) {
756                 ast_log(LOG_WARNING, "Security event type %u not handled\n",
757                                 sec->event_type);
758                 return -1;
759         }
760
761         if (sec->version != sec_events[sec->event_type].version) {
762                 ast_log(LOG_WARNING, "Security event %u version mismatch\n",
763                                 sec->event_type);
764                 return -1;
765         }
766
767         if (handle_security_event(sec)) {
768                 ast_log(LOG_ERROR, "Failed to issue security event of type %s.\n",
769                                 ast_security_event_get_name(sec->event_type));
770         }
771
772         return 0;
773 }
774
775