238c1007dd86fb9d2df459c70e58fde0abf59e62
[asterisk/asterisk.git] / res / res_pjsip / security_events.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@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 Generate security events in the PJSIP channel
23  *
24  * \author Joshua Colp <jcolp@digium.com>
25  */
26
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30
31 #include <pjsip.h>
32
33 #include "asterisk/res_pjsip.h"
34 #include "asterisk/security_events.h"
35
36 static enum ast_transport security_event_get_transport(pjsip_rx_data *rdata)
37 {
38         if (rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP ||
39                 rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
40                 return AST_TRANSPORT_UDP;
41         } else if (rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP ||
42                 rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP6) {
43                 return AST_TRANSPORT_TCP;
44         } else if (rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS ||
45                 rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS6) {
46                 return AST_TRANSPORT_TLS;
47         } else if (!strcmp(rdata->tp_info.transport->type_name, "WS")) {
48                 return AST_TRANSPORT_WS;
49         } else if (!strcmp(rdata->tp_info.transport->type_name, "WSS")) {
50                 return AST_TRANSPORT_WSS;
51         } else {
52                 return 0;
53         }
54 }
55
56 static void security_event_populate(pjsip_rx_data *rdata, char *call_id, size_t call_id_size, struct ast_sockaddr *local, struct ast_sockaddr *remote)
57 {
58         char host[NI_MAXHOST];
59
60         ast_copy_pj_str(call_id, &rdata->msg_info.cid->id, call_id_size);
61
62         ast_copy_pj_str(host, &rdata->tp_info.transport->local_name.host, sizeof(host));
63         ast_sockaddr_parse(local, host, PARSE_PORT_FORBID);
64         ast_sockaddr_set_port(local, rdata->tp_info.transport->local_name.port);
65
66         ast_sockaddr_parse(remote, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
67         ast_sockaddr_set_port(remote, rdata->pkt_info.src_port);
68 }
69
70 void ast_sip_report_invalid_endpoint(const char *name, pjsip_rx_data *rdata)
71 {
72         enum ast_transport transport = security_event_get_transport(rdata);
73         char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
74         struct ast_sockaddr local, remote;
75
76         struct ast_security_event_inval_acct_id inval_acct_id = {
77                 .common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID,
78                 .common.version    = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
79                 .common.service    = "PJSIP",
80                 .common.account_id = name,
81                 .common.local_addr = {
82                         .addr      = &local,
83                         .transport = transport,
84                 },
85                 .common.remote_addr = {
86                         .addr       = &remote,
87                         .transport = transport,
88                 },
89                 .common.session_id = call_id,
90         };
91
92         security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
93
94         ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
95 }
96
97 void ast_sip_report_failed_acl(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *name)
98 {
99         enum ast_transport transport = security_event_get_transport(rdata);
100         char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
101         struct ast_sockaddr local, remote;
102
103         struct ast_security_event_failed_acl failed_acl_event = {
104                         .common.event_type  = AST_SECURITY_EVENT_FAILED_ACL,
105                         .common.version     = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
106                         .common.service     = "PJSIP",
107                         .common.account_id  = ast_sorcery_object_get_id(endpoint),
108                         .common.local_addr  = {
109                                         .addr       = &local,
110                                         .transport  = transport,
111                         },
112                         .common.remote_addr = {
113                                         .addr       = &remote,
114                                         .transport  = transport,
115                         },
116                         .common.session_id  = call_id,
117                         .acl_name           = name,
118         };
119
120         security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
121
122         ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
123 }
124
125 void ast_sip_report_auth_failed_challenge_response(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
126 {
127         pjsip_authorization_hdr *auth = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL);
128         enum ast_transport transport = security_event_get_transport(rdata);
129         char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
130         char nonce[64] = "", response[256] = "";
131         struct ast_sockaddr local, remote;
132
133         struct ast_security_event_chal_resp_failed chal_resp_failed = {
134                                 .common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED,
135                                 .common.version    = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
136                                 .common.service    = "PJSIP",
137                                 .common.account_id = ast_sorcery_object_get_id(endpoint),
138                                 .common.local_addr = {
139                                                 .addr      = &local,
140                                                 .transport = transport,
141                                 },
142                                 .common.remote_addr = {
143                                                 .addr      = &remote,
144                                                 .transport = transport,
145                                 },
146                                 .common.session_id = call_id,
147
148                                 .challenge         = nonce,
149                                 .response          = response,
150                                 .expected_response = "",
151                 };
152
153         if (auth && !pj_strcmp2(&auth->scheme, "Digest")) {
154                 ast_copy_pj_str(nonce, &auth->credential.digest.nonce, sizeof(nonce));
155                 ast_copy_pj_str(response, &auth->credential.digest.response, sizeof(response));
156         }
157
158         security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
159
160         ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
161 }
162
163 void ast_sip_report_auth_success(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
164 {
165         pjsip_authorization_hdr *auth = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL);
166         enum ast_transport transport = security_event_get_transport(rdata);
167         char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
168         struct ast_sockaddr local, remote;
169
170         struct ast_security_event_successful_auth successful_auth = {
171                         .common.event_type  = AST_SECURITY_EVENT_SUCCESSFUL_AUTH,
172                         .common.version     = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
173                         .common.service     = "PJSIP",
174                         .common.account_id  = ast_sorcery_object_get_id(endpoint),
175                         .common.local_addr  = {
176                                         .addr       = &local,
177                                         .transport  = transport,
178                         },
179                         .common.remote_addr = {
180                                         .addr       = &remote,
181                                         .transport  = transport,
182                         },
183                         .common.session_id  = call_id,
184                         .using_password     = auth ? (uint32_t *)1 : (uint32_t *)0,
185         };
186
187         security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
188
189         ast_security_event_report(AST_SEC_EVT(&successful_auth));
190 }
191
192 void ast_sip_report_auth_challenge_sent(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata)
193 {
194         pjsip_www_authenticate_hdr *auth = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_WWW_AUTHENTICATE, NULL);
195         enum ast_transport transport = security_event_get_transport(rdata);
196         char nonce[64] = "", call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
197         struct ast_sockaddr local, remote;
198
199         struct ast_security_event_chal_sent chal_sent = {
200                         .common.event_type = AST_SECURITY_EVENT_CHAL_SENT,
201                         .common.version    = AST_SECURITY_EVENT_CHAL_SENT_VERSION,
202                         .common.service    = "PJSIP",
203                         .common.account_id = ast_sorcery_object_get_id(endpoint),
204                         .common.local_addr = {
205                                         .addr      = &local,
206                                         .transport = transport,
207                         },
208                         .common.remote_addr = {
209                                         .addr      = &remote,
210                                         .transport = transport,
211                         },
212                         .common.session_id = call_id,
213                         .challenge         = nonce,
214         };
215
216         if (auth && !pj_strcmp2(&auth->scheme, "digest")) {
217                 ast_copy_pj_str(nonce, &auth->challenge.digest.nonce, sizeof(nonce));
218         }
219
220         security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
221
222         ast_security_event_report(AST_SEC_EVT(&chal_sent));
223 }
224
225 void ast_sip_report_req_no_support(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
226                                    const char* req_type)
227 {
228         enum ast_transport transport = security_event_get_transport(rdata);
229         char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
230         struct ast_sockaddr local, remote;
231
232         struct ast_security_event_req_no_support req_no_support_event = {
233                 .common.event_type  = AST_SECURITY_EVENT_REQ_NO_SUPPORT,
234                 .common.version     = AST_SECURITY_EVENT_REQ_NO_SUPPORT_VERSION,
235                 .common.service     = "PJSIP",
236                 .common.account_id  = ast_sorcery_object_get_id(endpoint),
237                 .common.local_addr  = {
238                         .addr       = &local,
239                         .transport  = transport,
240                 },
241                 .common.remote_addr = {
242                         .addr       = &remote,
243                         .transport  = transport,
244                 },
245                 .common.session_id  = call_id,
246                 .request_type       = req_type
247         };
248
249         security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
250
251         ast_security_event_report(AST_SEC_EVT(&req_no_support_event));
252 }
253
254 void ast_sip_report_mem_limit(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
255 {
256         enum ast_transport transport = security_event_get_transport(rdata);
257         char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
258         struct ast_sockaddr local, remote;
259
260         struct ast_security_event_mem_limit mem_limit_event = {
261                 .common.event_type  = AST_SECURITY_EVENT_MEM_LIMIT,
262                 .common.version     = AST_SECURITY_EVENT_MEM_LIMIT_VERSION,
263                 .common.service     = "PJSIP",
264                 .common.account_id  = ast_sorcery_object_get_id(endpoint),
265                 .common.local_addr  = {
266                         .addr       = &local,
267                         .transport  = transport,
268                 },
269                 .common.remote_addr = {
270                         .addr       = &remote,
271                         .transport  = transport,
272                 },
273                 .common.session_id  = call_id
274         };
275
276         security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
277
278         ast_security_event_report(AST_SEC_EVT(&mem_limit_event));
279 }