[asterisk-commits] mmichelson: branch group/pimp_my_sip r385967 - in /team/group/pimp_my_sip: in...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 17 10:33:00 CDT 2013


Author: mmichelson
Date: Wed Apr 17 10:32:57 2013
New Revision: 385967

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=385967
Log:
This adds support for outbound authentication for outbound registrations.

In order to facilitate the change, the outbound authentication API had to
be modified not to be dependent on endpoints but rather to be given the
names of auth IDs in sorcery to use. This way, outbound registration
can be configured to point to an auth section in the configuration the
same way that endpoints do.

Review: https://reviewboard.asterisk.org/r/2431


Modified:
    team/group/pimp_my_sip/include/asterisk/res_sip.h
    team/group/pimp_my_sip/res/res_sip.c
    team/group/pimp_my_sip/res/res_sip.exports.in
    team/group/pimp_my_sip/res/res_sip/sip_outbound_auth.c
    team/group/pimp_my_sip/res/res_sip_outbound_authenticator_digest.c
    team/group/pimp_my_sip/res/res_sip_outbound_registration.c

Modified: team/group/pimp_my_sip/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/include/asterisk/res_sip.h?view=diff&rev=385967&r1=385966&r2=385967
==============================================================================
--- team/group/pimp_my_sip/include/asterisk/res_sip.h (original)
+++ team/group/pimp_my_sip/include/asterisk/res_sip.h Wed Apr 17 10:32:57 2013
@@ -380,14 +380,15 @@
 	/*!
 	 * \brief Create a new request with authentication credentials
 	 *
-	 * \param endpoint The SIP endpoint with which Asterisk is communicating
+	 * \param auths An array of IDs of auth sorcery objects
+	 * \param num_auths The number of IDs in the array
 	 * \param challenge The SIP response with authentication challenge(s)
 	 * \param tsx The transaction in which the challenge was received
 	 * \param new_request The new SIP request with challenge response(s)
 	 * \retval 0 Successfully created new request
 	 * \retval -1 Failed to create a new request
 	 */
-	int (*create_request_with_auth)(const struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *challenge,
+	int (*create_request_with_auth)(const char **auths, size_t num_auths, struct pjsip_rx_data *challenge,
 			struct pjsip_transaction *tsx, struct pjsip_tx_data **new_request);
 };
 
@@ -957,7 +958,7 @@
  * callback in the \ref ast_sip_outbound_authenticator structure for details about
  * the parameters and return values.
  */
