/* Re-parsing version of build_local() function: * it builds a local CANCEL or ACK (for non-200 response) request based on * the previous INVITE which was sent out. * * Can not be used to build other type of requests! */ char *build_local_reparse(struct cell *Trans,unsigned int branch, unsigned int *len, char *method, int method_len, str *to #ifdef CANCEL_REASON_SUPPORT , struct cancel_reason *reason #endif /* CANCEL_REASON_SUPPORT */ ) { char *invite_buf, *invite_buf_end; char *cancel_buf; char *s, *s1, *d; /* source and destination buffers */ short invite_len; enum _hdr_types_t hf_type; int first_via, to_len; int cancel_buf_len; #ifdef CANCEL_REASON_SUPPORT int reason_len, code_len; struct hdr_field *reas1, *reas_last, *hdr; #endif /* CANCEL_REASON_SUPPORT */ int hadded = 0; sr_cfgenv_t *cenv = NULL; invite_buf = Trans->uac[branch].request.buffer; invite_len = Trans->uac[branch].request.buffer_len; if (!invite_buf || !invite_len) { LM_ERR("INVITE is missing\n"); goto error; } if ((*invite_buf != 'I') && (*invite_buf != 'i')) { LM_ERR("trying to build with local reparse" " for a non-INVITE request?\n"); goto error; } #ifdef CANCEL_REASON_SUPPORT reason_len = 0; reas1 = 0; reas_last = 0; /* compute reason size (if no reason or disabled => reason_len == 0)*/ if (reason && reason->cause != CANCEL_REAS_UNKNOWN){ if (likely(reason->cause > 0 && cfg_get(tm, tm_cfg, local_cancel_reason))){ /* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */ reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN + (reason->u.text.s? REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) + CRLF_LEN; } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS && !(Trans->flags & T_NO_E2E_CANCEL_REASON))) { reason_len = reason->u.packed_hdrs.len; } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL && reason->u.e2e_cancel && !(Trans->flags & T_NO_E2E_CANCEL_REASON)) { /* parse the entire cancel, to get all the Reason headers */ if(parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0)<0) { LM_WARN("failed to parse headers\n"); } for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ reason_len += hdr->len; reas_last=hdr; } } else if (unlikely(reason->cause < CANCEL_REAS_MIN)) LM_BUG("unhandled reason cause %d\n", reason->cause); } #endif /* CANCEL_REASON_SUPPORT */ invite_buf_end = invite_buf + invite_len; s = invite_buf; /* Allocate memory for the new message. The new request will be smaller than the INVITE, so the same size is enough. I just extend it with the length of new To HF to be sure. Ugly, but we avoid lots of checks and memory allocations this way */ to_len = to ? to->len : 0; #ifdef CANCEL_REASON_SUPPORT cancel_buf_len = invite_len + to_len + reason_len; #else cancel_buf_len = invite_len + to_len; #endif /* CANCEL_REASON_SUPPORT */ cancel_buf = shm_malloc(sizeof(char)*cancel_buf_len); if (!cancel_buf) { LM_ERR("cannot allocate shared memory\n"); goto error; } d = cancel_buf; /* method name + space */ append_str(d, method, method_len); *d = ' '; d++; /* skip "INVITE " and copy the rest of the line including CRLF */ s += 7; s1 = s; s = eat_line(s, invite_buf_end - s); append_str(d, s1, s - s1); cenv = sr_cfgenv_get(); /* check every header field name, we must exclude and modify some of the headers */ first_via = 1; while (s < invite_buf_end) { s1 = s; if ((*s == '\n') || (*s == '\r')) { /* end of SIP msg */ hf_type = HDR_EOH_T; } else { /* parse HF name */ s = lw_get_hf_name(s, invite_buf_end, &hf_type); } switch(hf_type) { case HDR_CSEQ_T: /* find the method name and replace it */ while ((s < invite_buf_end) && ((*s == ':') || (*s == ' ') || (*s == '\t') || ((*s >= '0') && (*s <= '9'))) ) s++; append_str(d, s1, s - s1); append_str(d, method, method_len); append_str(d, CRLF, CRLF_LEN); s = lw_next_line(s, invite_buf_end); break; case HDR_VIA_T: s = lw_next_line(s, invite_buf_end); if (first_via) { /* copy hf */ append_str(d, s1, s - s1); first_via = 0; } /* else skip this line, we need olny the first via */ break; case HDR_TO_T: if (to_len == 0) { /* there is no To tag required, just copy paste * the header */ s = lw_next_line(s, invite_buf_end); append_str(d, s1, s - s1); } else { /* use the given To HF instead of the original one */ append_str(d, to->s, to->len); /* move the pointer to the next line */ s = lw_next_line(s, invite_buf_end); } break; case HDR_FROM_T: case HDR_CALLID_T: case HDR_ROUTE_T: case HDR_MAXFORWARDS_T: /* copy hf */ s = lw_next_line(s, invite_buf_end); append_str(d, s1, s - s1); break; case HDR_REQUIRE_T: case HDR_PROXYREQUIRE_T: /* skip this line */ s = lw_next_line(s, invite_buf_end); break; case HDR_CONTENTLENGTH_T: /* copy hf name with 0 value */ append_str(d, s1, s - s1); append_str(d, ": 0" CRLF, 3 + CRLF_LEN); /* move the pointer to the next line */ s = lw_next_line(s, invite_buf_end); break; case HDR_EOH_T: /* end of SIP message found */ #ifdef CANCEL_REASON_SUPPORT /* add reason if needed */ if (reason_len) { /* if reason_len !=0, no need for any reason enabled * checks */ if (likely(reason->cause > 0)) { append_str(d, REASON_PREFIX, REASON_PREFIX_LEN); code_len=ushort2sbuf(reason->cause, d, cancel_buf_len-(int)(d-cancel_buf)); if (unlikely(code_len==0)) LM_BUG("not enough space to write reason code"); d+=code_len; if (reason->u.text.s){ append_str(d, REASON_TEXT, REASON_TEXT_LEN); *d='"'; d++; append_str(d, reason->u.text.s, reason->u.text.len); *d='"'; d++; } append_str(d, CRLF, CRLF_LEN); } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS)) { append_str(d, reason->u.packed_hdrs.s, reason->u.packed_hdrs.len); } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) { for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ append_str(d, hdr->name.s, hdr->len); if (likely(hdr==reas_last)) break; } } } #endif /* CANCEL_REASON_SUPPORT */ /* final (end-of-headers) CRLF */ append_str(d, CRLF, CRLF_LEN); *len = d - cancel_buf; /* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */ return cancel_buf; default: s = lw_next_line(s, invite_buf_end); hadded = 0; /* uac auth headers */ if(Trans->uas.request && (Trans->uas.request->msg_flags & FL_UAC_AUTH)) { if(s1 + cenv->uac_cseq_auth.len + 2 < invite_buf_end) { if(s1[cenv->uac_cseq_auth.len]==':' && strncmp(s1, cenv->uac_cseq_auth.s, cenv->uac_cseq_auth.len)==0) { hadded = 1; append_str(d, s1, s - s1); } else if(s1[cenv->uac_cseq_refresh.len]==':' && strncmp(s1, cenv->uac_cseq_refresh.s, cenv->uac_cseq_refresh.len)==0) { hadded = 1; append_str(d, s1, s - s1); } } } if(likely(hadded==0)) { if (cfg_get(tm, tm_cfg, ac_extra_hdrs).len && (s1 + cfg_get(tm, tm_cfg, ac_extra_hdrs).len < invite_buf_end) && (strncasecmp(s1, cfg_get(tm, tm_cfg, ac_extra_hdrs).s, cfg_get(tm, tm_cfg, ac_extra_hdrs).len) == 0)) { append_str(d, s1, s - s1); } } break; } } /* HDR_EOH_T was not found in the buffer, the message is corrupt */ LM_ERR("HDR_EOH_T was not found\n"); shm_free(cancel_buf); error: LM_ERR("cannot build %.*s request\n", method_len, method); return NULL; }
int dlg_cseq_msg_sent(sr_event_param_t *evp) { sip_msg_t msg; str *obuf; unsigned int direction; dlg_cell_t *dlg = NULL; str nval = STR_NULL; char tbuf[BUF_SIZE]; int tbuf_len = 0; struct via_body *via; hdr_field_t *hfk = NULL; sr_cfgenv_t *cenv = NULL; obuf = (str*)evp->data; memset(&msg, 0, sizeof(sip_msg_t)); msg.buf = obuf->s; msg.len = obuf->len; cenv = sr_cfgenv_get(); if(dlg_cseq_prepare_new_msg(&msg)!=0) { goto done; } if(msg.first_line.type==SIP_REPLY) { /* nothing to do for outgoing replies */ goto done; } LM_DBG("traking cseq updates\n"); via = (struct via_body*)msg.h_via1->parsed; if(via->branch==NULL || via->branch->value.len<=0) { LM_DBG("no branch parameter in top via\n"); goto done; } direction = DLG_DIR_NONE; dlg = dlg_lookup_msg_dialog(&msg, &direction); if(dlg == NULL) { LM_DBG("no dialog for this request\n"); goto done; } /* supported only for downstrem direction */ if(direction != DLG_DIR_DOWNSTREAM) { LM_DBG("request not going downstream (%u)\n", direction); goto done; } if(parse_headers(&msg, HDR_EOH_F, 0)==-1) { LM_ERR("failed to parse all headers\n"); } /* check if transaction is marked for a new increment */ hfk = sr_hdr_get_z(&msg, cenv->uac_cseq_auth.s); if(hfk!=NULL) { LM_DBG("new cseq inc requested\n"); nval = hfk->body; trim(&nval); } else { LM_DBG("new cseq inc not requested\n"); } if(nval.len<=0) { hfk = sr_hdr_get_z(&msg, cenv->uac_cseq_refresh.s); if(hfk!=NULL) { LM_DBG("cseq refresh requested\n"); nval = hfk->body; trim(&nval); } else { LM_DBG("cseq refresh not requested\n"); } } if(nval.len<=0) { LM_DBG("cseq refresh requested, but no new value found\n"); goto done; } if(msg.len + 3 + 2*nval.len>=BUF_SIZE) { LM_ERR("new messages is too big\n"); goto done; } LM_DBG("updating cseq to: %.*s\n", nval.len, nval.s); /* new cseq value */ dlg->iflags |= DLG_IFLAG_CSEQ_DIFF; if(via->branch->value.s<get_cseq(&msg)->number.s) { /* Via is before CSeq */ /* copy first part till after via branch */ tbuf_len = via->branch->value.s + via->branch->value.len - msg.buf; memcpy(tbuf, msg.buf, tbuf_len); /* complete via branch */ tbuf[tbuf_len++] = '.'; tbuf[tbuf_len++] = 'c'; tbuf[tbuf_len++] = 's'; memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s, get_cseq(&msg)->number.len); tbuf_len += get_cseq(&msg)->number.len; /* copy till beginning of cseq number */ memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len, get_cseq(&msg)->number.s - via->branch->value.s - via->branch->value.len); tbuf_len += get_cseq(&msg)->number.s - via->branch->value.s - via->branch->value.len; /* add new value */ memcpy(tbuf+tbuf_len, nval.s, nval.len); tbuf_len += nval.len; if(hfk && hfk->name.s > get_cseq(&msg)->number.s) { /* copy from after cseq number to the beginning of hfk */ memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len, hfk->name.s - get_cseq(&msg)->number.s - get_cseq(&msg)->number.len); tbuf_len += hfk->name.s - get_cseq(&msg)->number.s - get_cseq(&msg)->number.len; /* copy from after hfk to the end of sip message */ memcpy(tbuf+tbuf_len, hfk->name.s + hfk->len, msg.buf + msg.len - hfk->name.s - hfk->len); tbuf_len += msg.buf + msg.len - hfk->name.s - hfk->len; } else { /* copy from after cseq number to the end of sip message */ memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len, msg.buf + msg.len - get_cseq(&msg)->number.s - get_cseq(&msg)->number.len); tbuf_len += msg.buf+msg.len - get_cseq(&msg)->number.s - get_cseq(&msg)->number.len; } } else { /* CSeq is before Via */ /* copy till beginning of cseq number */ tbuf_len = get_cseq(&msg)->number.s - msg.buf; memcpy(tbuf, msg.buf, tbuf_len); /* add new value */ memcpy(tbuf+tbuf_len, nval.s, nval.len); tbuf_len += nval.len; /* copy from after cseq number to the after via branch */ memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len, via->branch->value.s + via->branch->value.len - get_cseq(&msg)->number.s - get_cseq(&msg)->number.len); tbuf_len += via->branch->value.s + via->branch->value.len - get_cseq(&msg)->number.s - get_cseq(&msg)->number.len; /* complete via branch */ tbuf[tbuf_len++] = '.'; tbuf[tbuf_len++] = 'c'; tbuf[tbuf_len++] = 's'; memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s, get_cseq(&msg)->number.len); tbuf_len += get_cseq(&msg)->number.len; if(hfk && hfk->name.s > get_cseq(&msg)->number.s) { /* copy from after via to the beginning of hfk */ memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len, hfk->name.s - via->branch->value.s - via->branch->value.len); tbuf_len += hfk->name.s - via->branch->value.s - via->branch->value.len; /* copy from after hfk to the end of sip message */ memcpy(tbuf+tbuf_len, hfk->name.s + hfk->len, msg.buf + msg.len - hfk->name.s - hfk->len); tbuf_len += msg.buf + msg.len - hfk->name.s - hfk->len; } else { /* copy from after via to the end of sip message */ memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len, msg.buf + msg.len - via->branch->value.s - via->branch->value.len); tbuf_len += msg.buf+msg.len - via->branch->value.s - via->branch->value.len; } } /* replace old msg content */ obuf->s = pkg_malloc((tbuf_len+1)*sizeof(char)); if(obuf->s==NULL) { LM_ERR("not enough memory for new message\n"); goto done; } memcpy(obuf->s, tbuf, tbuf_len); obuf->s[tbuf_len] = 0; obuf->len = tbuf_len; done: if(dlg!=NULL) dlg_release(dlg); free_sip_msg(&msg); return 0; }
int uac_auth(sip_msg_t *msg) { static struct authenticate_body auth; struct uac_credential *crd; int code, branch; struct sip_msg *rpl; struct cell *t; struct hdr_field *hdr; HASHHEX response; str *new_hdr; sr_cfgenv_t *cenv = NULL; /* get transaction */ t = uac_tmb.t_gett(); if (t==T_UNDEFINED || t==T_NULL_CELL) { LM_CRIT("no current transaction found\n"); goto error; } /* get the selected branch */ branch = uac_tmb.t_get_picked_branch(); if (branch<0) { LM_CRIT("no picked branch (%d)\n",branch); goto error; } rpl = t->uac[branch].reply; code = t->uac[branch].last_received; LM_DBG("picked reply is %p, code %d\n",rpl,code); if (rpl==0) { LM_CRIT("empty reply on picked branch\n"); goto error; } if (rpl==FAKED_REPLY) { LM_ERR("cannot process a FAKED reply\n"); goto error; } hdr = get_autenticate_hdr( rpl, code); if (hdr==0) { LM_ERR("failed to extract authenticate hdr\n"); goto error; } LM_DBG("header found; body=<%.*s>\n", hdr->body.len, hdr->body.s); if (parse_authenticate_body( &hdr->body, &auth)<0) { LM_ERR("failed to parse auth hdr body\n"); goto error; } /* can we authenticate this realm? */ crd = 0; /* first look into AVP, if set */ if ( auth_realm_spec.type!=PVT_NONE ) crd = get_avp_credential( msg, &auth.realm ); /* if not found, look into predefined credentials */ if (crd==0) crd = lookup_realm( &auth.realm ); /* found? */ if (crd==0) { LM_DBG("no credential for realm \"%.*s\"\n", auth.realm.len, auth.realm.s); goto error; } /* do authentication */ do_uac_auth( &msg->first_line.u.request.method, &t->uac[branch].uri, crd, &auth, response); /* build the authorization header */ new_hdr = build_authorization_hdr( code, &t->uac[branch].uri, crd, &auth, response); if (new_hdr==0) { LM_ERR("failed to build authorization hdr\n"); goto error; } /* so far, so good -> add the header and set the proper RURI */ if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 ) { LM_ERR("failed to apply changes\n"); goto error; } /* mark request in T with uac auth for increase of cseq via dialog * - this function is executed in failure route, msg_flags will be * reset afterwards by tm fake env */ if(t->uas.request) { t->uas.request->msg_flags |= FL_UAC_AUTH; cenv = sr_cfgenv_get(); if(cenv->cb_cseq_update != NULL) { if(cenv->cb_cseq_update(msg)<0) { goto error; } } } return 0; error: return -1; }
int dlg_cseq_refresh(sip_msg_t *msg, dlg_cell_t *dlg, unsigned int direction) { unsigned int ninc = 0; unsigned int vinc = 0; str nval; str *pval; sr_cfgenv_t *cenv = NULL; if(dlg_cseq_prepare_msg(msg)!=0) { goto error; } if(msg->first_line.type==SIP_REPLY) { /* nothing to do for outgoing replies */ goto done; } LM_DBG("initiating cseq refresh\n"); /* supported only for downstrem direction */ if(direction != DLG_DIR_DOWNSTREAM) { LM_DBG("request not going downstream (%u)\n", direction); goto done; } /* take the increment value from dialog */ if(!((dlg->iflags&DLG_IFLAG_CSEQ_DIFF)==DLG_IFLAG_CSEQ_DIFF)) { LM_DBG("no cseq refresh required\n"); goto done; } /* get dialog variable holding cseq diff */ pval = get_dlg_variable(dlg, &_dlg_cseq_diff_var_name); if(pval==NULL || pval->s==NULL || pval->len<=0) { LM_DBG("dialog marked with cseq diff but no variable set yet\n"); goto done; } if(str2int(pval, &vinc)<0) { LM_ERR("invalid dlg cseq diff var value: %.*s\n", pval->len, pval->s); goto done; } if(vinc==0) { LM_DBG("nothing to increment\n"); goto done; } str2int(&get_cseq(msg)->number, &ninc); vinc += ninc; nval.s = int2str(vinc, &nval.len); trim(&nval); LM_DBG("adding cseq refresh header value: %.*s\n", nval.len, nval.s); if(parse_headers(msg, HDR_EOH_F, 0)==-1) { LM_ERR("failed to parse all headers\n"); } cenv = sr_cfgenv_get(); sr_hdr_add_zs(msg, cenv->uac_cseq_refresh.s, &nval); done: return 0; error: return -1; }