a4ce54769f79f6a1baf52fa175251d424305136e
[asterisk/asterisk.git] / res / res_pjsip_registrar.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 /*** MODULEINFO
20         <depend>pjproject</depend>
21         <depend>res_pjproject</depend>
22         <depend>res_pjsip</depend>
23         <support_level>core</support_level>
24  ***/
25
26 #include "asterisk.h"
27
28 #include <pjsip.h>
29 #include <pjsip_ua.h>
30
31 #include "asterisk/res_pjsip.h"
32 #include "asterisk/module.h"
33 #include "asterisk/paths.h"
34 #include "asterisk/test.h"
35 #include "asterisk/taskprocessor.h"
36 #include "asterisk/manager.h"
37 #include "asterisk/named_locks.h"
38 #include "asterisk/res_pjproject.h"
39 #include "res_pjsip/include/res_pjsip_private.h"
40
41 /*** DOCUMENTATION
42         <manager name="PJSIPShowRegistrationsInbound" language="en_US">
43                 <synopsis>
44                         Lists PJSIP inbound registrations.
45                 </synopsis>
46                 <syntax />
47                 <description>
48                         <para>
49                         In response, <literal>InboundRegistrationDetail</literal> events showing configuration
50                         and status information are raised for all contacts, static or dynamic.  Once all events
51                         are completed an <literal>InboundRegistrationDetailComplete</literal> is issued.
52                         </para>
53                         <warning><para>
54                                 This command just dumps all coonfigured AORs with contacts, even if the contact
55                                 is a permanent one.  To really get just inbound registrations, use
56                                 <literal>PJSIPShowRegistrationInboundContactStatuses</literal>.
57                         </para>
58                         </warning>
59                 </description>
60                 <see-also>
61                         <ref type="manager" module="res_pjsip_registrar">PJSIPShowRegistrationInboundContactStatuses</ref>
62                 </see-also>
63         </manager>
64         <manager name="PJSIPShowRegistrationInboundContactStatuses" language="en_US">
65                 <synopsis>
66                         Lists ContactStatuses for PJSIP inbound registrations.
67                 </synopsis>
68                 <syntax />
69                 <description>
70                         <para>
71                         In response, <literal>ContactStatusDetail</literal> events showing status information
72                         are raised for each inbound registration (dynamic contact) object.  Once all events
73                         are completed a <literal>ContactStatusDetailComplete</literal> event is issued.
74                         </para>
75                 </description>
76         </manager>
77  ***/
78
79 static int pj_max_hostname = PJ_MAX_HOSTNAME;
80 static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE;
81
82 /*! \brief Internal function which returns the expiration time for a contact */
83 static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
84 {
85         pjsip_expires_hdr *expires;
86         int expiration = aor->default_expiration;
87
88         if (contact && contact->expires != -1) {
89                 /* Expiration was provided with the contact itself */
90                 expiration = contact->expires;
91         } else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
92                 /* Expiration was provided using the Expires header */
93                 expiration = expires->ivalue;
94         }
95
96         /* If the value has explicitly been set to 0, do not enforce */
97         if (!expiration) {
98                 return expiration;
99         }
100
101         /* Enforce the range that we will allow for expiration */
102         if (expiration < aor->minimum_expiration) {
103                 expiration = aor->minimum_expiration;
104         } else if (expiration > aor->maximum_expiration) {
105                 expiration = aor->maximum_expiration;
106         }
107
108         return expiration;
109 }
110
111 /*! \brief Structure used for finding contact */
112 struct registrar_contact_details {
113         /*! \brief Pool used for parsing URI */
114         pj_pool_t *pool;
115         /*! \brief URI being looked for */
116         pjsip_sip_uri *uri;
117 };
118
119 /*! \brief Callback function for finding a contact */
120 static int registrar_find_contact(void *obj, void *arg, int flags)
121 {
122         struct ast_sip_contact *contact = obj;
123         const struct registrar_contact_details *details = arg;
124         pjsip_uri *contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
125
126         return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0;
127 }
128
129 /*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
130 static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted)
131 {
132         pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
133         struct registrar_contact_details details = {
134                 .pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256),
135         };
136
137         if (!details.pool) {
138                 return -1;
139         }
140
141         while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
142                 int expiration = registrar_get_expiration(aor, contact, rdata);
143                 RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup);
144                 char contact_uri[pjsip_max_url_size];
145
146                 if (contact->star) {
147                         /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
148                         if ((expiration != 0) || previous) {
149                                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
150                                 return -1;
151                         }
152                         continue;
153                 } else if (previous && previous->star) {
154                         /* If there is a previous contact and it is a '*' this is a deal breaker */
155                         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
156                         return -1;
157                 }
158                 previous = contact;
159
160                 if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
161                         continue;
162                 }
163
164                 details.uri = pjsip_uri_get_uri(contact->uri);
165
166                 /* pjsip_uri_print returns -1 if there's not enough room in the buffer */
167                 if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
168                         /* If the total length of the uri is greater than pjproject can handle, go no further */
169                         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
170                         return -1;
171                 }
172
173                 if (details.uri->host.slen >= pj_max_hostname) {
174                         /* If the length of the hostname is greater than pjproject can handle, go no further */
175                         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
176                         return -1;
177                 }
178
179                 /* Determine if this is an add, update, or delete for policy enforcement purposes */
180                 if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) {
181                         if (expiration) {
182                                 (*added)++;
183                         }
184                 } else if (expiration) {
185                         (*updated)++;
186                 } else {
187                         (*deleted)++;
188                 }
189         }
190
191         /* The provided contacts are acceptable, huzzah! */
192         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
193         return 0;
194 }
195
196 /*! \brief Callback function which prunes static contacts */
197 static int registrar_prune_static(void *obj, void *arg, int flags)
198 {
199         struct ast_sip_contact *contact = obj;
200
201         return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
202 }
203
204 /*! \brief Internal function used to delete a contact from an AOR */
205 static int registrar_delete_contact(void *obj, void *arg, int flags)
206 {
207         struct ast_sip_contact *contact = obj;
208         const char *aor_name = arg;
209
210         ast_sip_location_delete_contact(contact);
211         if (!ast_strlen_zero(aor_name)) {
212                 ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name);
213                 ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
214                                 "Contact: %s\r\n"
215                                 "AOR: %s\r\n"
216                                 "UserAgent: %s",
217                                 contact->uri,
218                                 aor_name,
219                                 contact->user_agent);
220         }
221
222         return 0;
223 }
224
225 /*! \brief Internal function which adds a contact to a response */
226 static int registrar_add_contact(void *obj, void *arg, int flags)
227 {
228         struct ast_sip_contact *contact = obj;
229         pjsip_tx_data *tdata = arg;
230         pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
231         pj_str_t uri;
232
233         pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
234         hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
235         hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;
236
237         pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
238
239         return 0;
240 }
241
242 /*! \brief Helper function which adds a Date header to a response */
243 static void registrar_add_date_header(pjsip_tx_data *tdata)
244 {
245         char date[256];
246         struct tm tm;
247         time_t t = time(NULL);
248
249         gmtime_r(&t, &tm);
250         strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);
251
252         ast_sip_add_header(tdata, "Date", date);
253 }
254
255 static const pj_str_t path_hdr_name = { "Path", 4 };
256
257 static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str)
258 {
259         pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, NULL);
260
261         if (!path_hdr) {
262                 return 0;
263         }
264
265         *path_str = ast_str_create(64);
266         if (!path_str) {
267                 return -1;
268         }
269
270         ast_str_set(path_str, 0, "%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
271
272         while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) {
273                 ast_str_append(path_str, 0, ",%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
274         }
275
276         return 0;
277 }
278
279 static int registrar_validate_path(pjsip_rx_data *rdata, struct ast_sip_aor *aor, struct ast_str **path_str)
280 {
281         const pj_str_t path_supported_name = { "path", 4 };
282         pjsip_supported_hdr *supported_hdr;
283         int i;
284
285         if (!aor->support_path) {
286                 return 0;
287         }
288
289         if (build_path_data(rdata, path_str)) {
290                 return -1;
291         }
292
293         if (!*path_str) {
294                 return 0;
295         }
296
297         supported_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL);
298         if (!supported_hdr) {
299                 return -1;
300         }
301
302         /* Find advertised path support */
303         for (i = 0; i < supported_hdr->count; i++) {
304                 if (!pj_stricmp(&supported_hdr->values[i], &path_supported_name)) {
305                         return 0;
306                 }
307         }
308
309         /* Path header present, but support not advertised */
310         return -1;
311 }
312
313 static int register_aor_core(pjsip_rx_data *rdata,
314         struct ast_sip_endpoint *endpoint,
315         struct ast_sip_aor *aor,
316         const char *aor_name,
317         struct ao2_container *contacts)
318 {
319         static const pj_str_t USER_AGENT = { "User-Agent", 10 };
320
321         int added = 0, updated = 0, deleted = 0;
322         pjsip_contact_hdr *contact_hdr = NULL;
323         struct registrar_contact_details details = { 0, };
324         pjsip_tx_data *tdata;
325         RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
326         struct ast_sip_contact *response_contact;
327         char *user_agent = NULL;
328         pjsip_user_agent_hdr *user_agent_hdr;
329         pjsip_expires_hdr *expires_hdr;
330         pjsip_via_hdr *via_hdr;
331         pjsip_via_hdr *via_hdr_last;
332         char *via_addr = NULL;
333         int via_port = 0;
334         pjsip_cid_hdr *call_id_hdr;
335         char *call_id = NULL;
336         size_t alloc_size;
337
338         /* So we don't count static contacts against max_contacts we prune them out from the container */
339         ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
340
341         if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) {
342                 /* The provided Contact headers do not conform to the specification */
343                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
344                 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
345                 ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
346                                 ast_sorcery_object_get_id(endpoint));
347                 return PJ_TRUE;
348         }
349
350         if (registrar_validate_path(rdata, aor, &path_str)) {
351                 /* Ensure that intervening proxies did not make invalid modifications to the request */
352                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 420, NULL, NULL, NULL);
353                 ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
354                                 ast_sorcery_object_get_id(endpoint));
355                 return PJ_TRUE;
356         }
357
358         if ((MAX(added - deleted, 0) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) {
359                 /* Enforce the maximum number of contacts */
360                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
361                 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
362                 ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n",
363                                 ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts);
364                 return PJ_TRUE;
365         }
366
367         if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) {
368                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
369                 return PJ_TRUE;
370         }
371
372         user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL);
373         if (user_agent_hdr) {
374                 alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
375                 user_agent = ast_alloca(alloc_size);
376                 ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
377         }
378
379         /* Find the first Via header */
380         via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
381         if (via_hdr) {
382                 /* Find the last Via header */
383                 while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
384                                 PJSIP_H_VIA, via_hdr->next)) != NULL) {
385                         via_hdr_last = via_hdr;
386                 }
387                 alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
388                 via_addr = ast_alloca(alloc_size);
389                 ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size);
390                 via_port=via_hdr_last->sent_by.port;
391         }
392
393         call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL);
394         if (call_id_hdr) {
395                 alloc_size = pj_strlen(&call_id_hdr->id) + 1;
396                 call_id = ast_alloca(alloc_size);
397                 ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size);
398         }
399
400         /* Iterate each provided Contact header and add, update, or delete */
401         while ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
402                 int expiration;
403                 char contact_uri[pjsip_max_url_size];
404                 RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
405
406                 if (contact_hdr->star) {
407                         /* A star means to unregister everything, so do so for the possible contacts */
408                         ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name);
409                         break;
410                 }
411
412                 if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
413                         /* This registrar only currently supports sip: and sips: URI schemes */
414                         continue;
415                 }
416
417                 expiration = registrar_get_expiration(aor, contact_hdr, rdata);
418                 details.uri = pjsip_uri_get_uri(contact_hdr->uri);
419                 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
420
421                 if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) {
422                         /* If they are actually trying to delete a contact that does not exist... be forgiving */
423                         if (!expiration) {
424                                 ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
425                                         contact_uri, aor_name);
426                                 continue;
427                         }
428
429                         if (ast_sip_location_add_contact_nolock(aor, contact_uri, ast_tvadd(ast_tvnow(),
430                                 ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL,
431                                         user_agent, via_addr, via_port, call_id, endpoint)) {
432                                 ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
433                                                 contact_uri, aor_name);
434                                 continue;
435                         }
436
437                         ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
438                                 contact_uri, aor_name, expiration);
439                         ast_test_suite_event_notify("AOR_CONTACT_ADDED",
440                                         "Contact: %s\r\n"
441                                         "AOR: %s\r\n"
442                                         "Expiration: %d\r\n"
443                                         "UserAgent: %s",
444                                         contact_uri,
445                                         aor_name,
446                                         expiration,
447                                         user_agent);
448                 } else if (expiration) {
449                         struct ast_sip_contact *contact_update;
450
451                         contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact);
452                         if (!contact_update) {
453                                 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
454                                         contact->uri, expiration);
455                                 continue;
456                         }
457
458                         contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
459                         contact_update->qualify_frequency = aor->qualify_frequency;
460                         contact_update->authenticate_qualify = aor->authenticate_qualify;
461                         if (path_str) {
462                                 ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
463                         }
464                         if (user_agent) {
465                                 ast_string_field_set(contact_update, user_agent, user_agent);
466                         }
467                         if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
468                                 ast_string_field_set(contact_update, reg_server, ast_config_AST_SYSTEM_NAME);
469                         }
470
471                         if (ast_sip_location_update_contact(contact_update)) {
472                                 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
473                                         contact->uri, expiration);
474                                 ast_sip_location_delete_contact(contact);
475                                 continue;
476                         }
477                         ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
478                                 contact_uri, aor_name, expiration);
479                         ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
480                                         "Contact: %s\r\n"
481                                         "AOR: %s\r\n"
482                                         "Expiration: %d\r\n"
483                                         "UserAgent: %s",
484                                         contact_uri,
485                                         aor_name,
486                                         expiration,
487                                         contact_update->user_agent);
488                         ao2_cleanup(contact_update);
489                 } else {
490                         /* We want to report the user agent that was actually in the removed contact */
491                         ast_sip_location_delete_contact(contact);
492                         ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
493                         ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
494                                         "Contact: %s\r\n"
495                                         "AOR: %s\r\n"
496                                         "UserAgent: %s",
497                                         contact_uri,
498                                         aor_name,
499                                         contact->user_agent);
500                 }
501         }
502
503         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
504
505         /* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
506          * do so
507          */
508         if (aor->remove_existing) {
509                 ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
510         }
511
512         /* Re-retrieve contacts.  Caller will clean up the original container. */
513         contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
514         response_contact = ao2_callback(contacts, 0, NULL, NULL);
515
516         /* Send a response containing all of the contacts (including static) that are present on this AOR */
517         if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
518                 ao2_cleanup(response_contact);
519                 ao2_cleanup(contacts);
520                 return PJ_TRUE;
521         }
522         ao2_cleanup(response_contact);
523
524         /* Add the date header to the response, some UAs use this to set their date and time */
525         registrar_add_date_header(tdata);
526
527         ao2_callback(contacts, 0, registrar_add_contact, tdata);
528         ao2_cleanup(contacts);
529
530         if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
531                 expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
532                 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
533         }
534
535         ast_sip_send_stateful_response(rdata, tdata, endpoint);
536
537         return PJ_TRUE;
538 }
539
540 static int register_aor(pjsip_rx_data *rdata,
541         struct ast_sip_endpoint *endpoint,
542         struct ast_sip_aor *aor,
543         const char *aor_name)
544 {
545         int res;
546         struct ao2_container *contacts = NULL;
547
548         ao2_lock(aor);
549         contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
550         if (!contacts) {
551                 ao2_unlock(aor);
552                 return PJ_TRUE;
553         }
554
555         res = register_aor_core(rdata, endpoint, aor, aor_name, contacts);
556         ao2_cleanup(contacts);
557         ao2_unlock(aor);
558
559         return res;
560 }
561
562 static int match_aor(const char *aor_name, const char *id)
563 {
564         if (ast_strlen_zero(aor_name)) {
565                 return 0;
566         }
567
568         if (!strcmp(aor_name, id)) {
569                 ast_debug(3, "Matched id '%s' to aor '%s'\n", id, aor_name);
570                 return 1;
571         }
572
573         return 0;
574 }
575
576 static char *find_aor_name(const char *username, const char *domain, const char *aors)
577 {
578         char *configured_aors;
579         char *aors_buf;
580         char *aor_name;
581         char *id_domain;
582         struct ast_sip_domain_alias *alias;
583
584         id_domain = ast_alloca(strlen(username) + strlen(domain) + 2);
585         sprintf(id_domain, "%s@%s", username, domain);
586
587         aors_buf = ast_strdupa(aors);
588
589         /* Look for exact match on username@domain */
590         configured_aors = aors_buf;
591         while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
592                 if (match_aor(aor_name, id_domain)) {
593                         return ast_strdup(aor_name);
594                 }
595         }
596
597         /* If there's a domain alias, look for exact match on username@domain_alias */
598         alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain);
599         if (alias) {
600                 char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2);
601
602                 sprintf(id_domain, "%s@%s", username, alias->domain);
603                 ao2_cleanup(alias);
604
605                 configured_aors = strcpy(aors_buf, aors);/* Safe */
606                 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
607                         if (match_aor(aor_name, id_domain_alias)) {
608                                 return ast_strdup(aor_name);
609                         }
610                 }
611         }
612
613         if (ast_strlen_zero(username)) {
614                 /* No username, no match */
615                 return NULL;
616         }
617
618         /* Look for exact match on username only */
619         configured_aors = strcpy(aors_buf, aors);/* Safe */
620         while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
621                 if (match_aor(aor_name, username)) {
622                         return ast_strdup(aor_name);
623                 }
624         }
625
626         return NULL;
627 }
628
629 static struct ast_sip_aor *find_registrar_aor(struct pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint)
630 {
631         struct ast_sip_aor *aor = NULL;
632         char *aor_name = NULL;
633         char *domain_name;
634         char *username = NULL;
635         int i;
636
637         for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); ++i) {
638                 pjsip_sip_uri *uri;
639                 pjsip_authorization_hdr *header = NULL;
640
641                 switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) {
642                 case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME:
643                         uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
644
645                         domain_name = ast_alloca(uri->host.slen + 1);
646                         ast_copy_pj_str(domain_name, &uri->host, uri->host.slen + 1);
647                         username = ast_alloca(uri->user.slen + 1);
648                         ast_copy_pj_str(username, &uri->user, uri->user.slen + 1);
649
650                         /*
651                          * We may want to match without any user options getting
652                          * in the way.
653                          */
654                         AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(username);
655
656                         aor_name = find_aor_name(username, domain_name, endpoint->aors);
657                         if (aor_name) {
658                                 ast_debug(3, "Matched aor '%s' by To username\n", aor_name);
659                         }
660                         break;
661                 case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME:
662                         while ((header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION,
663                                 header ? header->next : NULL))) {
664                                 if (header && !pj_stricmp2(&header->scheme, "digest")) {
665                                         username = ast_alloca(header->credential.digest.username.slen + 1);
666                                         ast_copy_pj_str(username, &header->credential.digest.username, header->credential.digest.username.slen + 1);
667                                         domain_name = ast_alloca(header->credential.digest.realm.slen + 1);
668                                         ast_copy_pj_str(domain_name, &header->credential.digest.realm, header->credential.digest.realm.slen + 1);
669
670                                         aor_name = find_aor_name(username, domain_name, endpoint->aors);
671                                         if (aor_name) {
672                                                 ast_debug(3, "Matched aor '%s' by Authentication username\n", aor_name);
673                                                 break;
674                                         }
675                                 }
676                         }
677                         break;
678                 default:
679                         continue;
680                 }
681
682                 if (aor_name) {
683                         break;
684                 }
685         }
686
687         if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
688                 /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
689                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
690                 ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
691                 ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n",
692                         username ?: "", ast_sorcery_object_get_id(endpoint));
693         }
694         ast_free(aor_name);
695         return aor;
696 }
697
698 static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
699 {
700         RAII_VAR(struct ast_sip_endpoint *, endpoint,
701                  ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
702         struct ast_sip_aor *aor;
703         const char *aor_name;
704
705         if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
706                 return PJ_FALSE;
707         }
708
709         if (ast_strlen_zero(endpoint->aors)) {
710                 /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
711                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
712                 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
713                 ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint));
714                 return PJ_TRUE;
715         }
716
717         if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
718                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
719                 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
720                 ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint));
721                 return PJ_TRUE;
722         }
723
724         aor = find_registrar_aor(rdata, endpoint);
725         if (!aor) {
726                 /* We've already responded about not finding an AOR. */
727                 return PJ_TRUE;
728         }
729
730         aor_name = ast_sorcery_object_get_id(aor);
731
732         if (!aor->max_contacts) {
733                 /* Registration is not permitted for this AOR */
734                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
735                 ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
736                 ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n",
737                         aor_name, ast_sorcery_object_get_id(endpoint));
738         } else {
739                 register_aor(rdata, endpoint, aor, aor_name);
740         }
741         ao2_ref(aor, -1);
742         return PJ_TRUE;
743 }
744
745 /* function pointer to callback needs to be within the module
746    in order to avoid problems with an undefined symbol */
747 static int sip_contact_to_str(void *acp, void *arg, int flags)
748 {
749         return ast_sip_contact_to_str(acp, arg, flags);
750 }
751
752 static int ami_registrations_aor(void *obj, void *arg, int flags)
753 {
754         struct ast_sip_aor *aor = obj;
755         struct ast_sip_ami *ami = arg;
756         int *count = ami->arg;
757         RAII_VAR(struct ast_str *, buf,
758                  ast_sip_create_ami_event("InboundRegistrationDetail", ami), ast_free);
759
760         if (!buf) {
761                 return -1;
762         }
763
764         ast_sip_sorcery_object_to_ami(aor, &buf);
765         ast_str_append(&buf, 0, "Contacts: ");
766         ast_sip_for_each_contact(aor, sip_contact_to_str, &buf);
767         ast_str_append(&buf, 0, "\r\n");
768
769         astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
770         (*count)++;
771         return 0;
772 }
773
774 static int ami_registrations_endpoint(void *obj, void *arg, int flags)
775 {
776         struct ast_sip_endpoint *endpoint = obj;
777         return ast_sip_for_each_aor(
778                 endpoint->aors, ami_registrations_aor, arg);
779 }
780
781 static int ami_registrations_endpoints(void *arg)
782 {
783         RAII_VAR(struct ao2_container *, endpoints,
784                  ast_sip_get_endpoints(), ao2_cleanup);
785
786         if (!endpoints) {
787                 return 0;
788         }
789
790         ao2_callback(endpoints, OBJ_NODATA, ami_registrations_endpoint, arg);
791         return 0;
792 }
793
794 static int ami_show_registrations(struct mansession *s, const struct message *m)
795 {
796         int count = 0;
797         struct ast_sip_ami ami = { .s = s, .m = m, .arg = &count, .action_id = astman_get_header(m, "ActionID"), };
798
799         astman_send_listack(s, m, "Following are Events for each Inbound registration",
800                 "start");
801
802         ami_registrations_endpoints(&ami);
803
804         astman_send_list_complete_start(s, m, "InboundRegistrationDetailComplete", count);
805         astman_send_list_complete_end(s);
806         return 0;
807 }
808
809 static int ami_show_registration_contact_statuses(struct mansession *s, const struct message *m)
810 {
811         int count = 0;
812         struct ast_sip_ami ami = { .s = s, .m = m, .arg = NULL, .action_id = astman_get_header(m, "ActionID"), };
813         struct ao2_container *contacts = ast_sorcery_retrieve_by_fields(
814                 ast_sip_get_sorcery(), "contact", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
815         struct ao2_iterator i;
816         struct ast_sip_contact *contact;
817
818         astman_send_listack(s, m, "Following are ContactStatusEvents for each Inbound "
819                             "registration", "start");
820
821         if (contacts) {
822                 i = ao2_iterator_init(contacts, 0);
823                 while ((contact = ao2_iterator_next(&i))) {
824                         struct ast_sip_contact_wrapper wrapper;
825
826                         wrapper.aor_id = (char *)contact->aor;
827                         wrapper.contact = contact;
828                         wrapper.contact_id = (char *)ast_sorcery_object_get_id(contact);
829
830                         ast_sip_format_contact_ami(&wrapper, &ami, 0);
831                         count++;
832
833                         ao2_ref(contact, -1);
834                 }
835                 ao2_iterator_destroy(&i);
836                 ao2_ref(contacts, -1);
837         }
838
839         astman_send_list_complete_start(s, m, "ContactStatusDetailComplete", count);
840         astman_send_list_complete_end(s);
841         return 0;
842 }
843
844 #define AMI_SHOW_REGISTRATION_CONTACT_STATUSES "PJSIPShowRegistrationInboundContactStatuses"
845 #define AMI_SHOW_REGISTRATIONS "PJSIPShowRegistrationsInbound"
846
847 static pjsip_module registrar_module = {
848         .name = { "Registrar", 9 },
849         .id = -1,
850         .priority = PJSIP_MOD_PRIORITY_APPLICATION,
851         .on_rx_request = registrar_on_rx_request,
852 };
853
854 static int load_module(void)
855 {
856         const pj_str_t STR_REGISTER = { "REGISTER", 8 };
857
858         CHECK_PJPROJECT_MODULE_LOADED();
859
860         ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
861         /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
862         ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
863
864         CHECK_PJSIP_MODULE_LOADED();
865
866         if (ast_sip_register_service(&registrar_module)) {
867                 return AST_MODULE_LOAD_DECLINE;
868         }
869
870         if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
871                 ast_sip_unregister_service(&registrar_module);
872                 return AST_MODULE_LOAD_DECLINE;
873         }
874
875         ast_manager_register_xml(AMI_SHOW_REGISTRATIONS, EVENT_FLAG_SYSTEM,
876                                  ami_show_registrations);
877         ast_manager_register_xml(AMI_SHOW_REGISTRATION_CONTACT_STATUSES, EVENT_FLAG_SYSTEM,
878                                  ami_show_registration_contact_statuses);
879
880         return AST_MODULE_LOAD_SUCCESS;
881 }
882
883 static int unload_module(void)
884 {
885         ast_manager_unregister(AMI_SHOW_REGISTRATIONS);
886         ast_manager_unregister(AMI_SHOW_REGISTRATION_CONTACT_STATUSES);
887         ast_sip_unregister_service(&registrar_module);
888         return 0;
889 }
890
891 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Registrar Support",
892         .support_level = AST_MODULE_SUPPORT_CORE,
893         .load = load_module,
894         .unload = unload_module,
895         .load_pri = AST_MODPRI_CHANNEL_DEPEND - 3,
896 );