/** * 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; } }
/** * 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; }
/** * Process the 200 response for REGISTER and creates the first Security-Associations. * The rest of the SA are not set. * could come over that one. * @param rpl - the 200 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_security_200(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; str sec_hdr; r_security_type sec_type; float sec_q; struct hdr_field *h; struct via_body *vb; r_contact *c; r_ipsec *i; int expires; unsigned long s_hash; char out_rpl[256],out_req[256],inc_rpl[256]; if (!pcscf_use_ipsec &&!pcscf_use_tls) goto ret_false; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_security_200: No transactional request found.\n"); goto error; } sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q); if (!sec_hdr.len) { LOG(L_DBG,"DBG:"M_NAME":P_security_200: No Security-Verify header found.\n"); goto error; } /* find the expires (reg or dereg?) */ expires = cscf_get_max_expires(req); /* get the IPSec info from the registrar */ vb = cscf_get_first_via(req,&h); LOG(L_DBG,"DBG:"M_NAME":P_security_200: Looking for <%d://%.*s:%d> \n", vb->proto,vb->host.len,vb->host.s,vb->port); c = get_r_contact(vb->host,vb->port,vb->proto); r_act_time(); if (!c){ LOG(L_ERR,"ERR:"M_NAME":P_security_200: Contact not found\n"); goto error; } if (c->security_temp){ if (c->security && c->security->type == SEC_TLS && (c->security->data.tls && c->security->data.tls->port_tls==req->rcv.src_port&& c->security->data.tls->session_hash!=0 && c->security->data.tls->session_hash == tls_get_session_hash(req))){ /* don't replace security when doing an integrity protected REGISTER with * possible attack-garbage from security_temp */ P_security_drop(c,c->security_temp); free_r_security(c->security_temp); c->security_temp = 0; } else { if (c->security) { P_security_drop(c,c->security); free_r_security(c->security); } c->security = c->security_temp; c->security_temp = 0; } } switch(sec_type){ case SEC_NONE: break; case SEC_TLS: if (c->security && pcscf_use_tls) { r_tls *tls; int port_tls = req->rcv.src_port; s_hash = get_tls_session_hash(req); if (!s_hash){ LOG(L_ERR,"ERR:"M_NAME":P_security_200: Session Hash could not be obtained !\n"); r_unlock(c->hash); goto error; } tls = new_r_tls(port_tls, s_hash); if (!tls) goto error; c->security->data.tls = tls; } r_unlock(c->hash); break; case SEC_IPSEC: if (!r_valid_contact(c)||!c->security||!c->security->data.ipsec ){ LOG(L_DBG,"DBG:"M_NAME":P_security_200: Contact expired or no IPSec info\n"); r_unlock(c->hash); goto error; } i = c->security->data.ipsec; /* P_Out_Rpl */ sprintf(out_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Rpl, c->host.len,c->host.s, i->port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, i->spi_uc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Req */ sprintf(out_req,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Req, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_us, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Inc_Rpl */ sprintf(inc_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Rpl, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_pc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); if (expires<=0) { /* Deregister */ c->reg_state = DEREGISTERED; r_act_time(); c->expires = time_now + 60; } r_unlock(c->hash); //print_r(L_CRIT); /* run the IPSec scripts */ /* Registration */ execute_cmd(out_rpl); execute_cmd(out_req); execute_cmd(inc_rpl); break; } return CSCF_RETURN_TRUE; ret_false: return CSCF_RETURN_FALSE; error: return CSCF_RETURN_ERROR; }
/** * Process the 200 response for REGISTER and creates the first Security-Associations. * The rest of the SA are not set. * could come over that one. * @param rpl - the 200 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_IPSec_200(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; struct hdr_field *hdr; str sec_cli; struct hdr_field *h; struct via_body *vb; r_contact *c; r_ipsec *i; int expires; char out_rpl[256],out_req[256],inc_rpl[256]; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: No transactional request found.\n"); goto error; } /* just to jump out if no IPSec is employed - the info is already saved */ sec_cli = cscf_get_security_client(req,&hdr); if (!sec_cli.len){ LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: No Security-Client header found.\n"); goto error; } /* find the expires (reg or dereg?) */ expires = cscf_get_max_expires(req); /* get the IPSec info from the registrar */ vb = cscf_get_first_via(req,&h); // if (!h||!h->parsed){ // LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: Error extracting sender's id.\n"); // goto error; // } // vb = (struct via_body*) h->parsed; LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: Looking for <%d://%.*s:%d> \n", vb->proto,vb->host.len,vb->host.s,vb->port); c = get_r_contact(vb->host,vb->port,vb->proto); r_act_time(); if (!c){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: Contact not found\n"); goto error; } if (!r_valid_contact(c)||!c->ipsec){ LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: Contact expired or no IPSec info\n"); r_unlock(c->hash); goto error; } i = c->ipsec; /* P_Out_Rpl */ sprintf(out_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Rpl, c->host.len,c->host.s, i->port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, i->spi_uc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Req */ sprintf(out_req,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Req, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_us, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Inc_Rpl */ sprintf(inc_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Rpl, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_pc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); if (expires<=0) { /* Deregister */ c->reg_state = DEREGISTERED; r_act_time(); c->expires = time_now + 60; } r_unlock(c->hash); //print_r(L_CRIT); /* run the IPSec scripts */ /* Registration */ execute_cmd(out_rpl); execute_cmd(out_req); execute_cmd(inc_rpl); return 1; error: return 0; }
/* Wrapper to send AAR from config file - only used for registration */ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char* bar) { int ret = CSCF_RETURN_ERROR; struct pcontact_info ci; struct cell *t; contact_t* c; struct hdr_field* h; pcontact_t* pcontact; contact_body_t* cb = 0; AAASession* auth; rx_authsessiondata_t* rx_regsession_data_p; cfg_action_t* cfg_action = 0; str route_name; char* p; int aar_sent = 0; saved_transaction_local_t* local_data = 0; //data to be shared across all async calls saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) { LM_ERR("no async route block for assign_server_unreg\n"); return -1; } LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s); int ri = route_get(&main_rt, route_name.s); if (ri < 0) { LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s); return -1; } cfg_action = main_rt.rlist[ri]; if (cfg_action == NULL) { LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s); return -1; } udomain_t* domain_t = (udomain_t*) str1; int is_rereg = 0; //is this a reg/re-reg LM_DBG("Rx AAR Register called\n"); //create the default return code AVP create_return_code(ret); memset(&ci, 0, sizeof (struct pcontact_info)); /** If this is a response then let's check the status before we try and do an AAR. * We will only do AAR for register on success response and of course if message is register */ if (msg->first_line.type == SIP_REPLY) { //check this is a response to a register /* Get the SIP request from this transaction */ t = tmb.t_gett(); if (!t) { LM_ERR("Cannot get transaction for AAR based on SIP Request\n"); goto error; } if ((strncmp(t->method.s, "REGISTER", 8) != 0)) { LM_ERR("Method is not a response to a REGISTER\n"); goto error; } if (msg->first_line.u.reply.statuscode < 200 || msg->first_line.u.reply.statuscode >= 300) { LM_DBG("Message is not a 2xx OK response to a REGISTER\n"); goto error; } tmb.t_release(msg); } else { //SIP Request /* in case of request make sure it is a REGISTER */ if (msg->first_line.u.request.method_value != METHOD_REGISTER) { LM_DBG("This is not a register request\n"); goto error; } if ((cscf_get_max_expires(msg, 0) == 0)) { //if ((cscf_get_expires(msg) == 0)) { LM_DBG("This is a de registration\n"); LM_DBG("We ignore it as these are dealt with by usrloc callbacks \n"); create_return_code(CSCF_RETURN_TRUE); return CSCF_RETURN_TRUE; } } //before we continue, make sure we have a transaction to work with (viz. cdp async) 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"); return CSCF_RETURN_ERROR; } t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_ERR("cannot lookup the transaction\n"); return CSCF_RETURN_ERROR; } } saved_t_data = (saved_transaction_t*) shm_malloc(sizeof (saved_transaction_t)); if (!saved_t_data) { LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n"); return CSCF_RETURN_ERROR; } memset(saved_t_data, 0, sizeof (saved_transaction_t)); saved_t_data->act = cfg_action; saved_t_data->domain = domain_t; saved_t_data->lock = lock_alloc(); if (saved_t_data->lock == NULL) { LM_ERR("unable to allocate init lock for saved_t_transaction reply counter\n"); return CSCF_RETURN_ERROR; } if (lock_init(saved_t_data->lock) == NULL) { LM_ERR("unable to init lock for saved_t_transaction reply counter\n"); return CSCF_RETURN_ERROR; } LM_DBG("Suspending SIP TM transaction\n"); if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) { LM_ERR("failed to suspend the TM processing\n"); free_saved_transaction_global_data(saved_t_data); return CSCF_RETURN_ERROR; } LM_DBG("Successfully suspended transaction\n"); //now get the contacts in the REGISTER and do AAR for each one. cb = cscf_parse_contacts(msg); if (!cb || (!cb->contacts && !cb->star)) { LM_DBG("No contact headers in Register message\n"); goto error; } lock_get(saved_t_data->lock); //we lock here to make sure we send all requests before processing replies asynchronously for (h = msg->contact; h; h = h->next) { if (h->type == HDR_CONTACT_T && h->parsed) { for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) { ul.lock_udomain(domain_t, &c->uri); if (ul.get_pcontact(domain_t, &c->uri, &pcontact) != 0) { LM_DBG("This contact does not exist in PCSCF usrloc - error in cfg file\n"); ul.unlock_udomain(domain_t, &c->uri); lock_release(saved_t_data->lock); goto error; } else if (pcontact->reg_state == PCONTACT_REG_PENDING || pcontact->reg_state == PCONTACT_REGISTERED) { //NEW reg request LM_DBG("Contact [%.*s] exists and is in state PCONTACT_REG_PENDING or PCONTACT_REGISTERED\n" , pcontact->aor.len, pcontact->aor.s); //get IP address from contact struct sip_uri puri; if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) { LM_ERR("failed to parse Contact\n"); ul.unlock_udomain(domain_t, &c->uri); lock_release(saved_t_data->lock); goto error; } LM_DBG("Parsed URI of from host is [%.*s]\n", puri.host.len, puri.host.s); uint16_t ip_version = AF_INET; //TODO IPv6!!!? //check for existing Rx session if (pcontact->rx_session_id.len > 0 && pcontact->rx_session_id.s && (auth = cdpb.AAAGetAuthSession(pcontact->rx_session_id))) { LM_DBG("Rx session already exists for this user\n"); if (memcmp(pcontact->rx_session_id.s, auth->id.s, auth->id.len) != 0) { LM_ERR("Rx session mismatch when URI is [%.*s].......Aborting\n", puri.host.len, puri.host.s); if (auth) cdpb.AAASessionsUnlock(auth->hash); lock_release(saved_t_data->lock); goto error; } //re-registration - update auth lifetime auth->u.auth.lifetime = time(NULL) + rx_auth_expiry; is_rereg = 1; } else { LM_DBG("Creating new Rx session for contact <%.*s>\n", pcontact->aor.len, pcontact->aor.s); int ret = create_new_regsessiondata(domain_t->name, &pcontact->aor, &rx_regsession_data_p); if (!ret) { LM_ERR("Unable to create regsession data parcel when URI is [%.*s]...Aborting\n", puri.host.len, puri.host.s); ul.unlock_udomain(domain_t, &c->uri); if (rx_regsession_data_p) { shm_free(rx_regsession_data_p); rx_regsession_data_p = 0; } lock_release(saved_t_data->lock); goto error; } auth = cdpb.AAACreateClientAuthSession(1, callback_for_cdp_session, rx_regsession_data_p); //returns with a lock if (!auth) { LM_ERR("Rx: unable to create new Rx Reg Session when URI is [%.*s]\n", puri.host.len, puri.host.s); if (rx_regsession_data_p) { shm_free(rx_regsession_data_p); rx_regsession_data_p = 0; } ul.unlock_udomain(domain_t, &c->uri); if (auth) cdpb.AAASessionsUnlock(auth->hash); if (rx_regsession_data_p) { shm_free(rx_regsession_data_p); rx_regsession_data_p = 0; } lock_release(saved_t_data->lock); goto error; } } //we are ready to send the AAR async. lets save the local data data int local_data_len = sizeof (saved_transaction_local_t) + c->uri.len + auth->id.len; local_data = shm_malloc(local_data_len); if (!local_data) { LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n"); lock_release(saved_t_data->lock); goto error; } memset(local_data, 0, local_data_len); local_data->is_rereg = is_rereg; local_data->global_data = saved_t_data; p = (char*) (local_data + 1); local_data->contact.s = p; local_data->contact.len = c->uri.len; memcpy(p, c->uri.s, c->uri.len); p += c->uri.len; local_data->auth_session_id.s = p; local_data->auth_session_id.len = auth->id.len; memcpy(p, auth->id.s, auth->id.len); p += auth->id.len; if (p != (((char*) local_data) + local_data_len)) { LM_CRIT("buffer overflow\n"); free_saved_transaction_data(local_data); goto error; } LM_DBG("Calling send aar register"); //TODOD remove - no longer user AOR parm //ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, local_data); //returns a locked rx auth object ul.unlock_udomain(domain_t, &c->uri); if (!ret) { LM_ERR("Failed to send AAR\n"); lock_release(saved_t_data->lock); free_saved_transaction_data(local_data); //free the local data becuase the CDP async request was not successful (we must free here) goto error; } else { aar_sent = 1; //before we send - bump up the reply counter saved_t_data->answers_not_received++; //we dont need to lock as we already hold the lock above } } else { //contact exists - this is a re-registration, for now we just ignore this LM_DBG("This contact exists and is not in state REGISTER PENDING - we assume re (or de) registration and ignore\n"); ul.unlock_udomain(domain_t, &c->uri); //now we loop for any other contacts. } } } else { if (h->type == HDR_CONTACT_T) { //means we couldnt parse the contact - this is an error LM_ERR("Failed to parse contact header\n"); lock_release(saved_t_data->lock); goto error; } } } //all requests sent at this point - we can unlock the reply lock lock_release(saved_t_data->lock); /*if we get here, we have either: * 1. Successfully sent AAR's for ALL contacts, or * 2. haven't needed to send ANY AAR's for ANY contacts */ if (aar_sent) { LM_DBG("Successful async send of AAR\n"); return CSCF_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process } else { create_return_code(CSCF_RETURN_TRUE); tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel); if (saved_t_data) { free_saved_transaction_global_data(saved_t_data); //no aar sent so we must free the global data } //return CSCF_RETURN_ERROR; return CSCF_RETURN_TRUE; } error: LM_ERR("Error trying to send AAR\n"); if (!aar_sent) { tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel); if (saved_t_data) { free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free //otherwise the callback will segfault } } return CSCF_RETURN_ERROR; //return CSCF_RETURN_FALSE; }
/** * 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; } }