2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * Joshua Colp <jcolp@digium.com>
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.
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.
20 <depend>pjproject</depend>
21 <depend>res_pjproject</depend>
22 <depend>res_pjsip</depend>
23 <support_level>core</support_level>
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"
42 <manager name="PJSIPShowRegistrationsInbound" language="en_US">
44 Lists PJSIP inbound registrations.
49 In response <literal>InboundRegistrationDetail</literal> events showing configuration and status
50 information are raised for each inbound registration object. As well as <literal>AuthDetail</literal>
51 events for each associated auth object. Once all events are completed an
52 <literal>InboundRegistrationDetailComplete</literal> is issued.
58 static int pj_max_hostname = PJ_MAX_HOSTNAME;
59 static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE;
61 /*! \brief Internal function which returns the expiration time for a contact */
62 static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
64 pjsip_expires_hdr *expires;
65 int expiration = aor->default_expiration;
67 if (contact && contact->expires != -1) {
68 /* Expiration was provided with the contact itself */
69 expiration = contact->expires;
70 } else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
71 /* Expiration was provided using the Expires header */
72 expiration = expires->ivalue;
75 /* If the value has explicitly been set to 0, do not enforce */
80 /* Enforce the range that we will allow for expiration */
81 if (expiration < aor->minimum_expiration) {
82 expiration = aor->minimum_expiration;
83 } else if (expiration > aor->maximum_expiration) {
84 expiration = aor->maximum_expiration;
90 /*! \brief Structure used for finding contact */
91 struct registrar_contact_details {
92 /*! \brief Pool used for parsing URI */
94 /*! \brief URI being looked for */
98 /*! \brief Callback function for finding a contact */
99 static int registrar_find_contact(void *obj, void *arg, int flags)
101 struct ast_sip_contact *contact = obj;
102 const struct registrar_contact_details *details = arg;
103 pjsip_uri *contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
105 return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH | CMP_STOP : 0;
108 /*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
109 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)
111 pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
112 struct registrar_contact_details details = {
113 .pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256),
120 while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
121 int expiration = registrar_get_expiration(aor, contact, rdata);
122 RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup);
123 char contact_uri[pjsip_max_url_size];
126 /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
127 if ((expiration != 0) || previous) {
128 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
132 } else if (previous && previous->star) {
133 /* If there is a previous contact and it is a '*' this is a deal breaker */
134 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
139 if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
143 details.uri = pjsip_uri_get_uri(contact->uri);
145 /* pjsip_uri_print returns -1 if there's not enough room in the buffer */
146 if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
147 /* If the total length of the uri is greater than pjproject can handle, go no further */
148 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
152 if (details.uri->host.slen >= pj_max_hostname) {
153 /* If the length of the hostname is greater than pjproject can handle, go no further */
154 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
158 /* Determine if this is an add, update, or delete for policy enforcement purposes */
159 if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) {
163 } else if (expiration) {
170 /* The provided contacts are acceptable, huzzah! */
171 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
175 /*! \brief Callback function which prunes static contacts */
176 static int registrar_prune_static(void *obj, void *arg, int flags)
178 struct ast_sip_contact *contact = obj;
180 return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
183 /*! \brief Internal function used to delete a contact from an AOR */
184 static int registrar_delete_contact(void *obj, void *arg, int flags)
186 struct ast_sip_contact *contact = obj;
187 const char *aor_name = arg;
189 ast_sip_location_delete_contact(contact);
190 if (!ast_strlen_zero(aor_name)) {
191 ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name);
192 ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
198 contact->user_agent);
204 /*! \brief Internal function which adds a contact to a response */
205 static int registrar_add_contact(void *obj, void *arg, int flags)
207 struct ast_sip_contact *contact = obj;
208 pjsip_tx_data *tdata = arg;
209 pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
212 pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
213 hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
214 hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;
216 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
221 /*! \brief Helper function which adds a Date header to a response */
222 static void registrar_add_date_header(pjsip_tx_data *tdata)
226 time_t t = time(NULL);
229 strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);
231 ast_sip_add_header(tdata, "Date", date);
234 static const pj_str_t path_hdr_name = { "Path", 4 };
236 static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str)
238 pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, NULL);
244 *path_str = ast_str_create(64);
249 ast_str_set(path_str, 0, "%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
251 while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) {
252 ast_str_append(path_str, 0, ",%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
258 static int registrar_validate_path(pjsip_rx_data *rdata, struct ast_sip_aor *aor, struct ast_str **path_str)
260 const pj_str_t path_supported_name = { "path", 4 };
261 pjsip_supported_hdr *supported_hdr;
264 if (!aor->support_path) {
268 if (build_path_data(rdata, path_str)) {
276 supported_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL);
277 if (!supported_hdr) {
281 /* Find advertised path support */
282 for (i = 0; i < supported_hdr->count; i++) {
283 if (!pj_stricmp(&supported_hdr->values[i], &path_supported_name)) {
288 /* Path header present, but support not advertised */
292 static int register_aor_core(pjsip_rx_data *rdata,
293 struct ast_sip_endpoint *endpoint,
294 struct ast_sip_aor *aor,
295 const char *aor_name,
296 struct ao2_container *contacts)
298 static const pj_str_t USER_AGENT = { "User-Agent", 10 };
300 int added = 0, updated = 0, deleted = 0;
301 pjsip_contact_hdr *contact_hdr = NULL;
302 struct registrar_contact_details details = { 0, };
303 pjsip_tx_data *tdata;
304 RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
305 struct ast_sip_contact *response_contact;
306 char *user_agent = NULL;
307 pjsip_user_agent_hdr *user_agent_hdr;
308 pjsip_expires_hdr *expires_hdr;
309 pjsip_via_hdr *via_hdr;
310 pjsip_via_hdr *via_hdr_last;
311 char *via_addr = NULL;
313 pjsip_cid_hdr *call_id_hdr;
314 char *call_id = NULL;
317 /* So we don't count static contacts against max_contacts we prune them out from the container */
318 ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
320 if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) {
321 /* The provided Contact headers do not conform to the specification */
322 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
323 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
324 ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
325 ast_sorcery_object_get_id(endpoint));
329 if (registrar_validate_path(rdata, aor, &path_str)) {
330 /* Ensure that intervening proxies did not make invalid modifications to the request */
331 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 420, NULL, NULL, NULL);
332 ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
333 ast_sorcery_object_get_id(endpoint));
337 if ((MAX(added - deleted, 0) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) {
338 /* Enforce the maximum number of contacts */
339 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
340 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
341 ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n",
342 ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts);
346 if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) {
347 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
351 user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL);
352 if (user_agent_hdr) {
353 alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
354 user_agent = ast_alloca(alloc_size);
355 ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
358 /* Find the first Via header */
359 via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
361 /* Find the last Via header */
362 while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
363 PJSIP_H_VIA, via_hdr->next)) != NULL) {
364 via_hdr_last = via_hdr;
366 alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
367 via_addr = ast_alloca(alloc_size);
368 ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size);
369 via_port=via_hdr_last->sent_by.port;
372 call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL);
374 alloc_size = pj_strlen(&call_id_hdr->id) + 1;
375 call_id = ast_alloca(alloc_size);
376 ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size);
379 /* Iterate each provided Contact header and add, update, or delete */
380 while ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
382 char contact_uri[pjsip_max_url_size];
383 RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
385 if (contact_hdr->star) {
386 /* A star means to unregister everything, so do so for the possible contacts */
387 ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name);
391 if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
392 /* This registrar only currently supports sip: and sips: URI schemes */
396 expiration = registrar_get_expiration(aor, contact_hdr, rdata);
397 details.uri = pjsip_uri_get_uri(contact_hdr->uri);
398 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
400 if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) {
401 /* If they are actually trying to delete a contact that does not exist... be forgiving */
403 ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
404 contact_uri, aor_name);
408 if (ast_sip_location_add_contact_nolock(aor, contact_uri, ast_tvadd(ast_tvnow(),
409 ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL,
410 user_agent, via_addr, via_port, call_id, endpoint)) {
411 ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
412 contact_uri, aor_name);
416 ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
417 contact_uri, aor_name, expiration);
418 ast_test_suite_event_notify("AOR_CONTACT_ADDED",
427 } else if (expiration) {
428 struct ast_sip_contact *contact_update;
430 contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact);
431 if (!contact_update) {
432 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
433 contact->uri, expiration);
437 contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
438 contact_update->qualify_frequency = aor->qualify_frequency;
439 contact_update->authenticate_qualify = aor->authenticate_qualify;
441 ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
444 ast_string_field_set(contact_update, user_agent, user_agent);
446 if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
447 ast_string_field_set(contact_update, reg_server, ast_config_AST_SYSTEM_NAME);
450 if (ast_sip_location_update_contact(contact_update)) {
451 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
452 contact->uri, expiration);
453 ast_sip_location_delete_contact(contact);
456 ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
457 contact_uri, aor_name, expiration);
458 ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
466 contact_update->user_agent);
467 ao2_cleanup(contact_update);
469 /* We want to report the user agent that was actually in the removed contact */
470 ast_sip_location_delete_contact(contact);
471 ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
472 ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
478 contact->user_agent);
482 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
484 /* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
487 if (aor->remove_existing) {
488 ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
491 /* Re-retrieve contacts. Caller will clean up the original container. */
492 contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
493 response_contact = ao2_callback(contacts, 0, NULL, NULL);
495 /* Send a response containing all of the contacts (including static) that are present on this AOR */
496 if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
497 ao2_cleanup(response_contact);
498 ao2_cleanup(contacts);
501 ao2_cleanup(response_contact);
503 /* Add the date header to the response, some UAs use this to set their date and time */
504 registrar_add_date_header(tdata);
506 ao2_callback(contacts, 0, registrar_add_contact, tdata);
507 ao2_cleanup(contacts);
509 if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
510 expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
511 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
514 ast_sip_send_stateful_response(rdata, tdata, endpoint);
519 static int register_aor(pjsip_rx_data *rdata,
520 struct ast_sip_endpoint *endpoint,
521 struct ast_sip_aor *aor,
522 const char *aor_name)
525 struct ao2_container *contacts = NULL;
528 contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
534 res = register_aor_core(rdata, endpoint, aor, aor_name, contacts);
535 ao2_cleanup(contacts);
541 static int match_aor(const char *aor_name, const char *id)
543 if (ast_strlen_zero(aor_name)) {
547 if (!strcmp(aor_name, id)) {
548 ast_debug(3, "Matched id '%s' to aor '%s'\n", id, aor_name);
555 static char *find_aor_name(const char *username, const char *domain, const char *aors)
557 char *configured_aors;
561 struct ast_sip_domain_alias *alias;
563 id_domain = ast_alloca(strlen(username) + strlen(domain) + 2);
564 sprintf(id_domain, "%s@%s", username, domain);
566 aors_buf = ast_strdupa(aors);
568 /* Look for exact match on username@domain */
569 configured_aors = aors_buf;
570 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
571 if (match_aor(aor_name, id_domain)) {
572 return ast_strdup(aor_name);
576 /* If there's a domain alias, look for exact match on username@domain_alias */
577 alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain);
579 char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2);
581 sprintf(id_domain, "%s@%s", username, alias->domain);
584 configured_aors = strcpy(aors_buf, aors);/* Safe */
585 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
586 if (match_aor(aor_name, id_domain_alias)) {
587 return ast_strdup(aor_name);
592 if (ast_strlen_zero(username)) {
593 /* No username, no match */
597 /* Look for exact match on username only */
598 configured_aors = strcpy(aors_buf, aors);/* Safe */
599 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
600 if (match_aor(aor_name, username)) {
601 return ast_strdup(aor_name);
608 static struct ast_sip_aor *find_registrar_aor(struct pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint)
610 struct ast_sip_aor *aor = NULL;
611 char *aor_name = NULL;
613 char *username = NULL;
616 for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); ++i) {
618 pjsip_authorization_hdr *header = NULL;
620 switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) {
621 case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME:
622 uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
624 domain_name = ast_alloca(uri->host.slen + 1);
625 ast_copy_pj_str(domain_name, &uri->host, uri->host.slen + 1);
626 username = ast_alloca(uri->user.slen + 1);
627 ast_copy_pj_str(username, &uri->user, uri->user.slen + 1);
629 aor_name = find_aor_name(username, domain_name, endpoint->aors);
631 ast_debug(3, "Matched aor '%s' by To username\n", aor_name);
634 case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME:
635 while ((header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION,
636 header ? header->next : NULL))) {
637 if (header && !pj_stricmp2(&header->scheme, "digest")) {
638 username = ast_alloca(header->credential.digest.username.slen + 1);
639 ast_copy_pj_str(username, &header->credential.digest.username, header->credential.digest.username.slen + 1);
640 domain_name = ast_alloca(header->credential.digest.realm.slen + 1);
641 ast_copy_pj_str(domain_name, &header->credential.digest.realm, header->credential.digest.realm.slen + 1);
643 aor_name = find_aor_name(username, domain_name, endpoint->aors);
645 ast_debug(3, "Matched aor '%s' by Authentication username\n", aor_name);
660 if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
661 /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
662 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
663 ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
664 ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n",
665 username ?: "", ast_sorcery_object_get_id(endpoint));
671 static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
673 RAII_VAR(struct ast_sip_endpoint *, endpoint,
674 ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
675 struct ast_sip_aor *aor;
676 const char *aor_name;
678 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
682 if (ast_strlen_zero(endpoint->aors)) {
683 /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
684 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
685 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
686 ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint));
690 if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
691 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
692 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
693 ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint));
697 aor = find_registrar_aor(rdata, endpoint);
699 /* We've already responded about not finding an AOR. */
703 aor_name = ast_sorcery_object_get_id(aor);
705 if (!aor->max_contacts) {
706 /* Registration is not permitted for this AOR */
707 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
708 ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
709 ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n",
710 aor_name, ast_sorcery_object_get_id(endpoint));
712 register_aor(rdata, endpoint, aor, aor_name);
718 /* function pointer to callback needs to be within the module
719 in order to avoid problems with an undefined symbol */
720 static int sip_contact_to_str(void *acp, void *arg, int flags)
722 return ast_sip_contact_to_str(acp, arg, flags);
725 static int ami_registrations_aor(void *obj, void *arg, int flags)
727 struct ast_sip_aor *aor = obj;
728 struct ast_sip_ami *ami = arg;
729 int *count = ami->arg;
730 RAII_VAR(struct ast_str *, buf,
731 ast_sip_create_ami_event("InboundRegistrationDetail", ami), ast_free);
737 ast_sip_sorcery_object_to_ami(aor, &buf);
738 ast_str_append(&buf, 0, "Contacts: ");
739 ast_sip_for_each_contact(aor, sip_contact_to_str, &buf);
740 ast_str_append(&buf, 0, "\r\n");
742 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
747 static int ami_registrations_endpoint(void *obj, void *arg, int flags)
749 struct ast_sip_endpoint *endpoint = obj;
750 return ast_sip_for_each_aor(
751 endpoint->aors, ami_registrations_aor, arg);
754 static int ami_registrations_endpoints(void *arg)
756 RAII_VAR(struct ao2_container *, endpoints,
757 ast_sip_get_endpoints(), ao2_cleanup);
763 ao2_callback(endpoints, OBJ_NODATA, ami_registrations_endpoint, arg);
767 static int ami_show_registrations(struct mansession *s, const struct message *m)
770 struct ast_sip_ami ami = { .s = s, .m = m, .arg = &count, .action_id = astman_get_header(m, "ActionID"), };
772 astman_send_listack(s, m, "Following are Events for each Inbound registration",
775 ami_registrations_endpoints(&ami);
777 astman_send_list_complete_start(s, m, "InboundRegistrationDetailComplete", count);
778 astman_send_list_complete_end(s);
782 #define AMI_SHOW_REGISTRATIONS "PJSIPShowRegistrationsInbound"
784 static pjsip_module registrar_module = {
785 .name = { "Registrar", 9 },
787 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
788 .on_rx_request = registrar_on_rx_request,
791 static int load_module(void)
793 const pj_str_t STR_REGISTER = { "REGISTER", 8 };
795 CHECK_PJPROJECT_MODULE_LOADED();
797 ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
798 /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
799 ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
801 CHECK_PJSIP_MODULE_LOADED();
803 if (ast_sip_register_service(®istrar_module)) {
804 return AST_MODULE_LOAD_DECLINE;
807 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
808 ast_sip_unregister_service(®istrar_module);
809 return AST_MODULE_LOAD_DECLINE;
812 ast_manager_register_xml(AMI_SHOW_REGISTRATIONS, EVENT_FLAG_SYSTEM,
813 ami_show_registrations);
815 return AST_MODULE_LOAD_SUCCESS;
818 static int unload_module(void)
820 ast_manager_unregister(AMI_SHOW_REGISTRATIONS);
821 ast_sip_unregister_service(®istrar_module);
825 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Registrar Support",
826 .support_level = AST_MODULE_SUPPORT_CORE,
828 .unload = unload_module,
829 .load_pri = AST_MODPRI_CHANNEL_DEPEND - 3,