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