/** * Processes a notification and updates the registrar info. * @param n - the notification * @param expires - the Subscription-Status expires parameter * @returns 1 on success, 0 on error */ int r_notification_process(r_notification *n,int expires) { r_registration *r; r_regcontact *rc; r_contact *c; struct sip_uri puri; enum Reg_States reg_state; int expires2; r_subscription *s=0; int sos_reg; r_notification_print(n); if (!n) return 0; r_act_time(); r = n->registration; while(r){ rc = r->contact; while(rc){ if (parse_uri(rc->uri.s,rc->uri.len,&puri)<0){ LOG(L_ERR,"ERR:"M_NAME":r_notification_process: Error parsing Contact URI <%.*s>\n", rc->uri.len,rc->uri.s); goto next; } sos_reg = cscf_get_sos_uri_param(rc->uri); if(sos_reg < 0) return 0; if(sos_reg>0) LOG(L_DBG,"DBG:"M_NAME":update_contact: with sos uri param\n"); // LOG(L_CRIT,"DBG:"M_NAME":r_notification_process: refreshing contacts <%.*s> [%d]\n",rc->uri.len,rc->uri.s,rc->expires); if (rc->state==IMS_REGINFO_TERMINATED){ reg_state = DEREGISTERED; expires2 = time_now+30; c = update_r_contact(puri.host,puri.port_no,puri.proto, 0,®_state,&expires2,0,0,0,&sos_reg); if (c) { LOG(L_DBG,"DBG:"M_NAME":r_notification_process: expired contact <%.*s>\n", c->uri.len,c->uri.s); r_unlock(c->hash); } }else{ reg_state = REGISTERED; expires2 = rc->expires+time_now; c = update_r_contact(puri.host,puri.port_no,puri.proto, 0,®_state,&expires2,0,0,0,&sos_reg); if (c) { LOG(L_DBG,"DBG:"M_NAME":r_notification_process: refreshing contact <%.*s> [%d]\n", c->uri.len,c->uri.s,rc->expires); r_unlock(c->hash); } } next: rc = rc->next; } s = get_r_subscription(r->aor); if (s){ update_r_subscription(s,expires); subs_unlock(s->hash); } r = r->next; } return 1; }
/** * 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; }
/** * Saves the Contact Security information into the P-CSCF registrar for this contact. * @param req - REGISTER request * @param auth - WWW-Authenticate header * @param sec_hdr - Security header * @param type - Security Type * @param q - Preference Value */ r_contact* save_contact_security(struct sip_msg *req, str auth, str sec_hdr,r_security_type type,float q) { contact_t* c=0; contact_body_t* b=0; r_contact *rc; enum Reg_States reg_state=REG_PENDING; int expires,pending_expires=60; struct sip_uri puri; r_security *s=0; int sos_reg = 0; b = cscf_parse_contacts(req); if (!b||!b->contacts) { LOG(L_ERR,"ERR:"M_NAME":save_contact_security: No contacts found\n"); goto error; } if(b) c = b->contacts; r_act_time(); /* the Security works for just 1 contact/registration! */ if(c){ LOG(L_DBG,"DBG:"M_NAME":save_contact_security: <%.*s>\n",c->uri.len,c->uri.s); expires = time_now+pending_expires; if (parse_uri(c->uri.s,c->uri.len,&puri)<0){ LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Error parsing Contact URI <%.*s>\n",c->uri.len,c->uri.s); goto error; } if (puri.port_no==0) puri.port_no=5060; LOG(L_DBG,"DBG:"M_NAME":save_contact_security: %d %.*s : %d\n", puri.proto, puri.host.len,puri.host.s,puri.port_no); sos_reg = cscf_get_sos_uri_param(c->uri); if(sos_reg < 0) return 0; if (type == SEC_TLS) puri.proto = PROTO_TLS; /* create the r_security structure */ s = new_r_security(sec_hdr,type,q); if (!s) goto error; switch(type) { case SEC_NONE: break; case SEC_TLS: // r_tls creation happens on 200 break; case SEC_IPSEC: { /* then parse the parameters */ r_ipsec *ipsec; str prot, mod, prot_set, mod_set; str ck,ik,ealg,alg,tmp; str alg_setkey,ealg_setkey; unsigned int spi_uc,spi_us; unsigned int spi_pc,spi_ps; int port_uc,port_us; char ck_c[64],ik_c[64]; str ck_esp={ck_c,0},ik_esp={ik_c,0}; get_param(sec_hdr,s_prot,prot); get_param(sec_hdr,s_mod,mod); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Protocol: <%.*s>\n", prot.len,prot.s); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Mode: <%.*s>\n", mod.len,mod.s); if (prot.len == s_ah_inout.len && strncasecmp(prot.s,s_ah_inout.s,prot.len)==0) { prot_set = s_ah_inout; }else{ prot_set = s_esp_inout; } if (mod.len == s_tun_inout.len && strncasecmp(mod.s,s_tun_inout.s,mod.len)==0) { mod_set = s_tun_inout; } else { mod_set = s_trans_inout; } LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Protocol: <%.*s>\n", prot_set.len,prot_set.s); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Mode: <%.*s>\n", mod_set.len,mod_set.s); get_qparam(auth,s_ck,ck); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: CK: <%.*s>\n", ck.len,ck.s); get_qparam(auth,s_ik,ik); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: IK: <%.*s>\n", ik.len,ik.s); get_param(sec_hdr,s_ealg,ealg); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Enc Algorithm: <%.*s>\n", ealg.len,ealg.s); get_param(sec_hdr,s_alg,alg); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Int Algorithm: <%.*s>\n", alg.len,alg.s); /* and for spis */ get_param(sec_hdr,s_spi_c,tmp); strtoint(tmp,spi_uc); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-C: %u\n", spi_uc); get_param(sec_hdr,s_spi_s,tmp); strtoint(tmp,spi_us); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-S: %u\n", spi_us); /* and for ports */ get_param(sec_hdr,s_port_c,tmp); strtoint(tmp,port_uc); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-C: %d\n", port_uc); get_param(sec_hdr,s_port_s,tmp); strtoint(tmp,port_us); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-S: %d\n", port_us); ck_esp.s[ck_esp.len++]='0'; ck_esp.s[ck_esp.len++]='x'; if (ealg.len == s_des_in.len && strncasecmp(ealg.s,s_des_in.s,ealg.len)==0) { memcpy(ck_esp.s+ck_esp.len,ck.s,32);ck_esp.len+=32; memcpy(ck_esp.s+ck_esp.len,ck.s,16);ck_esp.len+=16; ealg_setkey = s_des_out; } else if (ealg.len == s_aes_in.len && strncasecmp(ealg.s,s_aes_in.s,ealg.len)==0) { memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len; ealg_setkey = s_aes_out; }else { memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len; ealg_setkey = s_null_out; ealg = s_null_out; } ik_esp.s[ik_esp.len++]='0'; ik_esp.s[ik_esp.len++]='x'; if (alg.len == s_md5_in.len && strncasecmp(alg.s,s_md5_in.s,alg.len)==0) { memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len; alg_setkey = s_md5_out; } else if (alg.len == s_sha_in.len && strncasecmp(alg.s,s_sha_in.s,alg.len)==0) { memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len; memcpy(ik_esp.s+ik_esp.len,"00000000",8);ik_esp.len+=8; alg_setkey = s_sha_out; }else{ LOG(L_ERR,"ERR:"M_NAME":save_contact_security: Unknown Integrity algorithm <%.*s>\n",alg.len,alg.s); goto error; } spi_pc=get_next_spi(); spi_ps=get_next_spi(); ipsec = new_r_ipsec(spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us, ealg_setkey,ealg, ck_esp,alg_setkey,alg, ik_esp, prot_set, mod_set); if (!ipsec) goto error; s->data.ipsec = ipsec; puri.port_no = ipsec->port_us; /* * this should actually be port_uc... then the cscf_get_ue_via should be * changed to give rport and not the port in the via. but this would * break NATed clients... */ } break; } } rc = update_r_contact_sec(puri.host,puri.port_no,puri.proto, &(c->uri),®_state,&expires,s, &sos_reg); return rc; error: if (s) free_r_security(s); return 0; }