diff options
-rw-r--r-- | res/res_pjsip_session.c | 141 |
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); |