/** * Returns the Private Identity extracted from the Authorization header. * If none found there takes the SIP URI in To without the "sip:" prefix * \todo - remove the fallback case to the To header * @param msg - the SIP message * @param realm - the realm to match in an Authorization header * @returns the str containing the private id, no mem dup */ str cscf_get_private_identity_no_realm(struct sip_msg *msg, str realm) { str pi={0,0}; struct hdr_field* h=0; int i; if (parse_headers(msg,HDR_AUTHORIZATION_F,0)!=0) { return pi; } if (!msg->authorization){ goto fallback; } h = msg->authorization; if (h) pi=((auth_body_t*)h->parsed)->digest.username.whole; goto done; fallback: pi = cscf_get_public_identity(msg); if (pi.len>4&&strncasecmp(pi.s,"sip:",4)==0) {pi.s+=4;pi.len-=4;} for(i=0;i<pi.len;i++) if (pi.s[i]==';') { pi.len=i; break; } done: return pi; }
/*! \brief the impu_registered() function * Return true if the AOR in the To Header is registered */ int impu_registered(struct sip_msg* _m, char* _t, char* _s) { impurecord_t* r; int res, ret=-1; str impu; impu = cscf_get_public_identity(_m); LM_DBG("Looking for IMPU <%.*s>\n", impu.len, impu.s); ul.lock_udomain((udomain_t*)_t, &impu); res = ul.get_impurecord((udomain_t*)_t, &impu, &r); if (res < 0) { ul.unlock_udomain((udomain_t*)_t, &impu); LM_ERR("failed to query usrloc for IMPU <%.*s>\n", impu.len, impu.s); return ret; } if (res == 0) { if (r->reg_state == IMPU_REGISTERED ) ret = 1; ul.unlock_udomain((udomain_t*) _t, &impu); LM_DBG("'%.*s' found in usrloc\n", impu.len, ZSW(impu.s)); return ret; } ul.unlock_udomain((udomain_t*)_t, &impu); LM_DBG("'%.*s' not found in usrloc\n", impu.len, ZSW(impu.s)); return ret; }
/** * Returns the Private Identity extracted from the Authorization header. * If none found there takes the SIP URI in To without the "sip:" prefix * \todo - remove the fallback case to the To header * @param msg - the SIP message * @param realm - the realm to match in an Authorization header * @returns the str containing the private id, no mem dup */ str cscf_get_private_identity(struct sip_msg *msg, str realm) { str pi = {0, 0}; struct hdr_field* h = 0; int ret, i, res; if ((parse_headers(msg, HDR_AUTHORIZATION_F, 0) != 0) && (parse_headers(msg, HDR_PROXYAUTH_F, 0) != 0)) { return pi; } h = msg->authorization; if (!msg->authorization) { goto fallback; } if (realm.len && realm.s) { ret = find_credentials(msg, &realm, HDR_AUTHORIZATION_F, &h); if (ret < 0) { ret = find_credentials(msg, &realm, HDR_PROXYAUTH_F, &h); if (ret < 0) { goto fallback; } else { if (ret >0) { goto fallback; } h = msg->proxy_auth; } } else { if (ret > 0) { goto fallback; } } } if (!h) goto fallback; res = parse_credentials(h); if (res != 0) { LOG(L_ERR, "Error while parsing credentials\n"); return pi; } if (h) pi = ((auth_body_t*) h->parsed)->digest.username.whole; goto done; fallback: pi = cscf_get_public_identity(msg); if (pi.len > 4 && strncasecmp(pi.s, "sip:", 4) == 0) { pi.s += 4; pi.len -= 4; } for (i = 0; i < pi.len; i++) if (pi.s[i] == ';') { pi.len = i; break; } done: return pi; }
/** * Handle third party registration * @param msg - the SIP REGISTER message * @param m - the isc_match that matched with info about where to forward it * @param mark - the isc_mark that should be used to mark the message * @returns #ISC_RETURN_TRUE if allowed, #ISC_RETURN_FALSE if not */ int isc_third_party_reg(struct sip_msg *msg, isc_match *m,isc_mark *mark) { r_third_party_registration r; int expires=0; str req_uri ={0,0}; str to ={0,0}; str pvni ={0,0}; str pani ={0,0}; str cv ={0,0}; struct hdr_field *hdr; LOG(L_INFO,"INFO:"M_NAME":isc_third_party_reg: Enter\n"); /* Set Request Uri to IFC matching server name */ req_uri.len = m->server_name.len; req_uri.s = m->server_name.s; /* Get To header*/ to = cscf_get_public_identity(msg); /*TODO - check if the min/max expires is in the acceptable limits * this does not work correctly if the user has multiple contacts * and register/deregisters them individually!!! */ expires = cscf_get_max_expires(msg); /* Get P-Visited-Network-Id header */ pvni = cscf_get_visited_network_id(msg, &hdr); /* Get P-Access-Network-Info header */ pani = cscf_get_access_network_info(msg, &hdr); /* Get P-Charging-Vector header */ /* Just forward the charging header received from P-CSCF */ /* Todo: implement also according to TS 24.229, chap 5.4.1.7 */ cv = cscf_get_charging_vector(msg, &hdr); if (req_uri.s){ memset(&r,0,sizeof(r_third_party_registration)); r.req_uri = req_uri; r.to = to; r.from = isc_my_uri_sip; r.pvni = pvni; r.pani = pani; r.cv = cv; r.service_info = m->service_info; if (expires<=0) r_send_third_party_reg(&r,0); else r_send_third_party_reg(&r,expires+isc_expires_grace); return ISC_RETURN_TRUE; }else{ return ISC_RETURN_FALSE; } }
int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, saved_transaction_local_t* saved_t_data) { AAAMessage* aar = 0; int ret = 0; AAA_AVP* avp = 0; char x[4]; str identifier; str ip; uint16_t ip_version; //we get ip and identifier for the auth session data rx_authsessiondata_t* p_session_data = 0; p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data; identifier = p_session_data->identifier; ip = p_session_data->ip; ip_version = p_session_data->ip_version; LM_DBG("Send AAR register\n"); aar = cdpb.AAACreateRequest(IMS_Rx, IMS_AAR, Flag_Proxyable, auth); if (!aar) goto error; /*Add AVPs*/ /* Add Auth-Application-Id AVP */ if (!rx_add_auth_application_id_avp(aar, IMS_Rx)) goto error; if (!rx_add_vendor_specific_application_id_group(aar, IMS_vendor_id_3GPP, IMS_Rx)) goto error; /* Add Destination-Realm AVP, if not already there */ avp = cdpb.AAAFindMatchingAVP(aar, aar->avpList.head, AVP_Destination_Realm, 0, AAA_FORWARD_SEARCH); if (!avp) { str realm = rx_dest_realm; if (realm.len && !rx_add_destination_realm_avp(aar, realm)) goto error; } /* Add Subscription ID AVP*/ identifier = cscf_get_public_identity(msg); int identifier_type = AVP_Subscription_Id_Type_SIP_URI; //we only do IMPU now rx_add_subscription_id_avp(aar, identifier, identifier_type); /* Add media component description avp for register*/ rx_add_media_component_description_avp_register(aar); /* Add specific action AVP's */ rx_add_specific_action_avp(aar, 1); // CHARGING_CORRELATION_EXCHANGE rx_add_specific_action_avp(aar, 2); // INDICATION_OF_LOSS_OF_BEARER rx_add_specific_action_avp(aar, 3); // INDICATION_RECOVERY_OF_BEARER rx_add_specific_action_avp(aar, 4); // INDICATION_RELEASE_OF_BEARER rx_add_specific_action_avp(aar, 5); // INDICATION_ESTABLISHMENT_OF_BEARER (now void) rx_add_specific_action_avp(aar, 6); // IP-CAN_CHANGE rx_add_specific_action_avp(aar, 12); // ACCESS_NETWORK_INFO_REPORT /* Add Framed IP address AVP*/ if (!rx_add_framed_ip_avp(&aar->avpList, ip, ip_version)) { LM_ERR("Unable to add framed IP AVP\n"); goto error; } /* Add Auth lifetime AVP */LM_DBG("auth_lifetime %u\n", rx_auth_expiry); //TODO check why this is 0 all the time if (rx_auth_expiry) { set_4bytes(x, rx_auth_expiry); if (!rx_add_avp(aar, x, 4, AVP_Authorization_Lifetime, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__)) goto error; } if (auth) cdpb.AAASessionsUnlock(auth->hash); LM_DBG("sending AAR to PCRF\n"); if (rx_forced_peer.len) ret = cdpb.AAASendMessageToPeer(aar, &rx_forced_peer, (void*) async_aar_reg_callback, (void*) saved_t_data); else ret = cdpb.AAASendMessage(aar, (void*) async_aar_reg_callback, (void*) saved_t_data); return ret; error: LM_ERR("unexpected error\n"); if (aar) cdpb.AAAFreeMessage(&aar); if (auth) { cdpb.AAASessionsUnlock(auth->hash); cdpb.AAADropAuthSession(auth); auth = 0; } return ret; }
/** * Perform User Authorization Request. * creates and send the user authorization query * @param msg - the SIP message * @param str1 - the realm * @param str2 - if to do capabilities * @returns true if OK, false if not */ int I_perform_user_authorization_request(struct sip_msg* msg, char* str1, char* str2) { str private_identity, public_identity, visited_network_id; int authorization_type = AVP_IMS_UAR_REGISTRATION; int expires = 3600; struct hdr_field *hdr; str realm; contact_t *c; int sos_reg = 0; contact_body_t *b = 0; str call_id; saved_uar_transaction_t* saved_t; tm_cell_t *t = 0; int intvalue_param; cfg_action_t* cfg_action; uar_param_t* ap = (uar_param_t*) str1; if (fixup_get_ivalue(msg, ap->ivalue, &intvalue_param) != 0) { LM_ERR("no int value param passed\n"); return CSCF_RETURN_ERROR; } cfg_action = ap->paction->next; realm = cscf_get_realm_from_ruri(msg); //check if we received what we should, we do this even though it should be done in cfg file - double checking! if (msg->first_line.type != SIP_REQUEST) { LM_ERR("ERR:I_UAR: The message is not a request\n"); return CSCF_RETURN_ERROR; } if (msg->first_line.u.request.method.len != 8 || memcmp(msg->first_line.u.request.method.s, "REGISTER", 8) != 0) { LM_ERR("ERR:I_UAR: The method is not a REGISTER\n"); return CSCF_RETURN_ERROR; } private_identity = cscf_get_private_identity(msg, realm); if (!private_identity.len) { LM_ERR("ERR:I_UAR: Private Identity not found, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_NO_PRIVATE); return CSCF_RETURN_BREAK; } public_identity = cscf_get_public_identity(msg); if (!public_identity.len) { LM_ERR("ERR:I_UAR: Public Identity not found, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC); return CSCF_RETURN_BREAK; } b = cscf_parse_contacts(msg); if (!b || (!b->contacts && !b->star)) { LM_DBG("DBG:I_UAR: No contacts found\n"); return CSCF_RETURN_ERROR; } for (c = b->contacts; c; c = c->next) { sos_reg = cscf_get_sos_uri_param(c->uri); if (sos_reg == -1) { //error case LM_ERR("ERR:I_UAR: MSG_400_MALFORMED_CONTACT, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_MALFORMED_CONTACT); return CSCF_RETURN_BREAK; } else if (sos_reg == -2) { LM_ERR("ERR:I_UAR: MSG_500_SERVER_ERROR_OUT_OF_MEMORY, responding with 500\n"); cscf_reply_transactional(msg, 500, MSG_500_SERVER_ERROR_OUT_OF_MEMORY); return CSCF_RETURN_BREAK; } } visited_network_id = cscf_get_visited_network_id(msg, &hdr); if (!visited_network_id.len) { LM_ERR("ERR:I_UAR: Visited Network Identity not found, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_NO_VISITED); return CSCF_RETURN_BREAK; } if (atoi(str1)) authorization_type = AVP_IMS_UAR_REGISTRATION_AND_CAPABILITIES; else { expires = cscf_get_max_expires(msg, 0); if (expires == 0) authorization_type = AVP_IMS_UAR_DE_REGISTRATION; } LM_DBG("SENDING UAR: PI: [%.*s], PU: [%.*s], VNID: [%.*s]\n", private_identity.len, private_identity.s, public_identity.len, public_identity.s, visited_network_id.len, visited_network_id.s); //before we send lets suspend the transaction t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { if (tmb.t_newtran(msg) < 0) { LM_ERR("cannot create the transaction for UAR async\n"); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_ERR("cannot lookup the transaction\n"); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } } saved_t = shm_malloc(sizeof (saved_uar_transaction_t)); if (!saved_t) { LM_ERR("no more memory trying to save transaction state\n"); return CSCF_RETURN_ERROR; } memset(saved_t, 0, sizeof (saved_uar_transaction_t)); saved_t->act = cfg_action; call_id = cscf_get_call_id(msg, 0); saved_t->callid.s = (char*) shm_malloc(call_id.len + 1); if (!saved_t->callid.s) { LM_ERR("no more memory trying to save transaction state : callid\n"); shm_free(saved_t); return CSCF_RETURN_ERROR; } memset(saved_t->callid.s, 0, call_id.len + 1); memcpy(saved_t->callid.s, call_id.s, call_id.len); saved_t->callid.len = call_id.len; LM_DBG("Setting default AVP return code used for async callbacks to default as ERROR \n"); create_uaa_return_code(CSCF_RETURN_ERROR); LM_DBG("Suspending SIP TM transaction\n"); if (tmb.t_suspend(msg, &saved_t->tindex, &saved_t->tlabel) < 0) { LM_ERR("failed to suspend the TM processing\n"); free_saved_uar_transaction_data(saved_t); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } if (cxdx_send_uar(msg, private_identity, public_identity, visited_network_id, authorization_type, sos_reg, saved_t) != 0) { LM_ERR("ERR:I_UAR: Error sending UAR or UAR time-out\n"); tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel); free_saved_uar_transaction_data(saved_t); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } //we use async replies therefore we send break and not true when successful return CSCF_RETURN_BREAK; }
/** * Handle third party registration * @param msg - the SIP REGISTER message * @param m - the isc_match that matched with info about where to forward it * @param mark - the isc_mark that should be used to mark the message * @returns #ISC_RETURN_TRUE if allowed, #ISC_RETURN_FALSE if not */ int isc_third_party_reg(struct sip_msg *msg, isc_match *m, isc_mark *mark, udomain_t* d) { r_third_party_registration r; str path, path_received; int expires = 0; str req_uri = {0, 0}; str to = {0, 0}; str pvni = {0, 0}; str pani = {0, 0}; str cv = {0, 0}; str s = {0, 0}; impurecord_t *p; struct hdr_field *hdr; LM_DBG("isc_third_party_reg: Enter\n"); /* Set Request Uri to IFC matching server name */ req_uri.len = m->server_name.len; req_uri.s = m->server_name.s; /* Get To header*/ to = cscf_get_public_identity(msg); if (cscf_get_originating_user(msg, &s)) { isc_ulb.lock_udomain(d, &s); if ( isc_ulb.get_impurecord(d,&s,&p) != 0) { isc_ulb.unlock_udomain(d, &s); LM_ERR("Failed to get IMPU domain from usrloc\n"); goto no_pai; } if ( build_p_associated_uri(p->s) != 0) { isc_ulb.unlock_udomain(d, &s); LM_ERR("Failed to build P-Associated URI for 3rd party reg\n"); goto no_pai; } isc_ulb.unlock_udomain(d, &s); } /*TODO - check if the min/max expires is in the acceptable limits * this does not work correctly if the user has multiple contacts * and register/deregisters them individually!!! */ no_pai: expires = cscf_get_max_expires(msg, 0); /* Get P-Visited-Network-Id header */ pvni = cscf_get_visited_network_id(msg, &hdr); /* Get P-Access-Network-Info header */ pani = cscf_get_access_network_info(msg, &hdr); if (build_path_vector(msg, &path, &path_received) < 0) { LM_ERR("Failed to parse PATH header for third-party reg\n"); return ISC_RETURN_FALSE; } LM_DBG("PATH header in REGISTER is [%.*s]\n", path.len, path.s); /* Get P-Charging-Vector header */ /* Just forward the charging header received from P-CSCF */ /* Todo: implement also according to TS 24.229, chap 5.4.1.7 */ cv = cscf_get_charging_vector(msg, &hdr); if (req_uri.s) { memset(&r, 0, sizeof (r_third_party_registration)); r.req_uri = req_uri; r.to = to; r.from = isc_my_uri_sip; r.pvni = pvni; r.pani = pani; r.cv = cv; if (m->service_info.s && m->service_info.len) { r.body.content_type = CT_SERVICE_INFO; r.body.content = m->service_info; } else if (m->include_register_request) { r.body.content_type = CT_REGISTER_REQ; r.body.content.s = msg->first_line.u.request.method.s; r.body.content.len = msg->len; } else if (m->include_register_response) { struct bookmark dummy_bm; r.body.content_type = CT_REGISTER_RESP; r.body.content.s = build_res_buf_from_sip_req(200, ®_resp_200OK, 0, msg, (unsigned int*)&r.body.content.len, &dummy_bm); if (!r.body.content.s) { LM_DBG("response building failed for body of third party register request"); r.body.content_type = CT_NONE; } } else { r.body.content_type = CT_NONE; } r.path = path; if (expires <= 0) r_send_third_party_reg(&r, 0); else r_send_third_party_reg(&r, expires + isc_expires_grace); return ISC_RETURN_TRUE; } else { return ISC_RETURN_FALSE; } }