/** * 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; }
/** * Look for Security-Verify and delete it if found. * @param msg - the SIP message to add to * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not found or #CSCF_RETURN_FALSE on error */ int P_remove_security_verify(struct sip_msg *msg,char *str1,char*str2) { struct hdr_field *hdr=0; for(hdr=cscf_get_next_header(msg,s_security_verify,0);hdr;hdr=cscf_get_next_header(msg,s_security_verify,hdr)){ if (!cscf_del_header(msg,hdr)){ LOG(L_INFO,"INF:"M_NAME":P_remove_security_verify: Error dropping Security-Client header.\n"); return CSCF_RETURN_ERROR; } } return CSCF_RETURN_TRUE; }
/** * Applies Privacy for P-Asserted-Identity. * @param msg - the SIP message * @returns #CSCF_RETURN_TRUE if privacy applied or #CSCF_RETURN_FALSE if not */ int apply_privacy_id(struct sip_msg* msg){ struct hdr_field *hdr; LOG(L_DBG, "DBG:"M_NAME": apply_privacy_id\n"); hdr = cscf_get_next_header(msg,asserted_identity,NULL); if (!hdr) return CSCF_RETURN_FALSE; do { cscf_del_header(msg,hdr); hdr=cscf_get_next_header(msg,asserted_identity,hdr); } while (hdr); return CSCF_RETURN_TRUE; }
/** * Remove from <str1> headers the <str2> tag * \note Does not work if you call it multiple times for the same hdr_name! * \note Because of the note above, this needs a fix to accept multiple tags in the str2 parameter! * @param msg - SIP Request * @param str1 - the header to remove from * @param str2 - the tag to remove * @returns #CSCF_RETURN_TRUE if removed, #CSCF_RETURN_FALSE if no changes required or #CSCF_RETURN_FALSE on error */ int P_remove_header_tag(struct sip_msg *msg,char *str1, char *str2) { str hdr_name,tag,x,y; struct hdr_field *hdr; char *c; int found,i,j,changed=0; hdr_name.s = str1; hdr_name.len = strlen(str1); tag.s = str2; tag.len = strlen(str2); hdr = cscf_get_header(msg,hdr_name); while (hdr){ /* get the original body */ x = hdr->body; LOG(L_INFO,"DBG:"M_NAME":P_remove_header_tag(): Original <%.*s> -> <%.*s>\n", hdr_name.len,hdr_name.s,x.len,x.s); /* duplicate the original body */ x.len++; STR_PKG_DUP(y,x,"P_remove_header_tag"); if (!y.s) goto error; y.len--; y.s[y.len]=0; /* look for occurences of tag and overwrite with \0 */ found=0; c = strtok(y.s," \t\r\n,"); while (c){ if (strlen(c)==tag.len && strncasecmp(c,tag.s,tag.len)==0){ found++; memset(c,0,tag.len); } c = strtok(0," \t\r\n,"); } /* if not found just skip to next header */ if (!found) goto next; /* compact the remaining tags by removing the \0 */ for(i=0,j=0;i<y.len;i++) if (y.s[i]!=0){ y.s[j++]=y.s[i]; } else { if (j!=0) y.s[j++]=','; while(i+1<y.len && y.s[i+1]==0) i++; } y.len = j; if (y.s[y.len-1]==',') y.len--; LOG(L_INFO,"DBG:"M_NAME":P_remove_header_tag(): Modified <%.*s> -> <%.*s>\n", hdr_name.len,hdr_name.s,y.len,y.s); /* write the changes */ if (y.len){ /* replace just the content */ if (!cscf_replace_string(msg,x,y)){ LOG(L_ERR,"ERR:"M_NAME":P_remove_header_tag(): Error replacing string!\n"); if (y.s) pkg_free(y.s); goto error; } }else{ /* remove the whole header */ if (y.s) pkg_free(y.s); if (!cscf_del_header(msg,hdr)){ LOG(L_ERR,"ERR:"M_NAME":P_remove_header_tag(): Error removing the whole header!\n"); goto error; } } changed++; next: hdr = cscf_get_next_header(msg,hdr_name,hdr); } return changed?CSCF_RETURN_TRUE:CSCF_RETURN_FALSE; error: out_of_memory: return CSCF_RETURN_ERROR; }
/** * 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; }