[Asterisk-code-review] res pjsip session: Fix in-dialog authentication. (asterisk[certified/13.1])
Richard Mudgett
asteriskteam at digium.com
Mon Jun 1 11:58:31 CDT 2015
Richard Mudgett has uploaded a new change for review.
https://gerrit.asterisk.org/559
Change subject: res_pjsip_session: Fix in-dialog authentication.
......................................................................
res_pjsip_session: Fix in-dialog authentication.
When the remote peer requires authentication for in-dialog requests then
re-INVITEs to the peer cause the call to be disconnected and other
in-dialog requests to the peer like MESSAGE just don't go through.
* Made session_inv_on_tsx_state_changed() handle in-dialog authentication
for re-INVITEs and other methods. Initial INVITEs cannot be handled here
because the INVITE transaction must be restarted earlier.
* Pulled needed code from res/res_pjsip/pjsip_outbound_auth.c in
preparation for removing the file. The generic outbound authentication
code did not work as well as anticipated.
* Created outbound_invite_auth() to only handle initial outbound INVITEs.
Re-INVITEs cannot be handled here. The re-INVITE transaction is still in
progress and the PJSIP library cannot handle the overlapping INVITE
transactions. Other method types should not be handled here as this code
only works on outgoing calls and we need to handle incoming and outgoing
calls.
ASTERISK-25131 #close
Reported by: Richard Mudgett
Change-Id: I12bdd7ddccc819b4ce4b091e826d1e26334601b0
---
M res/res_pjsip_session.c
1 file changed, 131 insertions(+), 16 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/59/559/1
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index e1a6e41..91e9705 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1237,16 +1237,95 @@
ao2_ref(suspender, -1);
}
-static int session_outbound_auth(pjsip_dialog *dlg, pjsip_tx_data *tdata, void *user_data)
+/*!
+ * \internal
+ * \brief Handle initial INVITE challenge response message.
+ * \since 13.5.0
+ *
+ * \param rdata PJSIP receive response message data.
+ *
+ * \retval PJ_FALSE Did not handle message.
+ * \retval PJ_TRUE Handled message.
+ */
+static pj_bool_t outbound_invite_auth(pjsip_rx_data *rdata)
{
- pjsip_inv_session *inv = pjsip_dlg_get_inv_session(dlg);
- struct ast_sip_session *session = inv->mod_data[session_module.id];
+ pjsip_transaction *tsx;
+ pjsip_dialog *dlg;
+ pjsip_inv_session *inv;
+ pjsip_tx_data *tdata;
+ struct ast_sip_session *session;
- if (inv->state < PJSIP_INV_STATE_CONFIRMED && tdata->msg->line.req.method.id == PJSIP_INVITE_METHOD) {
- pjsip_inv_uac_restart(inv, PJ_FALSE);
+ if (rdata->msg_info.msg->line.status.code != 401
+ && rdata->msg_info.msg->line.status.code != 407) {
+ /* Doesn't pertain to us. Move on */
+ return PJ_FALSE;
}
+
+ tsx = pjsip_rdata_get_tsx(rdata);
+ dlg = pjsip_rdata_get_dlg(rdata);
+ if (!dlg || !tsx) {
+ return PJ_FALSE;
+ }
+
+ if (tsx->method.id != PJSIP_INVITE_METHOD) {
+ /* Not an INVITE that needs authentication */
+ return PJ_FALSE;
+ }
+
+ inv = pjsip_dlg_get_inv_session(dlg);
+ if (PJSIP_INV_STATE_CONFIRMED <= inv->state) {
+ /*
+ * We cannot handle reINVITE authentication at this
+ * time because the reINVITE transaction is still in
+ * progress.
+ */
+ ast_debug(1, "A reINVITE is being challenged.\n");
+ return PJ_FALSE;
+ }
+ ast_debug(1, "Initial INVITE is being challenged.\n");
+
+ session = inv->mod_data[session_module.id];
+
+ if (ast_sip_create_request_with_auth(&session->endpoint->outbound_auths, rdata, tsx,
+ &tdata)) {
+ return PJ_FALSE;
+ }
+
+ /*
+ * Restart the outgoing initial INVITE transaction to deal
+ * with authentication.
+ */
+ pjsip_inv_uac_restart(inv, PJ_FALSE);
+
ast_sip_session_send_request(session, tdata);
- return 0;
+ return PJ_TRUE;
+}
+
+static pjsip_module outbound_invite_auth_module = {
+ .name = {"Outbound INVITE Auth", 20},
+ .priority = PJSIP_MOD_PRIORITY_DIALOG_USAGE,
+ .on_rx_response = outbound_invite_auth,
+};
+
+/*!
+ * \internal
+ * \brief Setup outbound initial INVITE authentication.
+ * \since 13.5.0
+ *
+ * \param dlg PJSIP dialog to attach outbound authentication.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int setup_outbound_invite_auth(pjsip_dialog *dlg)
+{
+ pj_status_t status;
+
+ ++dlg->sess_count;
+ status = pjsip_dlg_add_usage(dlg, &outbound_invite_auth_module, NULL);
+ --dlg->sess_count;
+
+ return status != PJ_SUCCESS ? -1 : 0;
}
struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint,
@@ -1283,7 +1362,7 @@
return NULL;
}
- if (ast_sip_dialog_setup_outbound_authentication(dlg, endpoint, session_outbound_auth, NULL)) {
+ if (setup_outbound_invite_auth(dlg)) {
pjsip_dlg_terminate(dlg);
return NULL;
}
@@ -1322,7 +1401,7 @@
ao2_cleanup(joint_caps);
}
- if ((pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS)) {
+ if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
/* Since we are not notifying ourselves that the INVITE session is being terminated
* we need to manually drop its reference to session
@@ -2029,6 +2108,8 @@
{
ast_sip_session_response_cb cb;
struct ast_sip_session *session = inv->mod_data[session_module.id];
+ pjsip_tx_data *tdata;
+
print_debug_details(inv, tsx, e);
if (!session) {
/* Transaction likely timed out after the call was hung up. Just
@@ -2057,12 +2138,23 @@
if (tsx->status_code == PJSIP_SC_REQUEST_PENDING) {
reschedule_reinvite(session, cb);
return;
- } else if (inv->state == PJSIP_INV_STATE_CONFIRMED &&
- tsx->status_code != 488) {
- /* Other reinvite failures (except 488) result in destroying the session. */
- pjsip_tx_data *tdata;
- if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) {
- ast_sip_session_send_request(session, tdata);
+ }
+ if (inv->state == PJSIP_INV_STATE_CONFIRMED) {
+ ast_debug(1, "reINVITE received final response code %d\n",
+ tsx->status_code);
+ if ((tsx->status_code == 401 || tsx->status_code == 407)
+ && !ast_sip_create_request_with_auth(
+ &session->endpoint->outbound_auths,
+ e->body.tsx_state.src.rdata, tsx, &tdata)) {
+ /* Send authed reINVITE */
+ ast_sip_session_send_request_with_cb(session, tdata, cb);
+ return;
+ }
+ if (tsx->status_code != 488) {
+ /* Other reinvite failures (except 488) result in destroying the session. */
+ if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) {
+ ast_sip_session_send_request(session, tdata);
+ }
}
}
} else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
@@ -2073,11 +2165,27 @@
* a cancelled call. Our role is to immediately send a BYE to end the
* dialog.
*/
- pjsip_tx_data *tdata;
-
if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) {
ast_sip_session_send_request(session, tdata);
}
+ }
+ }
+ }
+ } else {
+ /* All other methods */
+ if (tsx->role == PJSIP_ROLE_UAC) {
+ if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
+ /* This means we got a final response to our outgoing method */
+ ast_debug(1, "%.*s received final response code %d\n",
+ (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
+ tsx->status_code);
+ if ((tsx->status_code == 401 || tsx->status_code == 407)
+ && !ast_sip_create_request_with_auth(
+ &session->endpoint->outbound_auths,
+ e->body.tsx_state.src.rdata, tsx, &tdata)) {
+ /* Send authed version of the method */
+ ast_sip_session_send_request_with_cb(session, tdata, cb);
+ return;
}
}
}
@@ -2388,6 +2496,7 @@
return AST_MODULE_LOAD_DECLINE;
}
ast_sip_register_service(&session_reinvite_module);
+ ast_sip_register_service(&outbound_invite_auth_module);
ast_module_ref(ast_module_info->self);
@@ -2397,6 +2506,12 @@
static int unload_module(void)
{
/* This will never get called as this module can't be unloaded */
+ ast_sip_unregister_service(&outbound_invite_auth_module);
+ ast_sip_unregister_service(&session_reinvite_module);
+ ast_sip_unregister_service(&session_module);
+ ast_sorcery_delete(ast_sip_get_sorcery(), nat_hook);
+ ao2_cleanup(nat_hook);
+ ao2_cleanup(sdp_handlers);
return 0;
}
--
To view, visit https://gerrit.asterisk.org/559
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I12bdd7ddccc819b4ce4b091e826d1e26334601b0
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: certified/13.1
Gerrit-Owner: Richard Mudgett <rmudgett at digium.com>
More information about the asterisk-code-review
mailing list