-int ast_sip_create_request_with_auth(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *challenge,
+int ast_sip_create_request_with_auth(const char **auths, size_t num_auths, pjsip_rx_data *challenge,
 		pjsip_transaction *tsx, pjsip_tx_data **new_request);
 
 /*!

Modified: team/group/pimp_my_sip/res/res_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip.c?view=diff&rev=385967&r1=385966&r2=385967
==============================================================================
--- team/group/pimp_my_sip/res/res_sip.c (original)
+++ team/group/pimp_my_sip/res/res_sip.c Wed Apr 17 10:32:57 2013
@@ -156,14 +156,14 @@
 	ast_module_unref(ast_module_info->self);
 }
 
-int ast_sip_create_request_with_auth(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *challenge,
+int ast_sip_create_request_with_auth(const char **auths, size_t num_auths, pjsip_rx_data *challenge,
 		pjsip_transaction *tsx, pjsip_tx_data **new_request)
 {
 	if (!registered_outbound_authenticator) {
 		ast_log(LOG_WARNING, "No SIP outbound authenticator registered. Cannot respond to authentication challenge\n");
 		return -1;
 	}
-	return registered_outbound_authenticator->create_request_with_auth(endpoint, challenge, tsx, new_request);
+	return registered_outbound_authenticator->create_request_with_auth(auths, num_auths, challenge, tsx, new_request);
 }
 
 struct endpoint_identifier_list {
@@ -524,9 +524,9 @@
 		return;
 	}
 
-	ast_sip_create_request_with_auth(endpoint, challenge, tsx, &tdata);
-
-	pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, NULL, NULL);
+	if (!ast_sip_create_request_with_auth(endpoint->sip_outbound_auths, endpoint->num_outbound_auths, challenge, tsx, &tdata)) {
+		pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, NULL, NULL);
+	}
 }
 
 static int send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint)

Modified: team/group/pimp_my_sip/res/res_sip.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip.exports.in?view=diff&rev=385967&r1=385966&r2=385967
==============================================================================
--- team/group/pimp_my_sip/res/res_sip.exports.in (original)
+++ team/group/pimp_my_sip/res/res_sip.exports.in Wed Apr 17 10:32:57 2013
@@ -12,6 +12,7 @@
 		LINKER_SYMBOL_PREFIXast_sip_push_task;
 		LINKER_SYMBOL_PREFIXast_sip_push_task_synchronous;
 		LINKER_SYMBOL_PREFIXast_sip_create_request;
+		LINKER_SYMBOL_PREFIXast_sip_create_request_with_auth;
 		LINKER_SYMBOL_PREFIXast_sip_send_request;
 		LINKER_SYMBOL_PREFIXast_sip_requires_authentication;
 		LINKER_SYMBOL_PREFIXast_sip_authenticate_request;

Modified: team/group/pimp_my_sip/res/res_sip/sip_outbound_auth.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip/sip_outbound_auth.c?view=diff&rev=385967&r1=385966&r2=385967
==============================================================================
--- team/group/pimp_my_sip/res/res_sip/sip_outbound_auth.c (original)
+++ team/group/pimp_my_sip/res/res_sip/sip_outbound_auth.c Wed Apr 17 10:32:57 2013
@@ -61,7 +61,7 @@
 		return PJ_FALSE;
 	}
 
-	if (ast_sip_create_request_with_auth(endpoint, rdata, tsx, &tdata)) {
+	if (ast_sip_create_request_with_auth(endpoint->sip_outbound_auths, endpoint->num_outbound_auths, rdata, tsx, &tdata)) {
 		return PJ_FALSE;
 	}
 

Modified: team/group/pimp_my_sip/res/res_sip_outbound_authenticator_digest.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip_outbound_authenticator_digest.c?view=diff&rev=385967&r1=385966&r2=385967
==============================================================================
--- team/group/pimp_my_sip/res/res_sip_outbound_authenticator_digest.c (original)
+++ team/group/pimp_my_sip/res/res_sip_outbound_authenticator_digest.c Wed Apr 17 10:32:57 2013
@@ -25,19 +25,19 @@
 #include "asterisk/module.h"
 #include "asterisk/strings.h"
 
-static int set_outbound_authentication_credentials(pjsip_auth_clt_sess *auth_sess, const struct ast_sip_endpoint *endpoint)
+static int set_outbound_authentication_credentials(pjsip_auth_clt_sess *auth_sess, const char **auth_strs, size_t num_auths)
 {
-	struct ast_sip_auth **auths = ast_alloca(endpoint->num_outbound_auths * sizeof(*auths));
-	pjsip_cred_info *auth_creds = ast_alloca(endpoint->num_outbound_auths * sizeof(*auth_creds));
+	struct ast_sip_auth **auths = ast_alloca(num_auths * sizeof(*auths));
+	pjsip_cred_info *auth_creds = ast_alloca(num_auths * sizeof(*auth_creds));
 	int res = 0;
 	int i;
 
-	if (ast_sip_retrieve_auths(endpoint->sip_outbound_auths, endpoint->num_outbound_auths, auths)) {
+	if (ast_sip_retrieve_auths(auth_strs, num_auths, auths)) {
 		res = -1;
 		goto cleanup;
 	}
 
-	for (i = 0; i < endpoint->num_outbound_auths; ++i) {
+	for (i = 0; i < num_auths; ++i) {
 		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");
@@ -53,14 +53,14 @@
 		}
 	}
 
-	pjsip_auth_clt_set_credentials(auth_sess, endpoint->num_outbound_auths, auth_creds);
+	pjsip_auth_clt_set_credentials(auth_sess, num_auths, auth_creds);
 
 cleanup:
-	ast_sip_cleanup_auths(auths, endpoint->num_outbound_auths);
+	ast_sip_cleanup_auths(auths, num_auths);
 	return res;
 }
 
-static int digest_create_request_with_auth(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *challenge,
+static int digest_create_request_with_auth(const char **auths, size_t num_auths, pjsip_rx_data *challenge,
 		pjsip_transaction *tsx, pjsip_tx_data **new_request)
 {
 	pjsip_auth_clt_sess auth_sess;
@@ -71,7 +71,7 @@
 		return -1;
 	}
 
-	if (set_outbound_authentication_credentials(&auth_sess, endpoint)) {
+	if (set_outbound_authentication_credentials(&auth_sess, auths, num_auths)) {
 		ast_log(LOG_WARNING, "Failed to set authentication credentials\n");
 		return -1;
 	}

Modified: team/group/pimp_my_sip/res/res_sip_outbound_registration.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip_outbound_registration.c?view=diff&rev=385967&r1=385966&r2=385967
==============================================================================
--- team/group/pimp_my_sip/res/res_sip_outbound_registration.c (original)
+++ team/group/pimp_my_sip/res/res_sip_outbound_registration.c Wed Apr 17 10:32:57 2013
@@ -60,8 +60,14 @@
 	unsigned int max_retries;
 	/*! \brief Interval at which retries should occur for temporal responses */
 	unsigned int retry_interval;
+	/*! \brief Treat authentication challenges that we cannot handle as permanent failures */
+	unsigned int auth_rejection_permanent;
 	/*! \brief Serializer for stuff and things */
 	struct ast_taskprocessor *serializer;
+	/*! \brief Configured authentication credentials */
+	const char **sip_outbound_auths;
+	/*! \brief Number of configured auths */
+	size_t num_outbound_auths;
 	/*! \brief Registration should be destroyed after completion of transaction */
 	unsigned int destroy:1;
 };
