/** * Checks if Session-Expires value is over Min_SE local policy * @param msg - the initial request * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not */ int S_check_session_expires(struct sip_msg* msg, char* str1, char* str2) { time_t t_time; time_t min_se_time = 0; str ses_exp = {0,0}; str min_se = {0,0}; str new_min_se = {0,0}; str new_ses_exp = {0,0}; struct hdr_field *h_se, *h_min_se; str refresher; ses_exp = cscf_get_session_expires_body(msg, &h_se); t_time = cscf_get_session_expires(ses_exp, &refresher); if (!t_time || t_time >= scscf_min_se) return CSCF_RETURN_TRUE; if (!supports_extension(msg, &str_ext_timer)) //does not suports timer extension { //add Min-SE header with its minimum interval min_se = cscf_get_min_se(msg, &h_min_se); if (min_se.len) { strtotime(min_se, min_se_time); if (min_se_time < scscf_min_se) cscf_del_header(msg, h_min_se); else return CSCF_RETURN_TRUE; } new_min_se.len = 11/*int value*/ + str_min_se.len+3; new_min_se.s = pkg_malloc(new_min_se.len+1); if (!new_min_se.s) { LOG(L_ERR,"ERR:"M_NAME":S_check_session_expires: Error allocating %d bytes\n",new_min_se.len); goto error; } new_min_se.len = snprintf(new_min_se.s, new_min_se.len, "%.*s %d\r\n",str_min_se.len, str_min_se.s, scscf_min_se); min_se_time = scscf_min_se; cscf_add_header(msg, &new_min_se, HDR_OTHER_T); if (t_time < scscf_min_se) { cscf_del_header(msg, h_se); new_ses_exp.len = 11 + str_se.len+3; new_ses_exp.s = pkg_malloc(new_ses_exp.len+1); if (!new_ses_exp.s) { LOG(L_ERR,"ERR:"M_NAME":S_check_session_expires: Error allocating %d bytes\n",new_ses_exp.len); goto error; } new_ses_exp.len = snprintf(new_ses_exp.s, new_ses_exp.len, "%.*s %d\r\n",str_se.len, str_se.s, scscf_min_se); t_time = scscf_min_se; cscf_add_header(msg, &new_ses_exp, HDR_OTHER_T); } return CSCF_RETURN_TRUE; } error: if (new_min_se.s) pkg_free(new_min_se.s); if (new_ses_exp.s) pkg_free(new_ses_exp.s); return CSCF_RETURN_FALSE; }
int add_supported_secagree_header(struct sip_msg* m) { // Add sec-agree header in the reply const char* supported_sec_agree = "Supported: sec-agree\r\n"; const int supported_sec_agree_len = 22; str* supported = NULL; if((supported = pkg_malloc(sizeof(str))) == NULL) { LM_ERR("Error allocating pkg memory for supported header\n"); return -1; } if((supported->s = pkg_malloc(supported_sec_agree_len)) == NULL) { LM_ERR("Error allcationg pkg memory for supported header str\n"); return -1; } memcpy(supported->s, supported_sec_agree, supported_sec_agree_len); supported->len = supported_sec_agree_len; if(cscf_add_header(m, supported, HDR_SUPPORTED_T) != 1) { LM_ERR("Error adding security header to reply!\n"); return -1; } return 0; }
int assert_called_identity(struct sip_msg* _m, udomain_t* _d) { int ret=CSCF_RETURN_FALSE; str called_party_id={0,0},x={0,0}; struct sip_msg* req; struct hdr_field *h=0; //get request from reply req = get_request_from_reply(_m); if (!req) { LM_ERR("Unable to get request from reply for REGISTER. No transaction\n"); goto error; } called_party_id = cscf_get_public_identity_from_called_party_id(req, &h); if (!called_party_id.len){ goto error; }else{ LM_DBG("Called Party ID from request: %.*s\n", called_party_id.len, called_party_id.s); x.len = p_asserted_identity_s.len+p_asserted_identity_m.len+called_party_id.len+p_asserted_identity_e.len; x.s = pkg_malloc(x.len); if (!x.s){ LM_ERR("P_assert_called_identity: Error allocating %d bytes\n", x.len); x.len=0; goto error; } x.len=0; STR_APPEND(x,p_asserted_identity_s); STR_APPEND(x,p_asserted_identity_m); STR_APPEND(x,called_party_id); STR_APPEND(x,p_asserted_identity_e); if (cscf_add_header(_m,&x,HDR_OTHER_T)) ret = CSCF_RETURN_TRUE; else goto error; } return ret; error: ret=CSCF_RETURN_FALSE; return ret; }
int add_security_server_header(struct sip_msg* m, ipsec_t* s) { // allocate memory for the header itself str* sec_header = NULL; if((sec_header = pkg_malloc(sizeof(str))) == NULL) { LM_ERR("Error allocating pkg memory for security header\n"); return -1; } memset(sec_header, 0, sizeof(str)); // create a temporary buffer and set the value in it char sec_hdr_buf[1024]; memset(sec_hdr_buf, 0, sizeof(sec_hdr_buf)); sec_header->len = snprintf(sec_hdr_buf, sizeof(sec_hdr_buf) - 1, "Security-Server: ipsec-3gpp;prot=esp;mod=trans;spi-c=%d;spi-s=%d;port-c=%d;port-s=%d;alg=%.*s;ealg=%.*s\r\n", s->spi_pc, s->spi_ps, ipsec_client_port, ipsec_server_port, s->r_alg.len, s->r_alg.s, s->r_ealg.len, s->r_ealg.s ); // copy to the header and add if((sec_header->s = pkg_malloc(sec_header->len)) == NULL) { LM_ERR("Error allocating pkg memory for security header payload\n"); pkg_free(sec_header); return -1; } memcpy(sec_header->s, sec_hdr_buf, sec_header->len); // add security-server header in reply if(cscf_add_header(m, sec_header, HDR_OTHER_T) != 1) { LM_ERR("Error adding security header to reply!\n"); pkg_free(sec_header->s); pkg_free(sec_header); return -1; } return 0; }
/** * Process the 401 response for REGISTER and creates the first Security-Associations. * IPSEc: Only the SA for P_Inc_Req - Incoming Requests is set now as the next REGISTER * could come over that one. * @param rpl - the 401 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_security_401(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; struct hdr_field *hdr; str sec_hdr,sec_srv={0,0}; r_security_type sec_type; char cmd[256]; r_contact *c; r_ipsec *ipsec; float sec_q=-1; str auth; 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_401: No transactional request found.\n"); goto error; } auth = cscf_get_authenticate(rpl,&hdr); if (!auth.len){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: No WWW-Authenticate header found.\n"); goto ret_false; } 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_401: No Security-Client header found.\n"); goto ret_false; } LOG(L_INFO,"DBG:"M_NAME":P_security_401: Security-Client header found : <%.*s>.\n", sec_hdr.len, sec_hdr.s); /* save data into registrar */ c = save_contact_security(req, auth, sec_hdr, sec_type, sec_q); if (!c) goto error; switch(sec_type){ case SEC_NONE: break; case SEC_TLS: /* try to add the Security-Server header */ sec_srv.len = s_security_server_s.len+sec_hdr.len+s_security_server_e.len; sec_srv.s = pkg_malloc(sec_srv.len); if (!sec_srv.s){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len); goto error; } sec_srv.len=0; STR_APPEND(sec_srv,s_security_server_s); STR_APPEND(sec_srv,sec_hdr); STR_APPEND(sec_srv,s_security_server_e); if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) { LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s); pkg_free(sec_srv.s); goto error; } break; case SEC_IPSEC: ipsec = c->security_temp->data.ipsec; /* try to add the Security-Server header */ sprintf(cmd,"Security-Server: ipsec-3gpp; ealg=%.*s; alg=%.*s; spi-c=%d; spi-s=%d; port-c=%d; port-s=%d; q=0.1\r\n", ipsec->r_ealg.len,ipsec->r_ealg.s, ipsec->r_alg.len,ipsec->r_alg.s, ipsec->spi_pc,ipsec->spi_ps, pcscf_ipsec_port_c,pcscf_ipsec_port_s); sec_srv.len = strlen(cmd); sec_srv.s = pkg_malloc(sec_srv.len); if (!sec_srv.s){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len); goto error; } memcpy(sec_srv.s,cmd,sec_srv.len); if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) { LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s); pkg_free(sec_srv.s); goto error; } /* run the IPSec script */ /* P_Inc_Req */ sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Req, c->host.len,c->host.s, ipsec->port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, ipsec->spi_ps, ipsec->ealg.len,ipsec->ealg.s, ipsec->ck.len,ipsec->ck.s, ipsec->alg.len,ipsec->alg.s, ipsec->ik.len,ipsec->ik.s); r_unlock(c->hash); execute_cmd(cmd); break; } return CSCF_RETURN_TRUE; ret_false: return CSCF_RETURN_FALSE; error: return CSCF_RETURN_ERROR; }
/** * Process the 401 response for REGISTER and creates the first Security-Associations. * Only the SA for P_Inc_Req - Incoming Requests is set now as the next REGISTER * could come over that one. * @param rpl - the 401 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_IPSec_401(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; str auth; struct hdr_field *hdr; str sec_cli,sec_srv={0,0}; str ck,ik; char ck_c[64],ik_c[64]; str ck_esp={ck_c,0},ik_esp={ik_c,0}; str alg,ealg; str alg_setkey,ealg_setkey; str tmp; unsigned int spi_uc,spi_us; unsigned int spi_pc,spi_ps; int port_uc,port_us; char cmd[256]; str ue; contact_body_t *contact; struct sip_uri uri; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: No transactional request found.\n"); goto error; } auth = cscf_get_authenticate(rpl,&hdr); if (!auth.len){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: No authorization header found.\n"); goto error; } sec_cli = cscf_get_security_client(req,&hdr); if (!sec_cli.len){ LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: No Security-Client header found.\n"); goto error; } /* first we look for CK, IK */ get_qparam(auth,s_ck,ck); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: CK: <%.*s>\n", ck.len,ck.s); get_qparam(auth,s_ik,ik); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: IK: <%.*s>\n", ik.len,ik.s); /* then for algorithms */ get_param(sec_cli,s_ealg,ealg); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Enc Algorithm: <%.*s>\n", ealg.len,ealg.s); get_param(sec_cli,s_alg,alg); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Int Algorithm: <%.*s>\n", alg.len,alg.s); /* and for spis */ get_param(sec_cli,s_spi_c,tmp); strtoint(tmp,spi_uc); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: SPI-C: %d\n", spi_uc); get_param(sec_cli,s_spi_s,tmp); strtoint(tmp,spi_us); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: SPI-S: %d\n", spi_us); /* and for ports */ get_param(sec_cli,s_port_c,tmp); strtoint(tmp,port_uc); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Port-C: %d\n", port_uc); get_param(sec_cli,s_port_s,tmp); strtoint(tmp,port_us); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Port-S: %d\n", port_us); contact = cscf_parse_contacts(req); if (!contact) { LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Message contains no Contact!\n"); goto error; } if (contact->contacts){ ue = contact->contacts->uri; if (parse_uri(ue.s,ue.len,&uri)){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error parsing uri <%.*s>\n",ue.len,ue.s); goto error; } ue = uri.host; if (uri.port_no==0) port_uc=5060; }else ue = req->via1->host; LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: UE IP: <%.*s> \n",ue.len,ue.s); spi_pc=get_next_spi(); spi_ps=get_next_spi(); 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":P_ipsec_401: Unknown Integrity algorithm <%.*s>\n",alg.len,alg.s); goto error; } /* try to add the Security-Server header */ sprintf(cmd,"Security-Server: ipsec-3gpp; ealg=%.*s; alg=%.*s; spi-c=%d; spi-s=%d; port-c=%d; port-s=%d; q=0.1\r\n", ealg.len,ealg.s, alg.len,alg.s, spi_pc,spi_ps, pcscf_ipsec_port_c,pcscf_ipsec_port_s); sec_srv.len = strlen(cmd); sec_srv.s = pkg_malloc(sec_srv.len); if (!sec_srv.s){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error allocating %d pkg bytes \n",sec_srv.len); goto error; } memcpy(sec_srv.s,cmd,sec_srv.len); if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) { LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s); pkg_free(sec_srv.s); goto error; } /* run the IPSec script */ /* P_Inc_Req */ sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Req, ue.len,ue.s, port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, spi_ps, ealg_setkey.len,ealg_setkey.s, ck_esp.len,ck_esp.s, alg_setkey.len,alg_setkey.s, ik_esp.len,ik_esp.s); execute_cmd(cmd); /* save data into registrar */ save_contact_ipsec(req,rpl, spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us, ealg_setkey,ck_esp,alg_setkey,ik_esp); return 1; error: return 0; }
/** * Updates dialog on reply message * @param msg - the SIP message * @param d - dialog to modify * @returns 1 on success or 0 on error */ int update_dialog_on_reply(struct sip_msg *msg, s_dialog *d) { struct hdr_field *h_req; struct hdr_field *h=0; int res=0; time_t t_time=0; str ses_exp = {0,0}; str refresher = {0,0}; str new_ses_exp = {0,0}; str new_ext = {0,0}; int expires = 0; ses_exp = cscf_get_session_expires_body(msg, &h); t_time = cscf_get_session_expires(ses_exp, &refresher); if (!t_time) //i.e not session-expires header in response { if (!d->uac_supp_timer || !d->lr_session_expires) { expires = cscf_get_expires_hdr(msg,0); if (expires >= 0) { d->expires = d_act_time()+expires; } else { d->expires = d_act_time()+scscf_dialogs_expiration_time; } } else// uac supports timer, but no session-expires header found in response { d->expires = d_act_time()+d->lr_session_expires; new_ses_exp.len = 11/*int value*/ + str_se.len+s_refresher.len+8; new_ses_exp.s = pkg_malloc(new_ses_exp.len+1); if (!new_ses_exp.s) { LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ses_exp.len); goto error; } new_ses_exp.len = snprintf(new_ses_exp.s, new_ses_exp.len, "%.*s %d; %.*suac\r\n",str_se.len, str_se.s, (int)d->lr_session_expires ,s_refresher.len, s_refresher.s); cscf_add_header(msg, &new_ses_exp, HDR_OTHER_T); if (!requires_extension(msg, &str_ext_timer)) //must have require timer extenstion { /* walk through all Require headers to find first require header*/ res = parse_headers(msg, HDR_EOH_F, 0); if (res == -1) { ERR("Error while parsing headers (%d)\n", res); return 0; /* what to return here ? */ } h_req = msg->require; while (h_req) { if (h_req->type == HDR_REQUIRE_T) { if (h_req->body.s[new_ext.len-1]=='\n') { new_ext.len = str_require.len + 1/* */+h_req->body.len + 7;/*, timer*/ new_ext.s = pkg_malloc(new_ext.len); if (!new_ext.s) { LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len); goto error; } new_ext.len = snprintf(new_ext.s, str_require.len, "%.*s %.*s, timer\r\n", str_require.len, str_require.s, h_req->body.len-2, h_req->body.s); } else { new_ext.len = str_require.len + 1/*space*/ + h_req->body.len + 9;/*, timer\r\n*/ new_ext.s = pkg_malloc(new_ext.len); if (!new_ext.s) { LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len); goto error; } new_ext.len = snprintf(new_ext.s, str_require.len, "%.*s %.*s, timer\r\n", str_require.len, str_require.s, h_req->body.len, h_req->body.s); } cscf_del_header(msg, h_req); cscf_add_header(msg, &new_ext, HDR_REQUIRE_T); break; } h_req = h_req->next; } } } } else{ d->expires = d_act_time() + t_time; d->lr_session_expires = t_time; } return 1; error: if (new_ses_exp.s) pkg_free(new_ses_exp.s); if (new_ext.s) pkg_free(new_ext.s); return 0; }