UNREGISTER instead of REGISTER in unload_module().
[asterisk/asterisk.git] / res / res_security_log.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, 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  * \author Russell Bryant <russell@digium.com>
23  *
24  * \brief Security Event Logging
25  *
26  * \todo Make informational security events optional
27  * \todo Escape quotes in string payload IE contents
28  */
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
33
34 #include "asterisk/module.h"
35 #include "asterisk/logger.h"
36 #include "asterisk/event.h"
37 #include "asterisk/threadstorage.h"
38 #include "asterisk/strings.h"
39 #include "asterisk/security_events.h"
40
41 static const char LOG_SECURITY_NAME[] = "SECURITY";
42
43 static int LOG_SECURITY;
44
45 static struct ast_event_sub *security_event_sub;
46
47 AST_THREADSTORAGE(security_event_buf);
48 static const size_t SECURITY_EVENT_BUF_INIT_LEN = 256;
49
50 enum ie_required {
51         NOT_REQUIRED,
52         REQUIRED
53 };
54
55 static int ie_is_present(const struct ast_event *event,
56                 const enum ast_event_ie_type ie_type)
57 {
58         return (ast_event_get_ie_raw(event, ie_type) != NULL);
59 }
60
61 static void append_ie(struct ast_str **str, const struct ast_event *event,
62                 const enum ast_event_ie_type ie_type, enum ie_required required)
63 {
64         if (!required && !ie_is_present(event, ie_type)) {
65                 /* Optional IE isn't present.  Ignore. */
66                 return;
67         }
68
69         /* At this point, it _better_ be there! */
70         ast_assert(ie_is_present(event, ie_type));
71
72         switch (ast_event_get_ie_pltype(ie_type)) {
73         case AST_EVENT_IE_PLTYPE_UINT:
74                 ast_str_append(str, 0, ",%s=\"%u\"",
75                                 ast_event_get_ie_type_name(ie_type),
76                                 ast_event_get_ie_uint(event, ie_type));
77                 break;
78         case AST_EVENT_IE_PLTYPE_STR:
79                 ast_str_append(str, 0, ",%s=\"%s\"",
80                                 ast_event_get_ie_type_name(ie_type),
81                                 ast_event_get_ie_str(event, ie_type));
82                 break;
83         case AST_EVENT_IE_PLTYPE_BITFLAGS:
84                 ast_str_append(str, 0, ",%s=\"%u\"",
85                                 ast_event_get_ie_type_name(ie_type),
86                                 ast_event_get_ie_bitflags(event, ie_type));
87                 break;
88         case AST_EVENT_IE_PLTYPE_UNKNOWN:
89         case AST_EVENT_IE_PLTYPE_EXISTS:
90         case AST_EVENT_IE_PLTYPE_RAW:
91                 ast_log(LOG_WARNING, "Unexpected payload type for IE '%s'\n",
92                                 ast_event_get_ie_type_name(ie_type));
93                 break;
94         }
95 }
96
97 static void append_ies(struct ast_str **str, const struct ast_event *event,
98                 const struct ast_security_event_ie_type *ies, enum ie_required required)
99 {
100         unsigned int i;
101
102         for (i = 0; ies[i].ie_type != AST_EVENT_IE_END; i++) {
103                 append_ie(str, event, ies[i].ie_type, required);
104         }
105 }
106
107 static void security_event_cb(const struct ast_event *event, void *data)
108 {
109         struct ast_str *str;
110         enum ast_security_event_type event_type;
111
112         if (!(str = ast_str_thread_get(&security_event_buf,
113                         SECURITY_EVENT_BUF_INIT_LEN))) {
114                 return;
115         }
116
117         /* Note that the event type is guaranteed to be valid here. */
118         event_type = ast_event_get_ie_uint(event, AST_EVENT_IE_SECURITY_EVENT);
119         ast_assert(event_type >= 0 && event_type < AST_SECURITY_EVENT_NUM_TYPES);
120
121         ast_str_set(&str, 0, "%s=\"%s\"",
122                         ast_event_get_ie_type_name(AST_EVENT_IE_SECURITY_EVENT),
123                         ast_security_event_get_name(event_type));
124
125         append_ies(&str, event,
126                         ast_security_event_get_required_ies(event_type), REQUIRED);
127         append_ies(&str, event,
128                         ast_security_event_get_optional_ies(event_type), NOT_REQUIRED);
129
130         ast_log_dynamic_level(LOG_SECURITY, "%s\n", ast_str_buffer(str));
131 }
132
133 static int load_module(void)
134 {
135         if ((LOG_SECURITY = ast_logger_register_level(LOG_SECURITY_NAME)) == -1) {
136                 return AST_MODULE_LOAD_DECLINE;
137         }
138
139         if (!(security_event_sub = ast_event_subscribe(AST_EVENT_SECURITY,
140                         security_event_cb, "Security Event Logger",
141                         NULL, AST_EVENT_IE_END))) {
142                 ast_logger_unregister_level(LOG_SECURITY_NAME);
143                 LOG_SECURITY = -1;
144                 return AST_MODULE_LOAD_DECLINE;
145         }
146
147         ast_verb(3, "Security Logging Enabled\n");
148
149         return AST_MODULE_LOAD_SUCCESS;
150 }
151
152 static int unload_module(void)
153 {
154         if (security_event_sub) {
155                 security_event_sub = ast_event_unsubscribe(security_event_sub);
156         }
157
158         ast_verb(3, "Security Logging Disabled\n");
159
160         return 0;
161 }
162
163 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Security Event Logging");