@@ -93,11 +99,26 @@
 	unsigned int expiration;
 	/*! \brief Interval at which retries should occur for temporal responses */
 	unsigned int retry_interval;
+	/*! \brief Treat authentication challenges that we cannot handle as permanent failures */
+	unsigned int auth_rejection_permanent;
 	/*! \brief Maximum number of retries permitted */
 	unsigned int max_retries;
 	/*! \brief Outbound registration state */
 	struct sip_outbound_registration_state *state;
+	/*! \brief Configured authentication credentials */
+	const char **sip_outbound_auths;
+	/*! \brief Number of configured auths */
+	size_t num_outbound_auths;
 };
+
+static void destroy_auths(const char **auths, size_t num_auths)
+{
+	int i;
+	for (i = 0; i < num_auths; ++i) {
+		ast_free((char *) auths[i]);
+	}
+	ast_free(auths);
+}
 
 /*! \brief Helper function which cancels the timer on a client */
 static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
@@ -186,6 +207,7 @@
 	pjsip_regc_destroy(client_state->client);
 
 	client_state->status = SIP_REGISTRATION_STOPPED;
+	destroy_auths(client_state->sip_outbound_auths, client_state->num_outbound_auths);
 
 	return 0;
 }
@@ -200,6 +222,10 @@
 	int retry_after;
 	/*! \brief Outbound registration client state */
 	struct sip_outbound_registration_client_state *client_state;
+	/*! \brief The response message */
+	pjsip_rx_data *rdata;
+	/*! \brief The response transaction */
+	pjsip_transaction *tsx;
 };
 
 /*! \brief Registration response structure destructor */
@@ -207,11 +233,13 @@
 {
 	struct registration_response *response = obj;
 
+	pjsip_rx_data_free_cloned(response->rdata);
 	ao2_cleanup(response->client_state);
 }
 
 /* \brief Helper funtion which determines if a response code is temporal or not */
