コード例 #1
0
ファイル: location.c プロジェクト: litnimax/asterisk
struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
{
	struct ao2_container *contacts;

	/* ao2_lock / ao2_unlock do not actually write aor since it has an ao2 lockobj. */
	ao2_lock((void*)aor);
	contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
	ao2_unlock((void*)aor);

	return contacts;
}
コード例 #2
0
ファイル: location.c プロジェクト: alyosha1879/asterisk
struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
{
	struct ao2_container *contacts;
	struct ast_named_lock *lock;

	lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor));
	if (!lock) {
		return NULL;
	}

	ao2_wrlock(lock);
	contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
	ao2_unlock(lock);
	ast_named_lock_put(lock);

	return contacts;
}
コード例 #3
0
static int register_aor(pjsip_rx_data *rdata,
	struct ast_sip_endpoint *endpoint,
	struct ast_sip_aor *aor,
	const char *aor_name)
{
	int res;
	struct ao2_container *contacts = NULL;

	ao2_lock(aor);
	contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
	if (!contacts) {
		ao2_unlock(aor);
		return PJ_TRUE;
	}

	res = register_aor_core(rdata, endpoint, aor, aor_name, contacts);
	ao2_cleanup(contacts);
	ao2_unlock(aor);

	return res;
}
コード例 #4
0
static int register_aor_core(pjsip_rx_data *rdata,
	struct ast_sip_endpoint *endpoint,
	struct ast_sip_aor *aor,
	const char *aor_name,
	struct ao2_container *contacts)
{
	static const pj_str_t USER_AGENT = { "User-Agent", 10 };

	int added = 0, updated = 0, deleted = 0;
	pjsip_contact_hdr *contact_hdr = NULL;
	struct registrar_contact_details details = { 0, };
	pjsip_tx_data *tdata;
	RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
	struct ast_sip_contact *response_contact;
	char *user_agent = NULL;
	pjsip_user_agent_hdr *user_agent_hdr;
	pjsip_expires_hdr *expires_hdr;
	pjsip_via_hdr *via_hdr;
	pjsip_via_hdr *via_hdr_last;
	char *via_addr = NULL;
	int via_port = 0;
	pjsip_cid_hdr *call_id_hdr;
	char *call_id = NULL;
	size_t alloc_size;

