d10338984a49246850ec8ee33c363b97f1e5af8c
[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_END, 0 }
384         },
385         .optional_ies = {
386                 { AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) },
387                 { AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) },
388                 { AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(inval_password, challenge) },
389                 { AST_EVENT_IE_RECEIVED_CHALLENGE, SEC_EVT_FIELD(inval_password, received_challenge) },
390                 { AST_EVENT_IE_RECEIVED_HASH, SEC_EVT_FIELD(inval_password, received_hash) },
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         json_temp = ast_json_integer_create(sec->event_type);
661         if (!json_temp || ast_json_object_set(json_object, "SecurityEvent", json_temp)) {
662                 return NULL;
663         }
664
665         json_temp = ast_json_stringf("%d", sec->version);
666         if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_VERSION), json_temp)) {
667                 return NULL;
668         }
669
670         /* AST_EVENT_IE_EVENT_TV */
671         json_temp  = ast_json_timeval(tv, NULL);
672         if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_TV), json_temp)) {
673                 return NULL;
674         }
675
676         /* AST_EVENT_IE_SERVICE */
677         json_temp = ast_json_string_create(sec->service);
678         if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SERVICE), json_temp)) {
679                 return NULL;
680         }
681
682         /* AST_EVENT_IE_SEVERITY */
683         severity_str = S_OR(
684                 ast_security_event_severity_get_name(sec_events[sec->event_type].severity),
685                 "Unknown"
686         );
687
688         json_temp = ast_json_string_create(severity_str);
689         if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SEVERITY), json_temp)) {
690                 return NULL;
691         }
692
693         return ast_json_ref(json_object);
694 }
695
696 static int handle_security_event(const struct ast_security_event_common *sec)
697 {
698         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
699         RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup);
700         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
701
702         const struct ast_security_event_ie_type *ies;
703         unsigned int i;
704
705         json_object = alloc_security_event_json_object(sec);
706
707         if (!json_object) {
708                 return -1;
709         }
710
711         for (ies = ast_security_event_get_required_ies(sec->event_type), i = 0;
712                         ies[i].ie_type != AST_EVENT_IE_END;
713                         i++) {
714                 if (add_json_object(json_object, sec, ies + i, REQUIRED)) {
715                         goto return_error;
716                 }
717         }
718
719         for (ies = ast_security_event_get_optional_ies(sec->event_type), i = 0;
720                         ies[i].ie_type != AST_EVENT_IE_END;
721                         i++) {
722                 if (add_json_object(json_object, sec, ies + i, NOT_REQUIRED)) {
723                         goto return_error;
724                 }
725         }
726
727         /* The json blob is ready.  Throw it in the payload and send it out over stasis. */
728         if (!(json_payload = ast_json_payload_create(json_object))) {
729                 goto return_error;
730         }
731
732         msg = stasis_message_create(ast_security_event_type(), json_payload);
733
734         if (!msg) {
735                 goto return_error;
736         }
737
738         stasis_publish(ast_security_topic(), msg);
739
740         return 0;
741
742 return_error:
743         return -1;
744 }
745
746 int ast_security_event_report(const struct ast_security_event_common *sec)
747 {
748         if (sec->event_type < 0 || sec->event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
749                 ast_log(LOG_ERROR, "Invalid security event type\n");
750                 return -1;
751         }
752
753         if (!sec_events[sec->event_type].name) {
754                 ast_log(LOG_WARNING, "Security event type %u not handled\n",
755                                 sec->event_type);
756                 return -1;
757         }
758
759         if (sec->version != sec_events[sec->event_type].version) {
760                 ast_log(LOG_WARNING, "Security event %u version mismatch\n",
761                                 sec->event_type);
762                 return -1;
763         }
764
765         if (handle_security_event(sec)) {
766                 ast_log(LOG_ERROR, "Failed to issue security event of type %s.\n",
767                                 ast_security_event_get_name(sec->event_type));
768         }
769
770         return 0;
771 }
772
773