-static int sip_outbound_registration_is_temporal(unsigned int code)
+static int sip_outbound_registration_is_temporal(unsigned int code,
+		struct sip_outbound_registration_client_state *client_state)
 {
 	/* Shamelessly taken from pjsua */
 	if (code == PJSIP_SC_REQUEST_TIMEOUT ||
@@ -219,6 +247,9 @@
 		code == PJSIP_SC_BAD_GATEWAY ||
 		code == PJSIP_SC_SERVICE_UNAVAILABLE ||
 		code == PJSIP_SC_SERVER_TIMEOUT ||
+		((code == PJSIP_SC_UNAUTHORIZED ||
+		  code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
+		 !client_state->auth_rejection_permanent) ||
 		PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
 		return 1;
 	} else {
@@ -240,6 +271,16 @@
 	pjsip_regc_get_info(response->client_state->client, &info);
 	ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
 	ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
+
+	if (response->code == 401 || response->code == 407) {
+		pjsip_tx_data *tdata;
+		if (!ast_sip_create_request_with_auth(response->client_state->sip_outbound_auths, response->client_state->num_outbound_auths,
+				response->rdata, response->tsx, &tdata)) {
+			pjsip_regc_send(response->client_state->client, tdata);
+			return 0;
+		}
+		/* Otherwise, fall through so the failure is processed appropriately */
+	}
 
 	if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
 		/* If the registration went fine simply reschedule registration for the future */
@@ -252,7 +293,7 @@
 		schedule_registration(response->client_state, response->retry_after);
 		ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on registration attempt to '%s', instructed to retry in '%d'\n",
 			response->code, server_uri, client_uri, response->retry_after);
-	} else if (response->client_state->retry_interval && sip_outbound_registration_is_temporal(response->code)) {
+	} else if (response->client_state->retry_interval && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
 		if (response->client_state->retries == response->client_state->max_retries) {
 			/* If we received enough temporal responses to exceed our maximum give up permanently */
 			response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
@@ -292,6 +333,8 @@
 	response->expiration = param->expiration;
 	response->retry_after = retry_after ? retry_after->ivalue : 0;
 	response->client_state = client_state;
+	response->tsx = pjsip_rdata_get_tsx(param->rdata);
+	pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
 	ao2_ref(response->client_state, +1);
 
 	if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
@@ -355,6 +398,7 @@
 	struct sip_outbound_registration *registration = obj;
 
 	ao2_cleanup(registration->state);
+	destroy_auths(registration->sip_outbound_auths, registration->num_outbound_auths);
 
 	ast_string_field_free_memory(registration);
 }
@@ -431,6 +475,36 @@
 	return 0;
 }
 
+/*!
+ * \internal
+ * \brief Check if a registration can be reused
+ *
+ * This checks if the existing outbound registration's configuration differs from a newly-applied
+ * outbound registration to see if the applied one.
+ *
+ * \param existing The pre-existing outbound registration
+ * \param applied The newly-created registration
+ */
+static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
+{
+	int i;
+
+	if (strcmp(existing->server_uri, applied->server_uri) || strcmp(existing->client_uri, applied->client_uri) ||
+		strcmp(existing->transport, applied->transport) || strcmp(existing->contact_user, applied->contact_user) ||
+		strcmp(existing->outbound_proxy, applied->outbound_proxy) || existing->num_outbound_auths != applied->num_outbound_auths ||
+		existing->auth_rejection_permanent != applied->auth_rejection_permanent) {
+		return 0;
+	}
+
+	for (i = 0; i < existing->num_outbound_auths; ++i) {
+		if (strcmp(existing->sip_outbound_auths[i], applied->sip_outbound_auths[i])) {
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
 /*! \brief Apply function which finds or allocates a state structure */
 static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
 {
@@ -444,9 +518,7 @@
 		applied->state = sip_outbound_registration_state_alloc();
 	} else {
 		/* If there is an existing registration things are more complicated, we can immediately reuse this state if most stuff remains unchanged */
-		if (!strcmp(existing->server_uri, applied->server_uri) && !strcmp(existing->client_uri, applied->client_uri) &&
-			!strcmp(existing->transport, applied->transport) && !strcmp(existing->contact_user, applied->contact_user) &&
-			!strcmp(existing->outbound_proxy, applied->outbound_proxy)) {
+		if (can_reuse_registration(existing, applied)) {
 			applied->state = existing->state;
 			ao2_ref(applied->state, +1);
 			return 0;
@@ -513,7 +585,18 @@
 static int sip_outbound_registration_perform(void *obj, void *arg, int flags)
 {
 	struct sip_outbound_registration *registration = obj;
-
+	size_t i;
+
+	/* Just in case the client state is being reused for this registration, free the auth information */
+	destroy_auths(registration->state->client_state->sip_outbound_auths,
+			registration->state->client_state->num_outbound_auths);
+	registration->state->client_state->num_outbound_auths = 0;
+
+	registration->state->client_state->sip_outbound_auths = ast_calloc(registration->num_outbound_auths, sizeof(char *));
+	for (i = 0; i < registration->num_outbound_auths; ++i) {
+		registration->state->client_state->sip_outbound_auths[i] = ast_strdup(registration->sip_outbound_auths[i]);
+	}
+	registration->state->client_state->num_outbound_auths = registration->num_outbound_auths;
 	registration->state->client_state->retry_interval = registration->retry_interval;
 	registration->state->client_state->max_retries = registration->max_retries;
 	registration->state->client_state->retries = 0;
@@ -535,6 +618,49 @@
 	}
 
 	ao2_callback(registrations, OBJ_NODATA, sip_outbound_registration_perform, NULL);
+}
+
+#define AUTH_INCREMENT 4
+
+static const char **auth_alloc(const char *value, size_t *num_auths)
+{
+	char *auths = ast_strdupa(value);
+	char *val;
+	int num_alloced = 0;
+	const char **alloced_auths = NULL;
+
+	while ((val = strsep(&auths, ","))) {
+		if (*num_auths >= num_alloced) {
+			size_t size;
+			num_alloced += AUTH_INCREMENT;
+			size = num_alloced * sizeof(char *);
+			alloced_auths = ast_realloc(alloced_auths, size);
+			if (!alloced_auths) {
+				goto failure;
+			}
+		}
+		alloced_auths[*num_auths] = ast_strdup(val);
+		if (!alloced_auths[*num_auths]) {
+			goto failure;
+		}
+		++(*num_auths);
+	}
+	return alloced_auths;
+
+failure:
+	destroy_auths(alloced_auths, *num_auths);
+	return NULL;
+}
+
+static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct sip_outbound_registration *registration = obj;
+
+	registration->sip_outbound_auths = auth_alloc(var->value, &registration->num_outbound_auths);
+	if (!registration->sip_outbound_auths) {
+		return -1;
+	}
+	return 0;
 }
 
 static int load_module(void)
@@ -554,6 +680,8 @@
 	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
 	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
 	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
+	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));
+	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, NULL, 0, 0);
 	ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
 	sip_outbound_registration_perform_all();
 




More information about the asterisk-commits mailing list