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