	/* So we don't count static contacts against max_contacts we prune them out from the container */
	ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);

	if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) {
		/* The provided Contact headers do not conform to the specification */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
		ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
		ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
				ast_sorcery_object_get_id(endpoint));
		return PJ_TRUE;
	}

	if (registrar_validate_path(rdata, aor, &path_str)) {
		/* Ensure that intervening proxies did not make invalid modifications to the request */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 420, NULL, NULL, NULL);
		ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
				ast_sorcery_object_get_id(endpoint));
		return PJ_TRUE;
	}

	if ((MAX(added - deleted, 0) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) {
		/* Enforce the maximum number of contacts */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
		ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
		ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n",
				ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts);
		return PJ_TRUE;
	}

	if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) {
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
		return PJ_TRUE;
	}

	user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL);
	if (user_agent_hdr) {
		alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
		user_agent = ast_alloca(alloc_size);
		ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
	}

	/* Find the first Via header */
	via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
	if (via_hdr) {
		/* Find the last Via header */
		while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
				PJSIP_H_VIA, via_hdr->next)) != NULL) {
			via_hdr_last = via_hdr;
		}
		alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
		via_addr = ast_alloca(alloc_size);
		ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size);
		via_port=via_hdr_last->sent_by.port;
	}

	call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL);
	if (call_id_hdr) {
		alloc_size = pj_strlen(&call_id_hdr->id) + 1;
		call_id = ast_alloca(alloc_size);
		ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size);
	}

	/* Iterate each provided Contact header and add, update, or delete */
	while ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
		int expiration;
		char contact_uri[pjsip_max_url_size];
		RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);

		if (contact_hdr->star) {
			/* A star means to unregister everything, so do so for the possible contacts */
			ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name);
			break;
		}

		if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
			/* This registrar only currently supports sip: and sips: URI schemes */
			continue;
		}

		expiration = registrar_get_expiration(aor, contact_hdr, rdata);
		details.uri = pjsip_uri_get_uri(contact_hdr->uri);
		pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));

		if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) {
			/* If they are actually trying to delete a contact that does not exist... be forgiving */
			if (!expiration) {
				ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
					contact_uri, aor_name);
				continue;
			}

			if (ast_sip_location_add_contact_nolock(aor, contact_uri, ast_tvadd(ast_tvnow(),
				ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL,
					user_agent, via_addr, via_port, call_id, endpoint)) {
				ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
						contact_uri, aor_name);
				continue;
			}

			ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
				contact_uri, aor_name, expiration);
			ast_test_suite_event_notify("AOR_CONTACT_ADDED",
					"Contact: %s\r\n"
					"AOR: %s\r\n"
					"Expiration: %d\r\n"
					"UserAgent: %s",
					contact_uri,
					aor_name,
					expiration,
					user_agent);
		} else if (expiration) {
			struct ast_sip_contact *contact_update;

			contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact);
			if (!contact_update) {
				ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
					contact->uri, expiration);
				continue;
			}

			contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
			contact_update->qualify_frequency = aor->qualify_frequency;
			contact_update->authenticate_qualify = aor->authenticate_qualify;
			if (path_str) {
				ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
			}
			if (user_agent) {
				ast_string_field_set(contact_update, user_agent, user_agent);
			}
			if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
				ast_string_field_set(contact_update, reg_server, ast_config_AST_SYSTEM_NAME);
			}

			if (ast_sip_location_update_contact(contact_update)) {
				ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
					contact->uri, expiration);
				ast_sip_location_delete_contact(contact);
				continue;
			}
			ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
				contact_uri, aor_name, expiration);
			ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
					"Contact: %s\r\n"
					"AOR: %s\r\n"
					"Expiration: %d\r\n"
					"UserAgent: %s",
					contact_uri,
					aor_name,
					expiration,
					contact_update->user_agent);
			ao2_cleanup(contact_update);
		} else {
			/* We want to report the user agent that was actually in the removed contact */
			ast_sip_location_delete_contact(contact);
			ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
			ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
					"Contact: %s\r\n"
					"AOR: %s\r\n"
					"UserAgent: %s",
					contact_uri,
					aor_name,
					contact->user_agent);
		}
	}

	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);

	/* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
	 * do so
	 */
	if (aor->remove_existing) {
		ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
	}

	/* Re-retrieve contacts.  Caller will clean up the original container. */
	contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
	response_contact = ao2_callback(contacts, 0, NULL, NULL);

	/* Send a response containing all of the contacts (including static) that are present on this AOR */
	if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
		ao2_cleanup(response_contact);
		ao2_cleanup(contacts);
		return PJ_TRUE;
	}
	ao2_cleanup(response_contact);

	/* Add the date header to the response, some UAs use this to set their date and time */
	registrar_add_date_header(tdata);

	ao2_callback(contacts, 0, registrar_add_contact, tdata);
	ao2_cleanup(contacts);

	if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
		expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
	}

	ast_sip_send_stateful_response(rdata, tdata, endpoint);

	return PJ_TRUE;
}
コード例 #5
0
static int register_aor(pjsip_rx_data *rdata,
	struct ast_sip_endpoint *endpoint,
	struct ast_sip_aor *aor,
	const char *aor_name)
{
	struct aor_core_response response = {
		.code = 500,
	};
	struct ao2_container *contacts = NULL;

	ao2_lock(aor);
	contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
	if (!contacts) {
		ao2_unlock(aor);
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
			rdata, response.code, NULL, NULL, NULL);
		return PJ_TRUE;
	}

	register_aor_core(rdata, endpoint, aor, aor_name, contacts, &response);
	ao2_cleanup(contacts);
	ao2_unlock(aor);

	/* Now send the REGISTER response to the peer */
	if (response.tdata) {
		ast_sip_send_stateful_response(rdata, response.tdata, endpoint);
	} else {
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
			rdata, response.code, NULL, NULL, NULL);
	}
	return PJ_TRUE;
}

static int match_aor(const char *aor_name, const char *id)
{
	if (ast_strlen_zero(aor_name)) {
		return 0;
	}

	if (!strcmp(aor_name, id)) {
		ast_debug(3, "Matched id '%s' to aor '%s'\n", id, aor_name);
		return 1;
	}

	return 0;
}

static char *find_aor_name(const char *username, const char *domain, const char *aors)
{
	char *configured_aors;
	char *aors_buf;
	char *aor_name;
	char *id_domain;
	struct ast_sip_domain_alias *alias;

	id_domain = ast_alloca(strlen(username) + strlen(domain) + 2);
	sprintf(id_domain, "%s@%s", username, domain);

	aors_buf = ast_strdupa(aors);

	/* Look for exact match on username@domain */
	configured_aors = aors_buf;
	while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
		if (match_aor(aor_name, id_domain)) {
			return ast_strdup(aor_name);
		}
	}

	/* If there's a domain alias, look for exact match on username@domain_alias */
	alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain);
	if (alias) {
		char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2);

		sprintf(id_domain, "%s@%s", username, alias->domain);
		ao2_cleanup(alias);

		configured_aors = strcpy(aors_buf, aors);/* Safe */
		while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
			if (match_aor(aor_name, id_domain_alias)) {
				return ast_strdup(aor_name);
			}
		}
	}

	if (ast_strlen_zero(username)) {
		/* No username, no match */
		return NULL;
	}

	/* Look for exact match on username only */
	configured_aors = strcpy(aors_buf, aors);/* Safe */
	while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
		if (match_aor(aor_name, username)) {
			return ast_strdup(aor_name);
		}
	}

	return NULL;
}