int ast_sip_for_each_auth(const struct ast_sip_auth_vector *vector, ao2_callback_fn on_auth, void *arg) { int i; if (!vector || !AST_VECTOR_SIZE(vector)) { return 0; } for (i = 0; i < AST_VECTOR_SIZE(vector); ++i) { /* AST_VECTOR_GET is safe to use since the vector is immutable */ RAII_VAR(struct ast_sip_auth *, auth, ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, AST_VECTOR_GET(vector,i)), ao2_cleanup); if (!auth) { continue; } if (on_auth(auth, arg, 0)) { return -1; } } return 0; }
/*! * \brief Verifies a user event header/value pair * * \param user_event which user event to check * \param header The header to verify * \param value The value read from the event * * \retval -1 on error or evaluation failure * \retval 0 if match not needed or success */ static int verify_user_event_fields(int user_event, const char *header, const char *value) { struct ast_variable *current; struct ast_variable *expected; regex_t regexbuf; int error; if (user_event >= AST_VECTOR_SIZE(&expected_user_event_fields)) { return -1; } expected = AST_VECTOR_GET(&expected_user_event_fields, user_event); if (!expected) { return -1; } for (current = expected; current; current = current->next) { struct ast_variable *bad_header; if (strcmp(current->name, header)) { continue; } error = regcomp(®exbuf, current->value, REG_EXTENDED | REG_NOSUB); if (error) { char error_buf[128]; regerror(error, ®exbuf, error_buf, sizeof(error_buf)); ast_log(LOG_ERROR, "Failed to compile regex '%s' for header check '%s': %s\n", current->value, current->name, error_buf); return -1; } if (!regexec(®exbuf, value, 0, NULL, 0)) { regfree(®exbuf); return 0; } bad_header = ast_variable_new(header, value, __FILE__); if (bad_header) { struct ast_variable *bad_headers_head = NULL; if (user_event < AST_VECTOR_SIZE(&bad_headers)) { bad_headers_head = AST_VECTOR_GET(&bad_headers, user_event); } ast_variable_list_append(&bad_headers_head, bad_header); AST_VECTOR_INSERT(&bad_headers, user_event, bad_headers_head); } regfree(®exbuf); return -1; } return 0; }
/*! * \brief Explicitly shutdown a session. * * \details An explicit shutdown is necessary, since the \ref stasis_app has a reference * to this session. We also need to be sure to null out the \c ws_session field, * since the websocket is about to go away. * * \internal * * \param session Event session object (\ref event_session). */ static void event_session_shutdown(struct event_session *session) { struct ao2_iterator i; char *app; int j; SCOPED_AO2LOCK(lock, session); /* Clean up the websocket_apps container */ if (session->websocket_apps) { i = ao2_iterator_init(session->websocket_apps, 0); while ((app = ao2_iterator_next(&i))) { stasis_app_unregister(app); ao2_cleanup(app); } ao2_iterator_destroy(&i); ao2_cleanup(session->websocket_apps); session->websocket_apps = NULL; } /* Clean up the message_queue container */ for (j = 0; j < AST_VECTOR_SIZE(&session->message_queue); j++) { struct ast_json *msg = AST_VECTOR_GET(&session->message_queue, j); ast_json_unref(msg); } AST_VECTOR_FREE(&session->message_queue); /* Remove the handle to the underlying websocket session */ session->ws_session = NULL; }
int __ast_string_fields_cmp(struct ast_string_field_vector *left, struct ast_string_field_vector *right) { int i; int res = 0; ast_assert(AST_VECTOR_SIZE(left) == AST_VECTOR_SIZE(right)); for (i = 0; i < AST_VECTOR_SIZE(left); i++) { if ((res = strcmp(*AST_VECTOR_GET(left, i), *AST_VECTOR_GET(right, i)))) { return res; } } return res; }
struct stasis_forward *stasis_forward_cancel(struct stasis_forward *forward) { int idx; struct stasis_topic *from; struct stasis_topic *to; if (!forward) { return NULL; } from = forward->from_topic; to = forward->to_topic; if (from && to) { topic_lock_both(to, from); AST_VECTOR_REMOVE_ELEM_UNORDERED(&to->upstream_topics, from, AST_VECTOR_ELEM_CLEANUP_NOOP); for (idx = 0; idx < AST_VECTOR_SIZE(&to->subscribers); ++idx) { topic_remove_subscription(from, AST_VECTOR_GET(&to->subscribers, idx)); } ao2_unlock(from); ao2_unlock(to); } ao2_cleanup(forward); return NULL; }
/*! * \internal * \brief Remove excess existing contacts that expire the soonest. * \since 13.18.0 * * \param contacts Container of unmodified contacts that could remove. * \param to_remove Maximum number of contacts to remove. * * \return Nothing */ static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_container *response_contacts, unsigned int to_remove) { struct excess_contact_vector contact_vec; /* * Create a sorted vector to hold the to_remove soonest to * expire contacts. The vector has an extra space to * temporarily hold the longest to expire contact that we * won't remove. */ if (AST_VECTOR_INIT(&contact_vec, to_remove + 1)) { return; } ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, vec_contact_add, &contact_vec); /* * The vector should always be populated with the number * of contacts we need to remove. Just in case, we will * remove all contacts in the vector even if the contacts * container had fewer contacts than there should be. */ ast_assert(AST_VECTOR_SIZE(&contact_vec) == to_remove); to_remove = AST_VECTOR_SIZE(&contact_vec); /* Remove the excess contacts that expire the soonest */ while (to_remove--) { struct ast_sip_contact *contact; contact = AST_VECTOR_GET(&contact_vec, to_remove); ast_sip_location_delete_contact(contact); ast_verb(3, "Removed contact '%s' from AOR '%s' due to remove_existing\n", contact->uri, contact->aor); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", "Contact: %s\r\n" "AOR: %s\r\n" "UserAgent: %s", contact->uri, contact->aor, contact->user_agent); ao2_unlink(response_contacts, contact); } AST_VECTOR_FREE(&contact_vec); }
/*! * \brief Check authentication using Digest scheme * * This function will check an incoming message against configured authentication * options. If \b any of the incoming Authorization headers result in successful * authentication, then authentication is considered successful. * * \see ast_sip_check_authentication */ static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata) { struct ast_sip_auth **auths; enum digest_verify_result *verify_res; enum ast_sip_check_auth_result res; int i; int failures = 0; size_t auth_size; RAII_VAR(struct ast_sip_endpoint *, artificial_endpoint, ast_sip_get_artificial_endpoint(), ao2_cleanup); auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths); auths = ast_alloca(auth_size * sizeof(*auths)); verify_res = ast_alloca(auth_size * sizeof(*verify_res)); if (!auths) { return AST_SIP_AUTHENTICATION_ERROR; } if (endpoint == artificial_endpoint) { auths[0] = ast_sip_get_artificial_auth(); } else if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) { res = AST_SIP_AUTHENTICATION_ERROR; goto cleanup; } for (i = 0; i < auth_size; ++i) { if (ast_strlen_zero(auths[i]->realm)) { ast_string_field_set(auths[i], realm, "asterisk"); } verify_res[i] = verify(auths[i], rdata, tdata->pool); if (verify_res[i] == AUTH_SUCCESS) { res = AST_SIP_AUTHENTICATION_SUCCESS; goto cleanup; } if (verify_res[i] == AUTH_FAIL) { failures++; } } for (i = 0; i < auth_size; ++i) { challenge(auths[i]->realm, tdata, rdata, verify_res[i] == AUTH_STALE); } if (failures == auth_size) { res = AST_SIP_AUTHENTICATION_FAILED; } else { res = AST_SIP_AUTHENTICATION_CHALLENGE; } cleanup: ast_sip_cleanup_auths(auths, auth_size); return res; }
static void route_table_dtor(struct route_table *table) { size_t idx; struct stasis_message_route *route; for (idx = 0; idx < AST_VECTOR_SIZE(table); ++idx) { route = AST_VECTOR_GET_ADDR(table, idx); ROUTE_TABLE_ELEM_CLEANUP(*route); } AST_VECTOR_FREE(table); }
/*! * \brief Event session object destructor (\ref event_session). * * \internal * * \param obj Void pointer to the \ref event_session object. */ static void event_session_dtor(void *obj) { #ifdef AST_DEVMODE /* Avoid unused variable warning */ struct event_session *session = obj; #endif /* event_session_shutdown should have been called before now */ ast_assert(session->ws_session == NULL); ast_assert(session->websocket_apps == NULL); ast_assert(AST_VECTOR_SIZE(&session->message_queue) == 0); }
static int topic_remove_subscription(struct stasis_topic *topic, struct stasis_subscription *sub) { size_t idx; SCOPED_AO2LOCK(lock_topic, topic); for (idx = 0; idx < AST_VECTOR_SIZE(&topic->upstream_topics); ++idx) { topic_remove_subscription( AST_VECTOR_GET(&topic->upstream_topics, idx), sub); } return AST_VECTOR_REMOVE_ELEM_UNORDERED(&topic->subscribers, sub, AST_VECTOR_ELEM_CLEANUP_NOOP); }
static int set_outbound_authentication_credentials(pjsip_auth_clt_sess *auth_sess, const struct ast_sip_auth_vector *auth_vector, pjsip_rx_data *challenge) { size_t auth_size = AST_VECTOR_SIZE(auth_vector); struct ast_sip_auth **auths = ast_alloca(auth_size * sizeof(*auths)); pjsip_cred_info *auth_creds = ast_alloca(auth_size * sizeof(*auth_creds)); pjsip_www_authenticate_hdr *auth_hdr = NULL; int res = 0; int i; if (ast_sip_retrieve_auths(auth_vector, auths)) { res = -1; goto cleanup; } auth_hdr = get_auth_header(challenge); if (auth_hdr == NULL) { res = -1; ast_log(LOG_ERROR, "Unable to find authenticate header in challenge.\n"); goto cleanup; } for (i = 0; i < auth_size; ++i) { if (ast_strlen_zero(auths[i]->realm)) { auth_creds[i].realm = auth_hdr->challenge.common.realm; } else { pj_cstr(&auth_creds[i].realm, auths[i]->realm); } pj_cstr(&auth_creds[i].username, auths[i]->auth_user); pj_cstr(&auth_creds[i].scheme, "digest"); switch (auths[i]->type) { case AST_SIP_AUTH_TYPE_USER_PASS: pj_cstr(&auth_creds[i].data, auths[i]->auth_pass); auth_creds[i].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; break; case AST_SIP_AUTH_TYPE_MD5: pj_cstr(&auth_creds[i].data, auths[i]->md5_creds); auth_creds[i].data_type = PJSIP_CRED_DATA_DIGEST; break; case AST_SIP_AUTH_TYPE_ARTIFICIAL: ast_log(LOG_ERROR, "Trying to set artificial outbound auth credentials shouldn't happen.\n"); break; } } pjsip_auth_clt_set_credentials(auth_sess, auth_size, auth_creds); cleanup: ast_sip_cleanup_auths(auths, auth_size); return res; }
int __ast_string_fields_copy(struct ast_string_field_pool *copy_pool, struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr) { int i; struct ast_string_field_vector *dest = &(copy_mgr->string_fields); struct ast_string_field_vector *src = &(orig_mgr->string_fields); ast_assert(AST_VECTOR_SIZE(dest) == AST_VECTOR_SIZE(src)); for (i = 0; i < AST_VECTOR_SIZE(dest); i++) { __ast_string_field_release_active(copy_pool, *AST_VECTOR_GET(dest, i)); *AST_VECTOR_GET(dest, i) = __ast_string_field_empty; } for (i = 0; i < AST_VECTOR_SIZE(dest); i++) { if (ast_string_field_ptr_set_by_fields(copy_pool, *copy_mgr, AST_VECTOR_GET(dest, i), *AST_VECTOR_GET(src, i))) { return -1; } } return 0; }
static void topic_dtor(void *obj) { struct stasis_topic *topic = obj; /* Subscribers hold a reference to topics, so they should all be * unsubscribed before we get here. */ ast_assert(AST_VECTOR_SIZE(&topic->subscribers) == 0); ast_free(topic->name); topic->name = NULL; AST_VECTOR_FREE(&topic->subscribers); AST_VECTOR_FREE(&topic->upstream_topics); }
/*! * \internal * \brief Destructor for \ref ast_multi_object_blob objects */ static void multi_object_blob_dtor(void *obj) { struct ast_multi_object_blob *multi = obj; int type; int i; for (type = 0; type < STASIS_UMOS_MAX; ++type) { for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) { ao2_cleanup(AST_VECTOR_GET(&multi->snapshots[type], i)); } AST_VECTOR_FREE(&multi->snapshots[type]); } ast_json_unref(multi->blob); }
static int vec_contact_add(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; struct excess_contact_vector *contact_vec = arg; /* * Performance wise, an insertion sort is fine because we * shouldn't need to remove more than a handful of contacts. * I expect we'll typically be removing only one contact. */ AST_VECTOR_ADD_SORTED(contact_vec, contact, vec_contact_cmp); if (AST_VECTOR_SIZE(contact_vec) == AST_VECTOR_MAX_SIZE(contact_vec)) { /* * We added a contact over the number we need to remove. * Remove the longest to expire contact from the vector * which is the last element in the vector. It may be * the one we just added or the one we just added pushed * out an earlier contact from removal consideration. */ --AST_VECTOR_SIZE(contact_vec); } return 0; }
/*! \internal \brief convert multi object blob to ari json */ static struct ast_json *multi_user_event_to_json( struct stasis_message *message, const struct stasis_message_sanitizer *sanitize) { RAII_VAR(struct ast_json *, out, NULL, ast_json_unref); struct ast_multi_object_blob *multi = stasis_message_data(message); struct ast_json *blob = multi->blob; const struct timeval *tv = stasis_message_timestamp(message); enum stasis_user_multi_object_snapshot_type type; int i; out = ast_json_object_create(); if (!out) { return NULL; } ast_json_object_set(out, "type", ast_json_string_create("ChannelUserevent")); ast_json_object_set(out, "timestamp", ast_json_timeval(*tv, NULL)); ast_json_object_set(out, "eventname", ast_json_string_create(ast_json_string_get((ast_json_object_get(blob, "eventname"))))); ast_json_object_set(out, "userevent", ast_json_deep_copy(blob)); for (type = 0; type < STASIS_UMOS_MAX; ++type) { for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) { struct ast_json *json_object = NULL; char *name = NULL; void *snapshot = AST_VECTOR_GET(&multi->snapshots[type], i); switch (type) { case STASIS_UMOS_CHANNEL: json_object = ast_channel_snapshot_to_json(snapshot, sanitize); name = "channel"; break; case STASIS_UMOS_BRIDGE: json_object = ast_bridge_snapshot_to_json(snapshot, sanitize); name = "bridge"; break; case STASIS_UMOS_ENDPOINT: json_object = ast_endpoint_snapshot_to_json(snapshot, sanitize); name = "endpoint"; break; } if (json_object) { ast_json_object_set(out, name, json_object); } } } return ast_json_ref(out); }
/*! \internal \brief convert multi object blob to ami string */ static struct ast_str *multi_object_blob_to_ami(void *obj) { struct ast_str *ami_str=ast_str_create(1024); struct ast_str *ami_snapshot; const struct ast_multi_object_blob *multi = obj; enum stasis_user_multi_object_snapshot_type type; int i; if (!ami_str) { return NULL; } if (!multi) { ast_free(ami_str); return NULL; } for (type = 0; type < STASIS_UMOS_MAX; ++type) { for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) { char *name = ""; void *snapshot = AST_VECTOR_GET(&multi->snapshots[type], i); ami_snapshot = NULL; if (i > 0) { ast_asprintf(&name, "%d", i + 1); } switch (type) { case STASIS_UMOS_CHANNEL: ami_snapshot = ast_manager_build_channel_state_string_prefix(snapshot, name); break; case STASIS_UMOS_BRIDGE: ami_snapshot = ast_manager_build_bridge_state_string_prefix(snapshot, name); break; case STASIS_UMOS_ENDPOINT: /* currently not sending endpoint snapshots to AMI */ break; } if (ami_snapshot) { ast_str_append(&ami_str, 0, "%s", ast_str_buffer(ami_snapshot)); ast_free(ami_snapshot); } } } return ami_str; }
int stasis_subscription_is_subscribed(const struct stasis_subscription *sub) { if (sub) { size_t i; struct stasis_topic *topic = sub->topic; SCOPED_AO2LOCK(lock_topic, topic); for (i = 0; i < AST_VECTOR_SIZE(&topic->subscribers); ++i) { if (AST_VECTOR_GET(&topic->subscribers, i) == sub) { return 1; } } } return 0; }
/*! * \brief Updates the websocket session for an \ref event_session. * * \details The websocket for the given \ref event_session will be updated to the value * of the \c ws_session argument. * * If the value of the \c ws_session is not \c NULL and there are messages in the * event session's \c message_queue, the messages are dispatched and removed from * the queue. * * \internal * * \param session The event session object to update (\ref event_session). * \param ws_session Handle to the underlying websocket session * (\ref ast_ari_websocket_session). */ static void event_session_update_websocket( struct event_session *session, struct ast_ari_websocket_session *ws_session) { int i; ast_assert(session != NULL); ao2_lock(session); session->ws_session = ws_session; for (i = 0; i < AST_VECTOR_SIZE(&session->message_queue); i++) { struct ast_json *msg = AST_VECTOR_GET(&session->message_queue, i); ast_ari_websocket_session_write(session->ws_session, msg); ast_json_unref(msg); } AST_VECTOR_RESET(&session->message_queue, AST_VECTOR_ELEM_CLEANUP_NOOP); ao2_unlock(session); }
/*! * \brief Add a subscriber to a topic. * \param topic Topic * \param sub Subscriber * \return 0 on success * \return Non-zero on error */ static int topic_add_subscription(struct stasis_topic *topic, struct stasis_subscription *sub) { size_t idx; SCOPED_AO2LOCK(lock, topic); /* The reference from the topic to the subscription is shared with * the owner of the subscription, which will explicitly unsubscribe * to release it. * * If we bumped the refcount here, the owner would have to unsubscribe * and cleanup, which is a bit awkward. */ AST_VECTOR_APPEND(&topic->subscribers, sub); for (idx = 0; idx < AST_VECTOR_SIZE(&topic->upstream_topics); ++idx) { topic_add_subscription( AST_VECTOR_GET(&topic->upstream_topics, idx), sub); } return 0; }
static struct stasis_message_route *route_table_find(struct route_table *table, struct stasis_message_type *message_type) { size_t idx; struct stasis_message_route *route; /* While a linear search for routes may seem very inefficient, most * route tables have six routes or less. For such small data, it's * hard to beat a linear search. If we start having larger route * tables, then we can look into containers with more efficient * lookups. */ for (idx = 0; idx < AST_VECTOR_SIZE(table); ++idx) { route = AST_VECTOR_GET_ADDR(table, idx); if (route->message_type == message_type) { return route; } } return NULL; }
struct stasis_forward *stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic) { int res; size_t idx; RAII_VAR(struct stasis_forward *, forward, NULL, ao2_cleanup); if (!from_topic || !to_topic) { return NULL; } forward = ao2_alloc_options(sizeof(*forward), forward_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!forward) { return NULL; } /* Forwards to ourselves are implicit. */ if (to_topic == from_topic) { return ao2_bump(forward); } forward->from_topic = ao2_bump(from_topic); forward->to_topic = ao2_bump(to_topic); topic_lock_both(to_topic, from_topic); res = AST_VECTOR_APPEND(&to_topic->upstream_topics, from_topic); if (res != 0) { ao2_unlock(from_topic); ao2_unlock(to_topic); return NULL; } for (idx = 0; idx < AST_VECTOR_SIZE(&to_topic->subscribers); ++idx) { topic_add_subscription(from_topic, AST_VECTOR_GET(&to_topic->subscribers, idx)); } ao2_unlock(from_topic); ao2_unlock(to_topic); return ao2_bump(forward); }
/*! * \internal \brief Publish a message to a topic's subscribers * \brief topic The topic to publish to * \brief message The message to publish * \brief sync_sub An optional subscriber of the topic to publish synchronously * to */ static void publish_msg(struct stasis_topic *topic, struct stasis_message *message, struct stasis_subscription *sync_sub) { size_t i; ast_assert(topic != NULL); ast_assert(message != NULL); /* * The topic may be unref'ed by the subscription invocation. * Make sure we hold onto a reference while dispatching. */ ao2_ref(topic, +1); ao2_lock(topic); for (i = 0; i < AST_VECTOR_SIZE(&topic->subscribers); ++i) { struct stasis_subscription *sub = AST_VECTOR_GET(&topic->subscribers, i); ast_assert(sub != NULL); dispatch_message(sub, message, (sub == sync_sub)); } ao2_unlock(topic); ao2_ref(topic, -1); }
/*! \brief Wait for the \ref test_msg_handler to receive the message */ static int handler_wait_for_message(struct ast_test *test) { int error = 0; struct timeval wait_now = ast_tvnow(); struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 }; ast_mutex_lock(&handler_lock); while (!handler_received_message) { error = ast_cond_timedwait(&handler_cond, &handler_lock, &wait_time); if (error == ETIMEDOUT) { ast_test_status_update(test, "Test timed out while waiting for handler to get message\n"); ast_test_set_result(test, AST_TEST_FAIL); break; } } ast_mutex_unlock(&handler_lock); return (error != ETIMEDOUT); } /*! \brief Wait for the expected number of user events to be received */ static int user_event_wait_for_events(struct ast_test *test, int expected_events) { int error; struct timeval wait_now = ast_tvnow(); struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 }; expected_user_events = expected_events; ast_mutex_lock(&user_event_lock); while (received_user_events != expected_user_events) { error = ast_cond_timedwait(&user_event_cond, &user_event_lock, &wait_time); if (error == ETIMEDOUT) { ast_test_status_update(test, "Test timed out while waiting for %d expected user events\n", expected_events); ast_test_set_result(test, AST_TEST_FAIL); break; } } ast_mutex_unlock(&user_event_lock); ast_test_status_update(test, "Received %d of %d user events\n", received_user_events, expected_events); return !(received_user_events == expected_events); } static int verify_bad_headers(struct ast_test *test) { int res = 0; int i; for (i = 0; i < AST_VECTOR_SIZE(&bad_headers); i++) { struct ast_variable *headers; struct ast_variable *current; headers = AST_VECTOR_GET(&bad_headers, i); if (!headers) { continue; } res = -1; for (current = headers; current; current = current->next) { ast_test_status_update(test, "Expected UserEvent %d: Failed to match %s: %s\n", i, current->name, current->value); ast_test_set_result(test, AST_TEST_FAIL); } } return res; }
static struct ast_sip_aor *find_registrar_aor(struct pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint) { struct ast_sip_aor *aor = NULL; char *aor_name = NULL; char *domain_name; char *username = NULL; int i; for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); ++i) { pjsip_sip_uri *uri; pjsip_authorization_hdr *header = NULL; switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) { case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME: uri = pjsip_uri_get_uri(rdata->msg_info.to->uri); domain_name = ast_alloca(uri->host.slen + 1); ast_copy_pj_str(domain_name, &uri->host, uri->host.slen + 1); username = ast_alloca(uri->user.slen + 1); ast_copy_pj_str(username, &uri->user, uri->user.slen + 1); /* * We may want to match without any user options getting * in the way. */ AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(username); aor_name = find_aor_name(username, domain_name, endpoint->aors); if (aor_name) { ast_debug(3, "Matched aor '%s' by To username\n", aor_name); } break; case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME: while ((header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, header ? header->next : NULL))) { if (header && !pj_stricmp2(&header->scheme, "digest")) { username = ast_alloca(header->credential.digest.username.slen + 1); ast_copy_pj_str(username, &header->credential.digest.username, header->credential.digest.username.slen + 1); domain_name = ast_alloca(header->credential.digest.realm.slen + 1); ast_copy_pj_str(domain_name, &header->credential.digest.realm, header->credential.digest.realm.slen + 1); aor_name = find_aor_name(username, domain_name, endpoint->aors); if (aor_name) { ast_debug(3, "Matched aor '%s' by Authentication username\n", aor_name); break; } } } break; default: continue; } if (aor_name) { break; } } if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) { /* The provided AOR name was not found (be it within the configuration or sorcery itself) */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL); ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found"); ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", username ?: "", ast_sorcery_object_get_id(endpoint)); }
/*! * \brief Determine if authentication is required * * Authentication is required if the endpoint has at least one auth * section specified */ static int digest_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata) { RAII_VAR(struct ast_sip_endpoint *, artificial, ast_sip_get_artificial_endpoint(), ao2_cleanup); return endpoint == artificial || AST_VECTOR_SIZE(&endpoint->inbound_auths) > 0; }