summaryrefslogtreecommitdiff
path: root/res/res_pjsip_session.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2015-05-26 13:56:42 -0500
committerRichard Mudgett <rmudgett@digium.com>2015-05-27 15:10:49 -0500
commitfe21f2e52f1b6629a254cc2f34345c4de6ec4293 (patch)
tree3a276b4eaf102881600f4fcd86ed487c0da4f382 /res/res_pjsip_session.c
parent262d590819b123b1f57196beef8aca45c4aa0d09 (diff)
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
Diffstat (limited to 'res/res_pjsip_session.c')
-rw-r--r--res/res_pjsip_session.c141
1 files changed, 125 insertions, 16 deletions
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 87ce2b0c1..3475e80b7 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1418,16 +1418,95 @@ void ast_sip_session_unsuspend(struct ast_sip_session *session)
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 (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 (inv->state < PJSIP_INV_STATE_CONFIRMED && tdata->msg->line.req.method.id == PJSIP_INVITE_METHOD) {
- pjsip_inv_uac_restart(inv, 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,
@@ -1465,7 +1544,7 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint
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;
}
@@ -1505,7 +1584,7 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint
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
@@ -2254,6 +2333,7 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
{
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) {
@@ -2283,12 +2363,23 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
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) {
@@ -2299,14 +2390,30 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
* 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;
+ }
+ }
+ }
}
if (cb) {
cb(session, e->body.tsx_state.src.rdata);
@@ -2640,6 +2747,7 @@ static int load_module(void)
return AST_MODULE_LOAD_DECLINE;
}
ast_sip_register_service(&session_reinvite_module);
+ ast_sip_register_service(&outbound_invite_auth_module);
ast_module_shutdown_ref(ast_module_info->self);
@@ -2648,6 +2756,7 @@ static int load_module(void)
static int unload_module(void)
{
+ 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);