int sca_set_called_line(struct sip_msg *msg, char *line_var) { pv_value_t value; str line; if (no_dialog_support) { LM_ERR("dialog support is disabled, cannot use this function\n"); return -1; } if (msg->REQ_METHOD != METHOD_INVITE) return 1; /* get the name of line first */ if (line_var) { /* take it from param */ if ( pv_get_spec_value( msg, (pv_spec_p)line_var, &value) < 0 ) { LM_ERR("failed to evaluate parameter\n"); return -1; } if ( (value.flags&PV_VAL_STR)==0 ) { LM_ERR("line value is not a string (flags are %d)\n",value.flags); return -1; } line = value.rs; } else { /* take it from RURI msg */ line = *GET_RURI(msg); } return sca_set_line(msg, &line, 0/*called*/); }
static int dst_to_msg(struct sip_msg *s_msg, struct sip_msg *d_msg) { /* move RURI */ if (set_ruri( d_msg, GET_RURI(s_msg))<0) { LM_ERR("failed to set new RURI\n"); return -1; } /* move DURI (empty is accepted as reset) */ if (set_dst_uri( d_msg, &s_msg->dst_uri)<0) { LM_ERR("failed to set DST URI\n"); return -1; } /* move PATH (empty is accepted as reset) */ if (set_path_vector( d_msg, & s_msg->path_vec)<0) { LM_ERR("failed to set PATH\n"); return -1; } /* Qval */ set_ruri_q( d_msg, get_ruri_q(s_msg) ); /* BFLAGS */ setb0flags( d_msg, getb0flags(s_msg) ); /* socket info */ d_msg->force_send_socket = s_msg->force_send_socket; return 0; }
static int pv_get_tm_ruri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { struct cell *t; if(msg==NULL || res==NULL) return -1; /* first get the transaction */ if (t_check( msg , 0 )==-1) return -1; if ( (t=get_t())==0) { /* no T */ if (msg!=NULL&&msg!=FAKED_REPLY && msg->first_line.type==SIP_REQUEST){ res->rs = *GET_RURI(msg); res->flags = PV_VAL_STR; return 0; } return pv_get_null(msg, param,res); } /* return the RURI for the current branch */ if (_tm_branch_index>=t->nr_of_outgoings) { LM_ERR("BUG: _tm_branch_index greater than nr_of_outgoings\n"); return -1; } res->rs = t->uac[_tm_branch_index].uri; res->flags = PV_VAL_STR; return 0; }
int w_is_gruu(sip_msg_t *msg, char *uri1, char *p2) { str s1, *s2; sip_uri_t turi; sip_uri_t *puri; if(uri1!=NULL) { if(fixup_get_svalue(msg, (gparam_p)uri1, &s1)!=0) { LM_ERR("cannot get first parameter\n"); return -8; } if(parse_uri(s1.s, s1.len, &turi)!=0) { LM_ERR("parsing of uri '%.*s' failed\n", s1.len, s1.s); return -1; } puri = &turi; } else { if(parse_sip_msg_uri(msg)<0) { s2 = GET_RURI(msg); LM_ERR("parsing of uri '%.*s' failed\n", s2->len, s2->s); return -1; } puri = &msg->parsed_uri; } if(puri->gr.s!=NULL) { if(puri->gr_val.len>0) return 1; return 2; } return -1; }
/* these wrappers parse all what may be needed; they don't care about * the result -- accounting functions just display "unavailable" if there * is nothing meaningful */ static int acc_rad_missed1(struct sip_msg *rq, char* p1, char* p2) { int code; preparse_req(rq); if (get_int_fparam(&code, rq, (fparam_t*)p1) < 0) { code = 0; } return log_request(rq, GET_RURI(rq), rq->to, code, time(0)); }
static void log_ack(struct cell* t , struct sip_msg *ack, time_t req_time) { struct sip_msg *rq; struct hdr_field *to; rq = t->uas.request; if (ack->to) to = ack->to; else to = rq->to; log_request(ack, GET_RURI(ack), to, t->uas.status, req_time); }
/* these wrappers parse all what may be needed; they don't care about * the result -- accounting functions just display "unavailable" if there * is nothing meaningful */ static int acc_db_request1(struct sip_msg *rq, char* p1, char* p2) { int code; if (get_int_fparam(&code, rq, (fparam_t*)p1) < 0) { code = 0; } preparse_req(rq); return log_request(rq, GET_RURI(rq), rq->to, acc_table.s, code, time(0)); }
/* * Converts Request-URI, if it is tel URI, to SIP URI. Returns 1, if * conversion succeeded or if no conversion was needed, i.e., Request-URI * was not tel URI. Returns -1, if conversion failed. */ int tel2sip(struct sip_msg* _msg, char* _s1, char* _s2) { str *ruri, furi; struct sip_uri pfuri; str suri; char* at; ruri = GET_RURI(_msg); if (ruri->len < 4) return 1; if (strncmp(ruri->s, "tel:", 4) != 0) return 1; if (parse_from_header(_msg) < 0) { LOG(L_ERR, "tel2sip(): Error while parsing From header\n"); return -1; } furi = get_from(_msg)->uri; if (parse_uri(furi.s, furi.len, &pfuri) < 0) { LOG(L_ERR, "tel2sip(): Error while parsing From URI\n"); return -1; } suri.len = 4 + ruri->len - 4 + 1 + pfuri.host.len + 1 + 10; suri.s = pkg_malloc(suri.len); if (suri.s == 0) { LOG(L_ERR, "tel2sip(): Memory allocation failure\n"); return -1; } at = suri.s; memcpy(at, "sip:", 4); at = at + 4; memcpy(at, ruri->s + 4, ruri->len - 4); at = at + ruri->len - 4; *at = '@'; at = at + 1; memcpy(at, pfuri.host.s, pfuri.host.len); at = at + pfuri.host.len; *at = ';'; at = at + 1; memcpy(at, "user=phone", 10); LOG(L_ERR, "tel2sip(): SIP URI is <%.*s>\n", suri.len, suri.s); if (rewrite_uri(_msg, &suri) == 1) { pkg_free(suri.s); return 1; } else { pkg_free(suri.s); return -1; } }
// Get canonical request URI static str get_canonical_request_uri(struct sip_msg* msg) { int_str value; if (!search_first_avp(canonical_uri_avp.type | AVP_VAL_STR, canonical_uri_avp.name, &value, NULL) || value.s.s==NULL || value.s.len==0) { return *GET_RURI(msg); } return value.s; }
/* * Converts Request-URI, if it is tel URI, to SIP URI. Returns 1, if * conversion succeeded or if no conversion was needed, i.e., Request-URI * was not tel URI. Returns -1, if conversion failed. */ int tel2sip(struct sip_msg* _msg, char* _s1, char* _s2) { str *ruri; struct sip_uri *pfuri; str suri; char* at; ruri = GET_RURI(_msg); if (ruri->len < 4) return 1; if (strncasecmp(ruri->s, "tel:", 4) != 0){ return 1; } if ((pfuri=parse_from_uri(_msg))==NULL) { LM_ERR("parsing From header failed\n"); return -1; } suri.len = 4 + ruri->len - 4 + 1 + pfuri->host.len + 1 + 10; suri.s = pkg_malloc(suri.len); if (suri.s == 0) { LM_ERR("no more pkg memory\n"); return -1; } at = suri.s; memcpy(at, "sip:", 4); at = at + 4; memcpy(at, ruri->s + 4, ruri->len - 4); at = at + ruri->len - 4; *at = '@'; at = at + 1; memcpy(at, pfuri->host.s, pfuri->host.len); at = at + pfuri->host.len; *at = ';'; at = at + 1; memcpy(at, "user=phone", 10); if (set_ruri(_msg, &suri) == 1) { pkg_free(suri.s); return 1; } else { pkg_free(suri.s); return -1; } }
int t_replicate(struct sip_msg *p_msg, str *dst, int flags) { /* this is a quite horrible hack -- we just take the message as is, including Route-s, Record-route-s, and Vias , forward it downstream and prevent replies received from relaying by setting the replication/local_trans bit; nevertheless, it should be good enough for the primary customer of this function, REGISTER replication if we want later to make it thoroughly, we need to introduce delete lumps for all the header fields above */ struct cell *t; if ( set_dst_uri( p_msg, dst)!=0 ) { LM_ERR("failed to set dst uri\n"); return -1; } if ( branch_uri2dset( GET_RURI(p_msg) )!=0 ) { LM_ERR("failed to convert uri to dst\n"); return -1; } t=get_t(); if (!t || t==T_UNDEFINED) { /* no transaction yet */ if (route_type==FAILURE_ROUTE) { LM_CRIT("BUG - undefined transaction in failure route\n"); return -1; } return t_relay_to( p_msg, NULL, flags|TM_T_RELAY_repl_FLAG); } else { /* transaction already created */ if (p_msg->REQ_METHOD==METHOD_ACK) /* local ACK */ return -1; t->flags|=T_IS_LOCAL_FLAG; return t_forward_nonack( t, p_msg, NULL, 1/*reset*/, 0/*unlocked*/); } }
int ds_hash_ruri(struct sip_msg *msg, unsigned int *hash) { str* uri; str key1; str key2; if(msg==NULL || hash == NULL) { LOG(L_ERR, "DISPATCHER:ds_hash_ruri: bad parameters\n"); return -1; } if (parse_sip_msg_uri(msg)<0){ LOG(L_ERR, "DISPATCHER: ds_hash_ruri: ERROR: bad request uri\n"); return -1; } uri=GET_RURI(msg); if (get_uri_hash_keys(&key1, &key2, uri, &msg->parsed_uri, ds_flags)<0) return -1; *hash = ds_get_hash(&key1, &key2); return 0; }
/* * Loads contacts in destination set into contacts_avp in reverse * priority order and associated each contact with Q_FLAG telling if * contact is the last one in its priority class. Finally, removes * all branches from destination set. */ int t_load_contacts(struct sip_msg* msg, char* key, char* value) { str uri, tmp, dst_uri, path, branch_info, *ruri; qvalue_t first_q, q; struct contact *contacts, *next, *prev, *curr; int_str val; int first_idx, idx; struct socket_info* sock; unsigned int flags; /* Check if contacts_avp has been defined */ if (contacts_avp.n == 0) { LM_ERR("feature has been disabled - " "to enable define contacts_avp module parameter"); return -1; } /* Check if anything needs to be done */ if (nr_branches == 0) { LM_DBG("t_load_contacts(): nothing to do - no branches!\n"); return 1; } ruri = (str *)0; /* Take first q from Request-URI */ ruri = GET_RURI(msg); if (!ruri) { LM_ERR("no Request-URI found\n"); return -1; } first_q = get_ruri_q(); first_idx = 0; /* Check if all q values are equal */ for(idx = first_idx; (tmp.s = get_branch(idx, &tmp.len, &q, 0, 0, 0, 0)) != 0; idx++) { if (q != first_q) { goto rest; } } LM_DBG("t_load_contacts(): nothing to do - all contacts have same q!\n"); return 1; rest: /* Allocate memory for first contact */ contacts = (struct contact *)pkg_malloc(sizeof(struct contact)); if (!contacts) { LM_ERR("no memory for contact info\n"); return -1; } /* Insert Request-URI branch to first contact */ contacts->uri.s = ruri->s; contacts->uri.len = ruri->len; contacts->dst_uri = msg->dst_uri; contacts->sock = msg->force_send_socket; getbflagsval(0, &contacts->flags); contacts->path = msg->path_vec; contacts->q = first_q; contacts->next = (struct contact *)0; /* Insert (remaining) branches to contact list in increasing q order */ for(idx = first_idx; (uri.s = get_branch(idx,&uri.len,&q,&dst_uri,&path,&flags,&sock)) != 0; idx++ ) { next = (struct contact *)pkg_malloc(sizeof(struct contact)); if (!next) { LM_ERR("no memory for contact info\n"); free_contact_list(contacts); return -1; } next->uri = uri; next->q = q; next->dst_uri = dst_uri; next->path = path; next->flags = flags; next->sock = sock; next->next = (struct contact *)0; prev = (struct contact *)0; curr = contacts; while (curr && (curr->q < q)) { prev = curr; curr = curr->next; } if (!curr) { next->next = (struct contact *)0; prev->next = next; } else { next->next = curr; if (prev) { prev->next = next; } else { contacts = next; } } } /* Assign values for q_flags */ curr = contacts; curr->q_flag = 0; while (curr->next) { if (curr->q < curr->next->q) { curr->next->q_flag = Q_FLAG; } else { curr->next->q_flag = 0; } curr = curr->next; } /* Add contacts to contacts_avp */ curr = contacts; while (curr) { if (encode_branch_info(&branch_info, curr) == 0) { LM_ERR("encoding of branch info failed\n"); free_contact_list(contacts); if (branch_info.s) pkg_free(branch_info.s); return -1; } val.s = branch_info; add_avp(contacts_avp_type|AVP_VAL_STR|(curr->q_flag), contacts_avp, val); pkg_free(branch_info.s); LM_DBG("loaded contact <%.*s> with q_flag <%d>\n", STR_FMT(&val.s), curr->q_flag); curr = curr->next; } /* Clear all branches */ clear_branches(); /* Free contact list */ free_contact_list(contacts); return 1; }
/* Actions are composed as follows: * (the action length and type as always= 5 bytes) * * TODO performance speedup: instead of using * dynamically allocated memory for headers,body,totag,reason and my_msg * use static buffers. * */ int ac_sl_msg(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len) { struct sip_msg *my_msg; str *uri; struct proxy_l *proxy; rr_t *my_route; int k,retval; //enum sip_protos proto; my_msg=NULL; k=0; proxy=0; if(!(my_msg = parse_ac_msg(HDR_EOH_F,action+k,len-k))){ LM_ERR("out of memory!\n"); goto error; } if(my_msg->first_line.type == SIP_REQUEST) LM_DBG("forwarding request:\"%.*s\" statelessly \n",my_msg->first_line.u.request.method.len+1+\ my_msg->first_line.u.request.uri.len,my_msg->first_line.u.request.method.s); else LM_DBG("forwarding reply:\"%.*s\" statelessly \n",my_msg->first_line.u.reply.status.len+1+\ my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.status.s); if (my_msg->route) { if (parse_rr(my_msg->route) < 0) { LM_ERR( "Error while parsing Route body\n"); goto error; } my_route = (rr_t*)my_msg->route->parsed; uri=&(my_route->nameaddr.uri); }else{ uri = GET_RURI(my_msg); } set_force_socket(my_msg, grep_sock_info(&my_msg->via1->host, my_msg->via1->port, my_msg->via1->proto) ); /* or also could be: my_msg->force_send_socket=the_as->binds[processor_id].bind_address; not sure which is better... */ /*proxy=uri2proxy(uri,PROTO_NONE); if (proxy==0) { LM_ERR("unable to create proxy from URI \n"); goto error; } proto=proxy->proto; */ //TODO my_msg->recvd if(0>forward_sl_request(my_msg,uri,PROTO_NONE)) goto error; retval=0; goto exit; error: retval = -1; exit: if(proxy){ free_proxy(proxy); pkg_free(proxy); } if(my_msg){ free_sip_msg_lite(my_msg); pkg_free(my_msg); } return retval; }
/* * Adds a new parameter to Request URI */ int add_uri_param(struct sip_msg* _msg, char* _param, char* _s2) { str *param, *cur_uri, new_uri; struct sip_uri *parsed_uri; char *at; param = (str*)_param; if (param->len == 0) { return 1; } if (parse_sip_msg_uri(_msg) < 0) { LM_ERR("ruri parsing failed\n"); return -1; } parsed_uri = &(_msg->parsed_uri); /* if current ruri has no headers, pad param at the end */ if (parsed_uri->headers.len == 0) { cur_uri = GET_RURI(_msg); new_uri.len = cur_uri->len + param->len + 1; if (new_uri.len > MAX_URI_SIZE) { LM_ERR("new ruri too long\n"); return -1; } new_uri.s = pkg_malloc(new_uri.len); if (new_uri.s == 0) { LM_ERR("add_uri_param(): Memory allocation failure\n"); return -1; } memcpy(new_uri.s, cur_uri->s, cur_uri->len); *(new_uri.s + cur_uri->len) = ';'; memcpy(new_uri.s + cur_uri->len + 1, param->s, param->len); if (rewrite_uri(_msg, &new_uri ) == 1) { goto ok; } else { goto nok; } } /* otherwise take the long path */ new_uri.len = 4 + (parsed_uri->user.len ? parsed_uri->user.len + 1 : 0) + (parsed_uri->passwd.len ? parsed_uri->passwd.len + 1 : 0) + parsed_uri->host.len + (parsed_uri->port.len ? parsed_uri->port.len + 1 : 0) + parsed_uri->params.len + param->len + 1 + parsed_uri->headers.len + 1; if (new_uri.len > MAX_URI_SIZE) { LM_ERR("new ruri too long\n"); return -1; } new_uri.s = pkg_malloc(new_uri.len); if (new_uri.s == 0) { LM_ERR("no more pkg memory\n"); return -1; } at = new_uri.s; memcpy(at, "sip:", 4); at = at + 4; if (parsed_uri->user.len) { memcpy(at, parsed_uri->user.s, parsed_uri->user.len); if (parsed_uri->passwd.len) { *at = ':'; at = at + 1; memcpy(at, parsed_uri->passwd.s, parsed_uri->passwd.len); at = at + parsed_uri->passwd.len; }; *at = '@'; at = at + 1; } memcpy(at, parsed_uri->host.s, parsed_uri->host.len); at = at + parsed_uri->host.len; if (parsed_uri->port.len) { *at = ':'; at = at + 1; memcpy(at, parsed_uri->port.s, parsed_uri->port.len); at = at + parsed_uri->port.len; } memcpy(at, parsed_uri->params.s, parsed_uri->params.len); at = at + parsed_uri->params.len; *at = ';'; at = at + 1; memcpy(at, param->s, param->len); at = at + param->len; *at = '?'; at = at + 1; memcpy(at, parsed_uri->headers.s, parsed_uri->headers.len); if (rewrite_uri(_msg, &new_uri) == 1) { goto ok; } nok: pkg_free(new_uri.s); return -1; ok: pkg_free(new_uri.s); return 1; }
int t_relay_to( struct sip_msg *p_msg , struct proxy_l *proxy, int proto, int replicate) { int ret; int new_tran; str *uri; int reply_ret; /* struct hdr_field *hdr; */ struct cell *t; ret=0; new_tran = t_newtran( p_msg ); /* parsing error, memory alloc, whatever ... if via is bad and we are forced to reply there, return with 0 (->break), pass error status otherwise */ if (new_tran<0) { ret = (ser_error==E_BAD_VIA && reply_to_via) ? 0 : new_tran; goto done; } /* if that was a retransmission, return we are happily done */ if (new_tran==0) { ret = 1; goto done; } /* new transaction */ /* ACKs do not establish a transaction and are fwd-ed statelessly */ if ( p_msg->REQ_METHOD==METHOD_ACK) { DBG("DEBUG:tm:t_relay: forwarding ACK statelessly \n"); if (proxy==0) { uri = GET_RURI(p_msg); proxy=uri2proxy(GET_NEXT_HOP(p_msg), proto); if (proxy==0) { ret=E_BAD_ADDRESS; goto done; } proto=proxy->proto; /* uri2proxy set it correctly */ ret=forward_request( p_msg , proxy, proto) ; free_proxy( proxy ); pkg_free( proxy ); } else { proto=get_proto(proto, proxy->proto); ret=forward_request( p_msg , proxy, proto ) ; } goto done; } /* if replication flag is set, mark the transaction as local so that replies will not be relaied */ t=get_t(); if (replicate) t->flags|=T_IS_LOCAL_FLAG; /* INVITE processing might take long, particularly because of DNS look-ups -- let upstream know we're working on it */ if (p_msg->REQ_METHOD==METHOD_INVITE ) { DBG("DEBUG:tm:t_relay: new INVITE\n"); if (!t_reply( t, p_msg , 100 , "trying -- your call is important to us")) DBG("SER: ERROR: t_reply (100)\n"); } /* now go ahead and forward ... */ ret=t_forward_nonack(t, p_msg, proxy, proto); if (ret<=0) { DBG( "ERROR:tm:t_relay_to: t_forward_nonack returned error \n"); /* we don't want to pass upstream any reply regarding replicating * a request; replicated branch must stop at us*/ if (!replicate) { reply_ret=kill_transaction( t ); if (reply_ret>0) { /* we have taken care of all -- do nothing in script */ DBG("ERROR: generation of a stateful reply " "on error succeeded\n"); ret=0; } else { DBG("ERROR: generation of a stateful reply " "on error failed\n"); } } } else { DBG( "SER: new transaction fwd'ed\n"); } done: return ret; }
/* these wrappers parse all what may be needed; they don't care about * the result -- accounting functions just display "unavailable" if there * is nothing meaningful */ static int acc_db_missed0(struct sip_msg *rq, char* s1, char* s2) { preparse_req(rq); return log_request(rq, GET_RURI(rq), rq->to, mc_table.s, 0, time(0)); }
/** * Evaluates the routing elements in locally originated request or reply to * locally originated request. * If original INVITE was in-dialog (had to-tag), it uses the * routes present there (b/c the 2xx for it does not have a RR set, normally). * Otherwise, use the reply (b/c the INVITE does not have yet the complete * route set). * * @return: negative for failure; out params: * - list: route set; * - ruri: RURI to be used in ACK; * - nexthop: where to first send the ACK. * * NOTE: assumes rpl's parsed to EOF! * */ static int eval_uac_routing(sip_msg_t *rpl, const struct retr_buf *inv_rb, str* contact, struct rte **list, str *ruri, str *next_hop) { sip_msg_t orig_inv, *sipmsg; /* reparse original INVITE */ rte_t *t, *prev_t, *rtset = NULL; int is_req; struct sip_uri puri; static size_t chklen; /* parse the retr. buffer */ memset(&orig_inv, 0, sizeof(struct sip_msg)); orig_inv.buf = inv_rb->buffer; orig_inv.len = inv_rb->buffer_len; LM_DBG("reparsing retransmission buffer of original INVITE:\n%.*s\n", (int)orig_inv.len, orig_inv.buf); if (parse_msg(orig_inv.buf, orig_inv.len, &orig_inv) != 0) { LM_ERR("failed to parse retr buffer (weird!): \n%.*s\n", (int)orig_inv.len, orig_inv.buf); return -1; } /* check if we need to look at request or reply */ if ((parse_headers(&orig_inv, HDR_TO_F, 0) < 0) || (! orig_inv.to)) { /* the bug is at message assembly */ LM_BUG("failed to parse INVITE retr. buffer and/or extract 'To' HF:" "\n%.*s\n", (int)orig_inv.len, orig_inv.buf); goto error; } if (((struct to_body *)orig_inv.to->parsed)->tag_value.len) { LM_DBG("building ACK for in-dialog INVITE (using RS in orig. INV.)\n"); if (parse_headers(&orig_inv, HDR_EOH_F, 0) < 0) { LM_BUG("failed to parse INVITE retr. buffer to EOH:" "\n%.*s\n", (int)orig_inv.len, orig_inv.buf); goto error; } sipmsg = &orig_inv; is_req = 1; } else { LM_DBG("building ACK for out-of-dialog INVITE (using RS in RR set).\n"); sipmsg = rpl; is_req = 0; } /* extract the route set */ if (get_uac_rs(sipmsg, is_req, &rtset) < 0) { LM_ERR("failed to extract route set.\n"); goto error; } if (! rtset) { /* No routes */ *ruri = *contact; *next_hop = *contact; } else if (! is_req) { /* out of dialog req. */ if (parse_uri(rtset->ptr->nameaddr.uri.s, rtset->ptr->nameaddr.uri.len, &puri) < 0) { LM_ERR("failed to parse first route in set.\n"); goto error; } if (puri.lr.s) { /* Next hop is loose router */ *ruri = *contact; *next_hop = rtset->ptr->nameaddr.uri; } else { /* Next hop is strict router */ *ruri = rtset->ptr->nameaddr.uri; *next_hop = *ruri; /* consume first route, b/c it will be put in RURI */ t = rtset; rtset = rtset->next; pkg_free(t); } } else { unsigned long route_flags = inv_rb->flags; LM_DBG("UAC rb flags: 0x%x.\n", (unsigned int)route_flags); eval_flags: switch (route_flags & (F_RB_NH_LOOSE|F_RB_NH_STRICT)) { case 0: LM_WARN("calculate_hooks() not called when built the local UAC of " "in-dialog request, or called with empty route set.\n"); /* try to figure out what kind of hop is the next one * (strict/loose) by reading the original invite */ if ((route_flags = nhop_type(&orig_inv, rtset, &inv_rb->dst, contact))) { LM_DBG("original request's next hop type evaluated to: 0x%x.\n", (unsigned int)route_flags); goto eval_flags; } else { LM_ERR("failed to establish what kind of router the next " "hop is.\n"); goto error; } break; case F_RB_NH_LOOSE: *ruri = *contact; *next_hop = rtset->ptr->nameaddr.uri; break; case F_RB_NH_STRICT: /* find ptr to last route body that contains the (possibly) old * remote target */ for (t = rtset, prev_t = NULL; t->next; prev_t = t, t = t->next) ; if ((t->ptr->len == contact->len) && (memcmp(t->ptr->nameaddr.name.s, contact->s, contact->len) == 0)){ /* the remote target didn't update -> keep the whole route set, * including the last entry */ /* do nothing */ } else { /* trash last entry and replace with new remote target */ free_rte_list(t); /* compact the rr_t struct along with rte. this way, free'ing * it can be done along with rte chunk, independent of Route * header parser's allocator (using pkg/shm) */ chklen = sizeof(struct rte) + sizeof(rr_t); if (! (t = pkg_malloc(chklen))) { ERR("out of pkg memory (%d required)\n", (int)chklen); /* last element was freed, unlink it */ if(prev_t == NULL) { /* there is only one elem in route set: the remote target */ rtset = NULL; } else { prev_t->next = NULL; } goto error; } /* this way, .free_rr is also set to 0 (!!!) */ memset(t, 0, chklen); ((rr_t *)&t[1])->nameaddr.name = *contact; ((rr_t *)&t[1])->len = contact->len; /* chain the new route elem in set */ if (prev_t == NULL) /* there is only one elem in route set: the remote target */ rtset = t; else prev_t->next = t; } *ruri = *GET_RURI(&orig_inv); /* reuse original RURI */ *next_hop = *ruri; break; default: /* probably a mem corruption */ LM_BUG("next hop of original request marked as both loose" " and strict router (buffer: %.*s).\n", inv_rb->buffer_len, inv_rb->buffer); #ifdef EXTRA_DEBUG abort(); #else goto error; #endif } } *list = rtset; free_sip_msg(&orig_inv); /* all went well */ return 0; error: free_sip_msg(&orig_inv); if (rtset) free_rte_list(rtset); return -1; }
int decode_contact_header (struct sip_msg *msg,char *unused1,char *unused2) { contact_body_t *cb; contact_t *c; str uri; str newUri; char separator; int res; #ifdef DEBUG str* ruri; fprintf (stdout,"---START--------DECODE CONTACT HEADER-----------------\n"); #endif if ((msg->contact == NULL)&&((parse_headers(msg,HDR_CONTACT_F,0) == -1) || (msg->contact== NULL) )) { LM_ERR("no Contact header present\n"); return -1; } separator = DEFAULT_SEPARATOR[0]; if (contact_flds_separator != NULL) if (strlen(contact_flds_separator)>=1) separator = contact_flds_separator[0]; #ifdef DEBUG fprintf (stdout,"Using separator %c\n",separator); ruri = GET_RURI(msg); fprintf (stdout,"[len = %d]New uri is->%.*s\n", ruri->len,ruri->len,ruri->s); ruri = &msg->first_line.u.request.uri; fprintf (stdout, "INITIAL.s=[%.*s]\n", ruri->len, ruri->s); #endif if (msg->contact->parsed == NULL) parse_contact (msg->contact); if (msg->contact->parsed != NULL) { cb = (contact_body_t *) msg->contact->parsed; c = cb->contacts; // we visit each contact if (c != NULL) { uri = c->uri; res = decode_uri (uri, separator, &newUri); #ifdef DEBUG fprintf (stdout, "newuri.s=[%.*s]\n", newUri.len, newUri.s); #endif if (res != 0) { LM_ERR("failed decoding contact.Code %d\n", res); #ifdef STRICT_CHECK return res; #endif } else if (patch (msg, uri.s, uri.len, newUri.s, newUri.len) < 0) { LM_ERR("lumping failed in mangling port \n"); return -2; } #ifdef DECODE_ALL_CONTACTS while (c->next != NULL) { c = c->next; uri = c->uri; res = decode_uri (uri, separator, &newUri); if (res != 0) { LM_ERR("failed decoding contact.Code %d\n",res); #ifdef STRICT_CHECK return res; #endif } else if (patch (msg, uri.s, uri.len, newUri.s, newUri.len) < 0) { LM_ERR("lumping failed in mangling port \n"); return -3; } } // end while #endif } // if c!= NULL } // end if else // after parsing still NULL { LM_ERR("unable to parse Contact header\n"); return -4; } #ifdef DEBUG fprintf (stdout,"---END--------DECODE CONTACT HEADER-----------------\n");fflush(stdout); #endif return 1; }
/* function returns: * 1 - forward successful * -1 - error during forward */ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , struct proxy_l * proxy, int proto) { str backup_uri; int branch_ret, lowest_ret; str current_uri; branch_bm_t added_branches; int first_branch; int i, q; struct cell *t_invite; int success_branch; int try_new; str dst_uri; /* make -Wall happy */ current_uri.s=0; set_kr(REQ_FWDED); if (p_msg->REQ_METHOD==METHOD_CANCEL) { t_invite=t_lookupOriginalT( p_msg ); if (t_invite!=T_NULL_CELL) { e2e_cancel( p_msg, t, t_invite ); UNREF(t_invite); return 1; } } /* backup current uri ... add_uac changes it */ backup_uri = p_msg->new_uri; /* if no more specific error code is known, use this */ lowest_ret=E_BUG; /* branches added */ added_branches=0; /* branch to begin with */ first_branch=t->nr_of_outgoings; /* on first-time forwarding, use current uri, later only what is in additional branches (which may be continuously refilled */ if (first_branch==0) { try_new=1; branch_ret=add_uac( t, p_msg, GET_RURI(p_msg), GET_NEXT_HOP(p_msg), proxy, proto ); if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } else try_new=0; init_branch_iterator(); while((current_uri.s=next_branch( ¤t_uri.len, &q, &dst_uri.s, &dst_uri.len))) { try_new++; branch_ret=add_uac( t, p_msg, ¤t_uri, (dst_uri.len) ? (&dst_uri) : ¤t_uri, proxy, proto); /* pick some of the errors in case things go wrong; note that picking lowest error is just as good as any other algorithm which picks any other negative branch result */ if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } /* consume processed branches */ clear_branches(); /* restore original URI */ p_msg->new_uri=backup_uri; /* don't forget to clear all branches processed so far */ /* things went wrong ... no new branch has been fwd-ed at all */ if (added_branches==0) { if (try_new==0) { LOG(L_ERR, "ERROR: t_forward_nonack: no branched for forwarding\n"); return -1; } LOG(L_ERR, "ERROR: t_forward_nonack: failure to add branches\n"); return lowest_ret; } /* send them out now */ success_branch=0; for (i=first_branch; i<t->nr_of_outgoings; i++) { if (added_branches & (1<<i)) { if (SEND_BUFFER( &t->uac[i].request)==-1) { LOG(L_ERR, "ERROR: t_forward_nonack: sending request failed\n"); if (proxy) { proxy->errors++; proxy->ok=0; } } else { success_branch++; } start_retr( &t->uac[i].request ); } } if (success_branch<=0) { ser_error=E_SEND; return -1; } return 1; }
/* function returns: * 1 - forward successful * -1 - error during forward */ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , struct proxy_l * proxy) { str backup_uri; str backup_dst; int branch_ret, lowest_ret; str current_uri; branch_bm_t added_branches; int i, q; struct cell *t_invite; int success_branch; str dst_uri; struct socket_info *bk_sock; unsigned int br_flags; unsigned int bk_br_flags; int idx; str path; str bk_path; /* make -Wall happy */ current_uri.s=0; /* before doing enything, update the t falgs from msg */ t->uas.request->flags = p_msg->flags; if (p_msg->REQ_METHOD==METHOD_CANCEL) { t_invite=t_lookupOriginalT( p_msg ); if (t_invite!=T_NULL_CELL) { t_invite->flags |= T_WAS_CANCELLED_FLAG; cancel_invite( p_msg, t, t_invite ); return 1; } } /* do not forward requests which were already cancelled*/ if (was_cancelled(t) || no_new_branches(t)) { LM_ERR("discarding fwd for a cancelled/6xx transaction\n"); ser_error = E_NO_DESTINATION; return -1; } /* backup current uri, sock and flags... add_uac changes it */ backup_uri = p_msg->new_uri; backup_dst = p_msg->dst_uri; bk_sock = p_msg->force_send_socket; bk_br_flags = getb0flags(); bk_path = p_msg->path_vec; /* check if the UAS retranmission port needs to be updated */ if ( (p_msg->msg_flags ^ t->uas.request->msg_flags) & FL_FORCE_RPORT ) su_setport( &t->uas.response.dst.to, p_msg->rcv.src_port ); /* if no more specific error code is known, use this */ lowest_ret=E_BUG; /* branches added */ added_branches=0; /* branch to begin with */ t->first_branch=t->nr_of_outgoings; /* as first branch, use current uri */ current_uri = *GET_RURI(p_msg); branch_ret = add_uac( t, p_msg, ¤t_uri, &backup_dst, &p_msg->path_vec, proxy); if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; /* ....and now add the remaining additional branches */ for( idx=0; (current_uri.s=get_branch( idx, ¤t_uri.len, &q, &dst_uri, &path, &br_flags, &p_msg->force_send_socket))!=0 ; idx++ ) { setb0flags(br_flags); branch_ret = add_uac( t, p_msg, ¤t_uri, &dst_uri, &path, proxy); /* pick some of the errors in case things go wrong; note that picking lowest error is just as good as any other algorithm which picks any other negative branch result */ if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } /* consume processed branches */ clear_branches(); /* restore original stuff */ p_msg->new_uri=backup_uri; p_msg->parsed_uri_ok = 0;/* just to be sure; add_uac may parse other uris*/ p_msg->dst_uri = backup_dst; p_msg->force_send_socket = bk_sock; p_msg->path_vec = bk_path; setb0flags(bk_br_flags); /* update on_branch, if modified */ t->on_branch = get_on_branch(); /* update flags, if changed in branch route */ t->uas.request->flags = p_msg->flags; /* things went wrong ... no new branch has been fwd-ed at all */ if (added_branches==0) { LM_ERR("failure to add branches\n"); ser_error = lowest_ret; return lowest_ret; } /* send them out now */ success_branch=0; for (i=t->first_branch; i<t->nr_of_outgoings; i++) { if (added_branches & (1<<i)) { #ifdef USE_TCP if (t->uac[i].br_flags & tcp_no_new_conn_bflag) tcp_no_new_conn = 1; #endif do { if (check_blacklists( t->uac[i].request.dst.proto, &t->uac[i].request.dst.to, t->uac[i].request.buffer.s, t->uac[i].request.buffer.len)) { LM_DBG("blocked by blacklists\n"); ser_error=E_IP_BLOCKED; } else { if (SEND_BUFFER( &t->uac[i].request)==0) { ser_error = 0; break; } LM_ERR("sending request failed\n"); ser_error=E_SEND; } /* get next dns entry */ if ( t->uac[i].proxy==0 || get_next_su( t->uac[i].proxy, &t->uac[i].request.dst.to, (ser_error==E_IP_BLOCKED)?0:1)!=0 ) break; t->uac[i].request.dst.proto = t->uac[i].proxy->proto; /* update branch */ if ( update_uac_dst( p_msg, &t->uac[i] )!=0) break; }while(1); #ifdef USE_TCP tcp_no_new_conn = 0; #endif if (ser_error) { shm_free(t->uac[i].request.buffer.s); t->uac[i].request.buffer.s = NULL; t->uac[i].request.buffer.len = 0; continue; } success_branch++; start_retr( &t->uac[i].request ); set_kr(REQ_FWDED); /* successfully sent out -> run callbacks */ if ( has_tran_tmcbs( t, TMCB_REQUEST_BUILT) ) { set_extra_tmcb_params( &t->uac[i].request.buffer, &t->uac[i].request.dst); run_trans_callbacks( TMCB_REQUEST_BUILT, t, p_msg,0, -p_msg->REQ_METHOD); } } } return (success_branch>0)?1:-1; }
/* * This function creates and submits radius authentication request as per * draft-sterman-aaa-sip-00.txt. In addition, _user parameter is included * in the request as value of a SER specific attribute type SIP-URI-User, * which can be be used as a check item in the request. Service type of * the request is Authenticate-Only. */ int radius_authorize_sterman(VALUE_PAIR** received, struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) { static char msg[4096]; VALUE_PAIR *send; UINT4 service, ser_service_type; str method, user, user_name; str *ruri; int i; send = 0; if (!(_cred && _method && _user)) { LOG(L_ERR, "radius_authorize_sterman(): Invalid parameter value\n"); return -1; } method = *_method; user = *_user; /* * Add all the user digest parameters according to the qop defined. * Most devices tested only offer support for the simplest digest. */ if (_cred->username.domain.len) { if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), _cred->username.whole.s, _cred->username.whole.len, VENDOR(attrs[A_USER_NAME].v))) { LOG(L_ERR, "radius_authorize_sterman(): Unable to add User-Name attribute\n"); goto err; } } else { user_name.len = _cred->username.user.len + _cred->realm.len + 1; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "radius_authorize_sterman(): No memory left\n"); return -3; } memcpy(user_name.s, _cred->username.whole.s, _cred->username.whole.len); user_name.s[_cred->username.whole.len] = '@'; memcpy(user_name.s + _cred->username.whole.len + 1, _cred->realm.s, _cred->realm.len); if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), user_name.s, user_name.len, VENDOR(attrs[A_USER_NAME].v))) { LOG(L_ERR, "sterman(): Unable to add User-Name attribute\n"); pkg_free(user_name.s); goto err; } pkg_free(user_name.s); } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_USER_NAME].v), _cred->username.whole.s, _cred->username.whole.len, VENDOR(attrs[A_DIGEST_USER_NAME].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-User-Name attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_REALM].v), _cred->realm.s, _cred->realm.len, VENDOR(attrs[A_DIGEST_REALM].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-Realm attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_NONCE].v), _cred->nonce.s, _cred->nonce.len, VENDOR(attrs[A_DIGEST_NONCE].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-Nonce attribute\n"); goto err; } if (use_ruri_flag < 0 || isflagset(_msg, use_ruri_flag) != 1) { ruri = &_cred->uri; } else { ruri = GET_RURI(_msg); } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_URI].v), ruri->s, ruri->len, VENDOR(attrs[A_DIGEST_URI].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-URI attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_METHOD].v), method.s, method.len, VENDOR(attrs[A_DIGEST_METHOD].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-Method attribute\n"); goto err; } /* * Add the additional authentication fields according to the QOP. */ if (_cred->qop.qop_parsed == QOP_AUTH) { if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_QOP].v), "auth", 4, VENDOR(attrs[A_DIGEST_QOP].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_NONCE_COUNT].v), _cred->nc.s, _cred->nc.len, VENDOR(attrs[A_DIGEST_NONCE_COUNT].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-CNonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_CNONCE].v), _cred->cnonce.s, _cred->cnonce.len, VENDOR(attrs[A_DIGEST_CNONCE].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-CNonce attribute\n"); goto err; } } else if (_cred->qop.qop_parsed == QOP_AUTHINT) { if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_QOP].v), "auth-int", 8, VENDOR(attrs[A_DIGEST_QOP].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_NONCE_COUNT].v), _cred->nc.s, _cred->nc.len, VENDOR(attrs[A_DIGEST_NONCE_COUNT].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-Nonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_CNONCE].v), _cred->cnonce.s, _cred->cnonce.len, VENDOR(attrs[A_DIGEST_CNONCE].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-CNonce attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_BODY_DIGEST].v), _cred->opaque.s, _cred->opaque.len, VENDOR(attrs[A_DIGEST_BODY_DIGEST].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-Body-Digest attribute\n"); goto err; } } else { /* send nothing for qop == "" */ } /* Add the response... What to calculate against... */ if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_RESPONSE].v), _cred->response.s, _cred->response.len, VENDOR(attrs[A_DIGEST_RESPONSE].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-Response attribute\n"); goto err; } /* Indicate the service type, Authenticate only in our case */ service = vals[V_SIP_SESSION].v; if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SERVICE_TYPE].v), &service, -1, VENDOR(attrs[A_SERVICE_TYPE].v))) { LOG(L_ERR, "sterman(): Unable to add Service-Type attribute\n"); goto err; } /* Indicate the service type, Authenticate only in our case */ ser_service_type = vals[V_DIGEST_AUTHENTICATION].v; if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), &ser_service_type, -1, VENDOR(attrs[A_SER_SERVICE_TYPE].v))) { LOG(L_ERR, "sterman(): Unable to add SER-Service-Type attribute\n"); goto err; } /* Add SIP URI as a check item */ if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_URI_USER].v), user.s, user.len, VENDOR(attrs[A_SER_URI_USER].v))) { LOG(L_ERR, "sterman(): Unable to add Sip-URI-User attribute\n"); goto err; } if (attrs[A_CISCO_AVPAIR].n != NULL) { if (add_cisco_vsa(&send, _msg)) { goto err; } } /* Send request */ if ((i = rc_auth(rh, SIP_PORT, send, received, msg)) == OK_RC) { DBG("radius_authorize_sterman(): Success\n"); rc_avpair_free(send); send = 0; return 1; } else { DBG("radius_authorize_sterman(): Failure\n"); goto err; } err: if (send) rc_avpair_free(send); return -1; }
/** * Evaluate if next hop is a strict or loose router, by looking at the * retr. buffer of the original INVITE. * Assumes: * orig_inv is a parsed SIP message; * rtset is not NULL. * @return: * F_RB_NH_LOOSE : next hop was loose router; * F_RB_NH_STRICT: nh is strict; * 0 on error. */ static unsigned long nhop_type(sip_msg_t *orig_inv, rte_t *rtset, const struct dest_info *dst_inv, str *contact) { struct sip_uri puri, topr_uri, lastr_uri, inv_ruri, cont_uri; struct ip_addr *uri_ia; union sockaddr_union uri_sau; unsigned int uri_port, dst_port, inv_port, cont_port, lastr_port; rte_t *last_r; #ifdef TM_LOC_ACK_DO_REV_DNS struct ip_addr ia; struct hostent *he; char **alias; #endif #define PARSE_URI(_str_, _uri_) \ do { \ /* parse_uri() 0z the puri */ \ if (parse_uri((_str_)->s, \ (_str_)->len, _uri_) < 0) { \ LM_ERR("failed to parse route body '%.*s'.\n", STR_FMT(_str_)); \ return 0; \ } \ } while (0) #define HAS_LR(_rte_) \ ({ \ PARSE_URI(&(_rte_)->ptr->nameaddr.uri, &puri); \ puri.lr.s; \ }) #define URI_PORT(_puri_, _port) \ do { \ if (! (_port = uri2port(_puri_))) \ return 0; \ } while (0) /* examine the easy/fast & positive cases foremost */ /* [1] check if 1st route lacks ;lr */ LM_DBG("checking lack of ';lr' in 1st route.\n"); if (! HAS_LR(rtset)) return F_RB_NH_STRICT; topr_uri = puri; /* save 1st route's URI */ /* [2] check if last route shows ;lr */ LM_DBG("checking presence of ';lr' in last route.\n"); for (last_r = rtset; last_r->next; last_r = last_r->next) /* scroll down to last route */ ; if (HAS_LR(last_r)) return F_RB_NH_LOOSE; /* [3] 1st route has ;lr -> check if the destination of original INV * equals the address provided by this route; if does -> loose */ LM_DBG("checking INVITE's destination against its first route.\n"); URI_PORT(&topr_uri, uri_port); if (! (dst_port = su_getport(&dst_inv->to))) return 0; /* not really expected */ if (dst_port != uri_port) return F_RB_NH_STRICT; /* if 1st route contains an IP address, comparing it against .dst */ if ((uri_ia = str2ip(&topr_uri.host)) || (uri_ia = str2ip6(&topr_uri.host)) ) { /* we have an IP address in route -> comparison can go swiftly */ if (init_su(&uri_sau, uri_ia, uri_port) < 0) return 0; /* not really expected */ if (su_cmp(&uri_sau, &dst_inv->to)) /* ;lr and sent there */ return F_RB_NH_LOOSE; else /* ;lr and NOT sent there (probably sent to RURI address) */ return F_RB_NH_STRICT; } else { /*if 1st route contains a name, rev resolve the .dst and compare*/ LM_INFO("Failed to decode string '%.*s' in route set element as IP" " address. Trying name resolution.\n",STR_FMT(&topr_uri.host)); /* TODO: alternatively, rev name and compare against dest. IP. */ #ifdef TM_LOC_ACK_DO_REV_DNS ia.af = 0; su2ip_addr(&ia, (void *)&dst_inv->to); if (! ia.af) return 0; /* not really expected */ if ((he = rev_resolvehost(&ia))) { if ((strlen(he->h_name) == topr_uri.host.len) && (memcmp(he->h_name, topr_uri.host.s, topr_uri.host.len) == 0)) return F_RB_NH_LOOSE; for (alias = he->h_aliases; *alias; alias ++) if ((strlen(*alias) == topr_uri.host.len) && (memcmp(*alias, topr_uri.host.s, topr_uri.host.len) == 0)) return F_RB_NH_LOOSE; return F_RB_NH_STRICT; } else { LM_INFO("failed to resolve address '%s' to a name.\n", ip_addr2a(&ia)); } #endif } LM_WARN("failed to establish with certainty the type of next hop;" " trying an educated guess.\n"); /* [4] compare (possibly updated) remote target to original RURI; if * equal, a strict router's address wasn't filled in as RURI -> loose */ LM_DBG("checking remote target against INVITE's RURI.\n"); PARSE_URI(contact, &cont_uri); PARSE_URI(GET_RURI(orig_inv), &inv_ruri); URI_PORT(&cont_uri, cont_port); URI_PORT(&inv_ruri, inv_port); if ((cont_port == inv_port) && (cont_uri.host.len == inv_ruri.host.len) && (memcmp(cont_uri.host.s, inv_ruri.host.s, cont_uri.host.len) == 0)) return F_RB_NH_LOOSE; /* [5] compare (possibly updated) remote target to last route; if equal, * strict router's address might have been filled as RURI and remote * target appended to route set -> strict */ LM_DBG("checking remote target against INVITE's last route.\n"); PARSE_URI(&last_r->ptr->nameaddr.uri, &lastr_uri); URI_PORT(&lastr_uri, lastr_port); if ((cont_port == lastr_port) && (cont_uri.host.len == lastr_uri.host.len) && (memcmp(cont_uri.host.s, lastr_uri.host.s, lastr_uri.host.len) == 0)) return F_RB_NH_STRICT; LM_WARN("failed to establish the type of next hop;" " assuming loose router.\n"); return F_RB_NH_LOOSE; #undef PARSE_URI #undef HAS_LR #undef URI_PORT }
/*! \brief * Loads contacts in destination set into "serial_fork" AVP in reverse * priority order and associated each contact with Q_FLAG telling if * contact is the last one in its priority class. Finally, removes * all branches from destination set. */ int serialize_branches(struct sip_msg *msg, int clean_before ) { static struct serial_contact contacts[MAX_BRANCHES]; int n, last, first, i, prev; str branch, *ruri; qvalue_t q, ruri_q; char *p; str dst_uri, path, enc_info; unsigned int flags; struct socket_info *sock_info; int_str val; int idx; /* Check if anything needs to be done */ if (nr_branches == 0) { LM_DBG("nothing to do - no branches!\n"); return 0; } ruri = GET_RURI(msg); ruri_q = get_ruri_q(); flags = getb0flags(); for (idx = 0; (branch.s = get_branch(idx,&branch.len,&q,0,0,0,0)); idx++) { if (q != ruri_q) break; } if (branch.s == 0) { LM_DBG("nothing to do - all same q!\n"); return 0; } /* reset contact array */ n = 0; /* Insert Request-URI to contact list */ enc_info.len = 3 * sizeof(long) + ruri->len + msg->dst_uri.len + msg->path_vec.len + 3; enc_info.s = (char*) pkg_malloc (enc_info.len); if (!enc_info.s) { LM_ERR("no pkg memory left\n"); goto error; /* nothing to free here */ } memset(enc_info.s, 0, enc_info.len); p = enc_info.s; LM_DBG("Msg information <%.*s,%.*s,%.*s,%d,%u>\n", ruri->len, ruri->s, msg->dst_uri.len, msg->dst_uri.s, msg->path_vec.len, msg->path_vec.s, ruri_q, flags); *((long*) p) = (long)msg->force_send_socket; p += sizeof(long); *((long*) p) = (long)flags; p += sizeof(long); *((long*) p) = (long)ruri_q; p += sizeof(long); memcpy(p , ruri->s, ruri->len); p += ruri->len + 1; memcpy(p, msg->dst_uri.s, msg->dst_uri.len); p += msg->dst_uri.len + 1; memcpy(p, msg->path_vec.s, msg->path_vec.len); contacts[n].enc_info = enc_info; contacts[n].q = ruri_q; contacts[n].next = -1; last = n; first = n; n++; /* Insert branch URIs to contact list in increasing q order */ for (idx = 0;(branch.s = get_branch(idx, &branch.len, &q, &dst_uri, &path, &flags, &sock_info)); idx++){ enc_info.len = 3 * sizeof(long) + branch.len + dst_uri.len + path.len + 3; enc_info.s = (char*) pkg_malloc (enc_info.len); if (!enc_info.s) { LM_ERR("no pkg memory left\n"); goto error_free; } memset(enc_info.s, 0, enc_info.len); p = enc_info.s; LM_DBG("Branch information <%.*s,%.*s,%.*s,%d,%u>\n", branch.len, branch.s, dst_uri.len, dst_uri.s, path.len, path.s, q, flags); *((long*) p) = (long)sock_info; p += sizeof(long); *((long*) p) = (long)flags; p += sizeof(long); *((long*) p) = (long)q; p += sizeof(long); memcpy(p , branch.s, branch.len); p += branch.len + 1; memcpy(p, dst_uri.s, dst_uri.len); p += dst_uri.len + 1; memcpy(p, path.s, path.len); contacts[n].enc_info = enc_info; contacts[n].q = q; /* insert based on q */ for (i = first, prev=-1; i != -1 && contacts[i].q < q; prev=i,i = contacts[i].next); if (i == -1) { /* append */ last = contacts[last].next = n; contacts[n].next = -1; } else { if (i == first) { /* first element */ contacts[n].next = first; first = n; } else { /* before pos i */ contacts[n].next = contacts[prev].next; contacts[prev].next = n; } } n++; } /* Assign values for q_flags */ for (i = first; contacts[i].next != -1; i = contacts[i].next) { if (contacts[i].q < contacts[contacts[i].next].q) contacts[contacts[i].next].q_flag = Q_FLAG; else contacts[contacts[i].next].q_flag = 0; } if (clean_before) destroy_avps( 0/*type*/, serial_avp, 1/*all*/); /* Add contacts to "contacts" AVP */ for (i = first; i != -1; i = contacts[i].next) { val.s = contacts[i].enc_info; if (add_avp( AVP_VAL_STR|contacts[i].q_flag, serial_avp, val)) { LM_ERR("failed to add avp\n"); goto error_free; } pkg_free(contacts[i].enc_info.s); contacts[i].enc_info.s = NULL; } /* Clear all branches */ clear_branches(); return 0; error_free: for( i=0 ; i<n ; i++) { if (contacts[i].enc_info.s) pkg_free(contacts[i].enc_info.s); } error: return -1; }
/* function triggered from reactor in order to continue the processing */ int t_resume_async(int *fd, void *param) { static struct sip_msg faked_req; static struct ua_client uac; async_ctx *ctx = (async_ctx *)param; struct cell *backup_t; struct cell *backup_cancelled_t; struct cell *backup_e2eack_t; struct usr_avp **backup_list; struct socket_info* backup_si; struct cell *t= ctx->t; int route; LM_DBG("resuming on fd %d, transaction %p \n",*fd, t); if (current_processing_ctx) { LM_CRIT("BUG - a context already set!\n"); abort(); } /* prepare for resume route */ uac.br_flags = getb0flags( t->uas.request ) ; uac.uri = *GET_RURI( t->uas.request ); if (!fake_req( &faked_req /* the fake msg to be built*/, t->uas.request, /* the template msg saved in transaction */ &t->uas, /*the UAS side of the transaction*/ &uac, /* the fake UAC */ 1 /* copy dst_uri too */) ) { LM_ERR("fake_req failed\n"); return 0; } /* enviroment setting */ current_processing_ctx = ctx->msg_ctx; backup_t = get_t(); backup_e2eack_t = get_e2eack_t(); backup_cancelled_t = get_cancelled_t(); /* fake transaction */ set_t( t ); set_cancelled_t(ctx->cancelled_t); set_e2eack_t(ctx->e2eack_t); reset_kr(); set_kr(ctx->kr); /* make available the avp list from transaction */ backup_list = set_avp_list( &t->user_avps ); /* set default send address to the saved value */ backup_si = bind_address; bind_address = t->uac[0].request.dst.send_sock; async_status = ASYNC_DONE; /* assume default status as done */ /* call the resume function in order to read and handle data */ return_code = ctx->resume_f( *fd, &faked_req, ctx->resume_param ); if (async_status==ASYNC_CONTINUE) { /* do not run the resume route */ goto restore; } else if (async_status==ASYNC_CHANGE_FD) { if (return_code<0) { LM_ERR("ASYNC_CHANGE_FD: given file descriptor shall be positive!\n"); goto restore; } else if (return_code > 0 && return_code == *fd) { /*trying to add the same fd; shall continue*/ LM_CRIT("You are trying to replace the old fd with the same fd!" "Will act as in ASYNC_CONTINUE!\n"); goto restore; } /* remove the old fd from the reactor */ reactor_del_reader( *fd, -1, IO_FD_CLOSING); *fd=return_code; /* insert the new fd inside the reactor */ if (reactor_add_reader( *fd, F_SCRIPT_ASYNC, RCT_PRIO_ASYNC, (void*)ctx)<0 ) { LM_ERR("failed to add async FD to reactor -> act in sync mode\n"); do { return_code = ctx->resume_f( *fd, &faked_req, ctx->resume_param ); if (async_status == ASYNC_CHANGE_FD) *fd=return_code; } while(async_status==ASYNC_CONTINUE||async_status==ASYNC_CHANGE_FD); goto route; } /* changed fd; now restore old state */ goto restore; } /* remove from reactor, we are done */ reactor_del_reader( *fd, -1, IO_FD_CLOSING); route: if (async_status == ASYNC_DONE_CLOSE_FD) close(*fd); /* run the resume_route (some type as the original one) */ swap_route_type(route, ctx->route_type); run_resume_route( ctx->resume_route, &faked_req); set_route_type(route); /* no need for the context anymore */ shm_free(ctx); /* free also the processing ctx if still set * NOTE: it may become null if inside the run_resume_route * another async jump was made (and context attached again * to transaction) */ if (current_processing_ctx) { context_destroy(CONTEXT_GLOBAL, current_processing_ctx); pkg_free(current_processing_ctx); } restore: /* restore original environment */ set_t(backup_t); set_cancelled_t(backup_cancelled_t); set_e2eack_t(backup_e2eack_t); /* restore original avp list */ set_avp_list( backup_list ); bind_address = backup_si; free_faked_req( &faked_req, t); current_processing_ctx = NULL; return 0; }
/* * This function creates and submits aaa authentication request as per * draft-sterman-aaa-sip-00.txt. In addition, _user parameter is included * in the request as value of a SER specific attribute type SIP-URI-User, * which can be be used as a check item in the request. Service type of * the request is Authenticate-Only. */ int aaa_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) { aaa_message *send, *received; uint32_t service; str method, user, user_name; str *ruri; send = received = NULL; if (!(_cred && _method && _user)) { LM_ERR("invalid parameter value\n"); return -1; } method = *_method; user = *_user; if ((send = proto.create_aaa_message(conn, AAA_AUTH)) == NULL) { LM_ERR("failed to create new aaa message for auth\n"); return -1; } /* * Add all the user digest parameters according to the qop defined. * Most devices tested only offer support for the simplest digest. */ if (_cred->username.domain.len) { if (proto.avp_add(conn, send, &attrs[A_USER_NAME], _cred->username.whole.s, _cred->username.whole.len, 0)) { LM_ERR("unable to add User-Name attribute\n"); goto err; } } else { user_name.len = _cred->username.user.len + _cred->realm.len + 1; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LM_ERR("no pkg memory left\n"); return -3; } memcpy(user_name.s, _cred->username.whole.s, _cred->username.whole.len); user_name.s[_cred->username.whole.len] = '@'; memcpy(user_name.s + _cred->username.whole.len + 1, _cred->realm.s, _cred->realm.len); if (proto.avp_add(conn, send, &attrs[A_USER_NAME], user_name.s, user_name.len, 0)) { LM_ERR("unable to add User-Name attribute\n"); pkg_free(user_name.s); goto err; } pkg_free(user_name.s); } if (proto.avp_add(conn, send, &attrs[A_DIGEST_USER_NAME], _cred->username.whole.s, _cred->username.whole.len, 0)) { LM_ERR("unable to add Digest-User-Name attribute\n"); goto err; } if (proto.avp_add(conn, send, &attrs[A_DIGEST_REALM], _cred->realm.s, _cred->realm.len, 0)) { LM_ERR("unable to add Digest-Realm attribute\n"); goto err; } if (proto.avp_add(conn, send, &attrs[A_DIGEST_NONCE], _cred->nonce.s, _cred->nonce.len, 0)) { LM_ERR("unable to add Digest-Nonce attribute\n"); goto err; } if (use_ruri_flag < 0 || isflagset(_msg, use_ruri_flag) != 1) { ruri = &_cred->uri; } else { ruri = GET_RURI(_msg); } if (proto.avp_add(conn, send, &attrs[A_DIGEST_URI], ruri->s, ruri->len, 0)) { LM_ERR("unable to add Digest-URI attribute\n"); goto err; } if (proto.avp_add(conn, send, &attrs[A_DIGEST_METHOD], method.s, method.len, 0)) { LM_ERR("unable to add Digest-Method attribute\n"); goto err; } /* * Add the additional authentication fields according to the QOP. */ if (_cred->qop.qop_parsed == QOP_AUTH_D) { if (proto.avp_add(conn, send, &attrs[A_DIGEST_QOP], "auth", 4, 0)) { LM_ERR("unable to add Digest-QOP attribute\n"); goto err; } if (proto.avp_add(conn, send, &attrs[A_DIGEST_NONCE_COUNT], _cred->nc.s, _cred->nc.len, 0)) { LM_ERR("unable to add Digest-CNonce-Count attribute\n"); goto err; } if (proto.avp_add(conn, send, &attrs[A_DIGEST_CNONCE], _cred->cnonce.s, _cred->cnonce.len, 0)) { LM_ERR("unable to add Digest-CNonce attribute\n"); goto err; } } else if (_cred->qop.qop_parsed == QOP_AUTHINT_D) { if (proto.avp_add(conn, send, &attrs[A_DIGEST_QOP], "auth-int", 8, 0)) { LM_ERR("unable to add Digest-QOP attribute\n"); goto err; } if (proto.avp_add(conn, send, &attrs[A_DIGEST_NONCE_COUNT], _cred->nc.s, _cred->nc.len, 0)) { LM_ERR("unable to add Digest-Nonce-Count attribute\n"); goto err; } if (proto.avp_add(conn, send, &attrs[A_DIGEST_CNONCE], _cred->cnonce.s, _cred->cnonce.len, 0)) { LM_ERR("unable to add Digest-CNonce attribute\n"); goto err; } if (proto.avp_add(conn, send, &attrs[A_DIGEST_BODY_DIGEST], _cred->opaque.s, _cred->opaque.len, 0)) { LM_ERR("unable to add Digest-Body-Digest attribute\n"); goto err; } } else { /* send nothing for qop == "" */ } /* Add the response... What to calculate against... */ if (proto.avp_add(conn, send, &attrs[A_DIGEST_RESPONSE], _cred->response.s, _cred->response.len, 0)) { LM_ERR("unable to add Digest-Response attribute\n"); goto err; } /* Indicate the service type, Authenticate only in our case */ service = vals[V_SIP_SESSION].value; if (proto.avp_add(conn, send, &attrs[A_SERVICE_TYPE], &service, -1, 0)) { LM_ERR("unable to add Service-Type attribute\n"); goto err; } /* Add SIP URI as a check item */ if (proto.avp_add(conn, send, &attrs[A_SIP_URI_USER], user.s,user.len,0)) { LM_ERR("unable to add Sip-URI-User attribute\n"); goto err; } /* Add CALL-ID in Acct-Session-Id Attribute */ if ( _msg->callid==NULL && (parse_headers(_msg, HDR_CALLID_F, 0)==-1 || _msg->callid==NULL) ) { LM_ERR("msg parsing failed or callid not present"); goto err; } if (proto.avp_add(conn, send, &attrs[A_ACCT_SESSION_ID], _msg->callid->body.s, _msg->callid->body.len, 0)) { LM_ERR("unable to add CALL-ID attribute\n"); goto err; } if (attrs[A_CISCO_AVPAIR].name != NULL) { if (add_cisco_vsa(&send, _msg)) { goto err; } } /* Send request */ if (!proto.send_aaa_request(conn, send, &received)) { LM_DBG("Success\n"); proto.destroy_aaa_message(conn, send); proto.destroy_aaa_message(conn, received); return 1; } else { #ifdef REJECT_RC /* if (i == REJECT_RC) { LM_DBG("Failure\n"); goto err; }*/ #endif LM_ERR("authorization failed\n"); } err: if (send) proto.destroy_aaa_message(conn, send); if (received) proto.destroy_aaa_message(conn, received); return -1; }
/* function returns: * 1 - forward successful * -1 - error during forward */ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , struct proxy_l * proxy, int reset_bcounter, int locked) { str reply_reason_487 = str_init("Request Terminated"); str backup_uri; str backup_dst; int branch_ret, lowest_ret; str current_uri; branch_bm_t added_branches; int i, q; struct cell *t_invite; int success_branch; str dst_uri; struct socket_info *bk_sock; unsigned int br_flags, bk_bflags; int idx; str path; str bk_path; /* make -Wall happy */ current_uri.s=0; /* before doing enything, update the t flags from msg */ t->uas.request->flags = p_msg->flags; if (p_msg->REQ_METHOD==METHOD_CANCEL) { t_invite=t_lookupOriginalT( p_msg ); if (t_invite!=T_NULL_CELL) { t_invite->flags |= T_WAS_CANCELLED_FLAG; cancel_invite( p_msg, t, t_invite, locked ); return 1; } } /* do not forward requests which were already cancelled*/ if (no_new_branches(t)) { LM_INFO("discarding fwd for a 6xx transaction\n"); ser_error = E_NO_DESTINATION; return -1; } if (was_cancelled(t)) { /* is this the first attempt of sending a branch out ? */ if (t->nr_of_outgoings==0) { /* if no other signalling was performed on the transaction * and the transaction was already canceled, better * internally generate the 487 reply here */ if (locked) t_reply_unsafe( t, p_msg , 487 , &reply_reason_487); else t_reply( t, p_msg , 487 , &reply_reason_487); } LM_INFO("discarding fwd for a cancelled transaction\n"); ser_error = E_NO_DESTINATION; return -1; } /* backup current uri, sock and flags... add_uac changes it */ backup_uri = p_msg->new_uri; backup_dst = p_msg->dst_uri; bk_sock = p_msg->force_send_socket; bk_path = p_msg->path_vec; bk_bflags = p_msg->ruri_bflags; /* advertised address/port are not changed */ /* check if the UAS retranmission port needs to be updated */ if ( (p_msg->msg_flags ^ t->uas.request->msg_flags) & FL_FORCE_RPORT ) su_setport( &t->uas.response.dst.to, p_msg->rcv.src_port ); /* if no more specific error code is known, use this */ lowest_ret=E_BUG; /* branches added */ added_branches=0; /* branch to begin with */ if (reset_bcounter) { t->first_branch=t->nr_of_outgoings; /* check if the previous branch is a PHONY one and if yes * keep it in the set of active branches; that means the * transaction had a t_wait_for_new_branches() call prior to relay() */ if ( t->first_branch>0 && (t->uac[t->first_branch-1].flags & T_UAC_IS_PHONY) ) t->first_branch--; } /* as first branch, use current uri */ current_uri = *GET_RURI(p_msg); branch_ret = add_uac( t, p_msg, ¤t_uri, &backup_dst, getb0flags(p_msg), &p_msg->path_vec, proxy); if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; /* ....and now add the remaining additional branches */ for( idx=0; (current_uri.s=get_branch( idx, ¤t_uri.len, &q, &dst_uri, &path, &br_flags, &p_msg->force_send_socket))!=0 ; idx++ ) { branch_ret = add_uac( t, p_msg, ¤t_uri, &dst_uri, br_flags, &path, proxy); /* pick some of the errors in case things go wrong; note that picking lowest error is just as good as any other algorithm which picks any other negative branch result */ if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } /* consume processed branches */ clear_branches(); /* restore original stuff */ p_msg->new_uri=backup_uri; p_msg->parsed_uri_ok = 0;/* just to be sure; add_uac may parse other uris*/ p_msg->dst_uri = backup_dst; p_msg->force_send_socket = bk_sock; p_msg->path_vec = bk_path; p_msg->ruri_bflags = bk_bflags; /* update on_branch, _only_ if modified, otherwise it overwrites * whatever it is already in the transaction */ if (get_on_branch()) t->on_branch = get_on_branch(); /* update flags, if changed in branch route */ t->uas.request->flags = p_msg->flags; /* things went wrong ... no new branch has been fwd-ed at all */ if (added_branches==0) { LM_ERR("failure to add branches\n"); ser_error = lowest_ret; return lowest_ret; } /* send them out now */ success_branch=0; for (i=t->first_branch; i<t->nr_of_outgoings; i++) { if (added_branches & (1<<i)) { if (t->uac[i].br_flags & tcp_no_new_conn_bflag) tcp_no_new_conn = 1; do { if (check_blacklists( t->uac[i].request.dst.proto, &t->uac[i].request.dst.to, t->uac[i].request.buffer.s, t->uac[i].request.buffer.len)) { LM_DBG("blocked by blacklists\n"); ser_error=E_IP_BLOCKED; } else { run_trans_callbacks(TMCB_PRE_SEND_BUFFER, t, p_msg, 0, i); if (SEND_BUFFER( &t->uac[i].request)==0) { ser_error = 0; break; } LM_ERR("sending request failed\n"); ser_error=E_SEND; } /* get next dns entry */ if ( t->uac[i].proxy==0 || get_next_su( t->uac[i].proxy, &t->uac[i].request.dst.to, (ser_error==E_IP_BLOCKED)?0:1)!=0 ) break; t->uac[i].request.dst.proto = t->uac[i].proxy->proto; /* update branch */ if ( update_uac_dst( p_msg, &t->uac[i] )!=0) break; }while(1); tcp_no_new_conn = 0; if (ser_error) { shm_free(t->uac[i].request.buffer.s); t->uac[i].request.buffer.s = NULL; t->uac[i].request.buffer.len = 0; continue; } success_branch++; start_retr( &t->uac[i].request ); set_kr(REQ_FWDED); /* successfully sent out -> run callbacks */ if ( has_tran_tmcbs( t, TMCB_REQUEST_BUILT|TMCB_MSG_SENT_OUT) ) { set_extra_tmcb_params( &t->uac[i].request.buffer, &t->uac[i].request.dst); run_trans_callbacks( TMCB_REQUEST_BUILT|TMCB_MSG_SENT_OUT, t, p_msg, 0, 0); } } } return (success_branch>0)?1:-1; }
int dialoginfo_set(struct sip_msg* msg, char* flag_pv, char* str2) { struct dlg_cell * dlg; str peer_uri= {0, 0}; /* constructed from TO display name and RURI */ struct to_body* from, peer_to_body, FROM, *to; str* ruri; int len =0,ret=-1; char flag= DLG_PUB_AB; static char buf[256]; int buf_len= 255; str flag_str; char caller_buf[256], callee_buf[256]; pv_value_t tok; peer_to_body.param_lst = FROM.param_lst = NULL; if (msg->REQ_METHOD != METHOD_INVITE) return 1; if(dlg_api.create_dlg(msg,0)< 0) { LM_ERR("Failed to create dialog\n"); return -1; } dlg = dlg_api.get_dlg(); LM_DBG("new INVITE dialog created: from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); from = get_from(msg); /* if defined overwrite */ if(caller_spec_param.s) /* if parameter defined */ { memset(&tok, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, &caller_spec, &tok) < 0) /* if value set */ { LM_ERR("Failed to get caller value\n"); return -1; } if(tok.flags&PV_VAL_STR) { str caller_str; if(tok.rs.len + CRLF_LEN > buf_len) { LM_ERR("Buffer overflow"); return -1; } trim(&tok.rs); memcpy(caller_buf, tok.rs.s, tok.rs.len); len = tok.rs.len; if(strncmp(tok.rs.s+len-CRLF_LEN, CRLF, CRLF_LEN)) { memcpy(caller_buf + len, CRLF, CRLF_LEN); len+= CRLF_LEN; } parse_to(caller_buf, caller_buf+len , &FROM); if(FROM.error != PARSE_OK) { LM_ERR("Failed to parse caller specification - not a valid uri\n"); goto end; } from = &FROM; caller_str.s = caller_buf; caller_str.len = len; LM_DBG("caller: %*s- len= %d\n", len, caller_buf, len); /* store caller in a dlg variable */ if(dlg_api.store_dlg_value(dlg, &entity_dlg_var, &caller_str)< 0) { LM_ERR("Failed to store dialog ruri\n"); goto end; } } } peer_uri.s = callee_buf; if(callee_spec_param.s) { memset(&tok, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, &callee_spec, &tok) < 0) { LM_ERR("Failed to get callee value\n"); goto end; } if(tok.flags&PV_VAL_STR) { if(tok.rs.len + CRLF_LEN > buf_len) { LM_ERR("Buffer overflow"); goto end; } trim(&tok.rs); memcpy(peer_uri.s, tok.rs.s, tok.rs.len); len = tok.rs.len; if(strncmp(tok.rs.s+len-CRLF_LEN, CRLF, CRLF_LEN)) { memcpy(peer_uri.s + len, CRLF, CRLF_LEN); len+= CRLF_LEN; } peer_uri.len = len; } else goto default_callee; } else { default_callee: ruri = GET_RURI(msg); to = get_to(msg); len= to->display.len + 2 + ruri->len + CRLF_LEN; if(len > buf_len) { LM_ERR("Buffer overflow\n"); goto end; } len = 0; if(to->display.len && to->display.s) { memcpy(peer_uri.s, to->display.s, to->display.len); peer_uri.s[to->display.len]='<'; len = to->display.len + 1; } memcpy(peer_uri.s + len, ruri->s, ruri->len); len+= ruri->len; if(to->display.len) { peer_uri.s[len++]='>'; } memcpy(peer_uri.s + len, CRLF, CRLF_LEN); len+= CRLF_LEN; peer_uri.len = len; } LM_DBG("Peer uri = %.*s\n", peer_uri.len, peer_uri.s); parse_to(peer_uri.s, peer_uri.s+peer_uri.len, &peer_to_body); if(peer_to_body.error != PARSE_OK) { LM_ERR("Failed to peer uri [%.*s]\n", peer_uri.len, peer_uri.s); goto end; } /* store peer uri in dialog structure */ if(dlg_api.store_dlg_value(dlg, &peer_dlg_var, &peer_uri)< 0) { LM_ERR("Failed to store dialog ruri\n"); goto end; } /* store flag, if defined */ if(flag_pv) { if(pv_printf(msg, (pv_elem_t*)flag_pv, buf, &buf_len)<0) { LM_ERR("cannot print the format\n"); goto end; } if(!check_flag(buf, buf_len)) { LM_ERR("Wrong value for flag\n"); goto end; } flag = buf[0]; flag_str.s = buf; flag_str.len = buf_len; if(dlg_api.store_dlg_value(dlg, &flag_dlg_var, &flag_str)< 0) { LM_ERR("Failed to store dialog ruri\n"); goto end; } } /* register dialog callbacks which triggers sending PUBLISH */ if (dlg_api.register_dlgcb(dlg, DLGCB_FAILED| DLGCB_CONFIRMED | DLGCB_TERMINATED | DLGCB_EXPIRED | DLGCB_RESPONSE_WITHIN | DLGCB_EARLY, __dialog_sendpublish, 0, 0) != 0) { LM_ERR("cannot register callback for interesting dialog types\n"); goto end; } #ifdef PUA_DIALOGINFO_DEBUG /* dialog callback testing (registered last to be executed first) */ if (dlg_api.register_dlgcb(dlg, DLGCB_FAILED| DLGCB_CONFIRMED | DLGCB_REQ_WITHIN | DLGCB_TERMINATED | DLGCB_EXPIRED | DLGCB_EARLY | DLGCB_RESPONSE_FWDED | DLGCB_RESPONSE_WITHIN | DLGCB_MI_CONTEXT | DLGCB_DESTROY, __dialog_cbtest, NULL, NULL) != 0) { LM_ERR("cannot register callback for all dialog types\n"); goto end; } #endif if(publish_on_trying) { if(flag == DLG_PUB_A || flag == DLG_PUB_AB) dialog_publish("trying", from, &peer_to_body, &(dlg->callid), 1, DEFAULT_CREATED_LIFETIME, 0, 0); if(flag == DLG_PUB_B || flag == DLG_PUB_AB) dialog_publish("trying", &peer_to_body, from, &(dlg->callid), 0, DEFAULT_CREATED_LIFETIME, 0, 0); } ret=1; end: if (peer_to_body.param_lst) free_to_params(&peer_to_body); if (FROM.param_lst) free_to_params(&FROM); return ret; }
/* * Send a request using data from the dialog structure */ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp,release_tmcb_param release_func) { union sockaddr_union to_su, new_to_su; struct cell *new_cell; struct cell *backup_cell; struct retr_buf *request; static struct sip_msg *req; struct usr_avp **backup; char *buf, *buf1; int buf_len, buf_len1; int ret, flags, sflag_bk; int backup_route_type; int sip_msg_len; unsigned int hi; struct socket_info *new_send_sock; str h_to, h_from, h_cseq, h_callid; struct proxy_l *proxy, *new_proxy; unsigned short dst_changed; ret=-1; /*** added by dcm * - needed by external ua to send a request within a dlg */ if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0) goto error3; if(dialog->obp.s) dialog->hooks.next_hop = &dialog->obp; LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); /* calculate the socket corresponding to next hop */ proxy = uri2proxy( dialog->hooks.next_hop, dialog->send_sock ? dialog->send_sock->proto : PROTO_NONE ); if (proxy==0) { ret=E_BAD_ADDRESS; goto error3; } /* use the first address */ hostent2su( &to_su, &proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT); /* check/discover the send socket */ if (dialog->send_sock) { /* if already set, the protocol of send sock must have the the same type as the proto required by destination URI */ if (proxy->proto != dialog->send_sock->proto) dialog->send_sock = NULL; } if (dialog->send_sock==NULL) { /* get the send socket */ dialog->send_sock = get_send_socket( NULL/*msg*/, &to_su, proxy->proto); if (!dialog->send_sock) { LM_ERR("no corresponding socket for af %d\n", to_su.s.sa_family); ser_error = E_NO_SOCKET; goto error2; } } LM_DBG("sending socket is %.*s \n", dialog->send_sock->name.len,dialog->send_sock->name.s); /* ***** Create TRANSACTION and all related ***** */ new_cell = build_cell( NULL/*msg*/, 1/*full UAS clone*/); if (!new_cell) { ret=E_OUT_OF_MEM; LM_ERR("short of cell shmem\n"); goto error2; } /* pass the transaction flags from dialog to transaction */ new_cell->flags |= dialog->T_flags; /* add the callback the transaction for LOCAL_COMPLETED event */ flags = TMCB_LOCAL_COMPLETED; /* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */ if (pass_provisional_replies || pass_provisional(new_cell)) flags |= TMCB_LOCAL_RESPONSE_OUT; if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){ ret=E_OUT_OF_MEM; LM_ERR("short of tmcb shmem\n"); goto error2; } if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0) new_cell->flags |= T_IS_INVITE_FLAG; new_cell->flags |= T_IS_LOCAL_FLAG; request = &new_cell->uac[0].request; if (dialog->forced_to_su.s.sa_family == AF_UNSPEC) request->dst.to = to_su; else request->dst.to = dialog->forced_to_su; request->dst.send_sock = dialog->send_sock; request->dst.proto = dialog->send_sock->proto; request->dst.proto_reserved1 = 0; hi=dlg2hash(dialog); LOCK_HASH(hi); insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); /* copy AVPs into transaction */ new_cell->user_avps = dialog->avps; dialog->avps = NULL; /* ***** Create the message buffer ***** */ buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len); if (!buf) { LM_ERR("failed to build message\n"); ret=E_OUT_OF_MEM; goto error1; } if (local_rlist.a) { LM_DBG("building sip_msg from buffer\n"); req = buf_to_sip_msg(buf, buf_len, dialog); if (req==NULL) { LM_ERR("failed to build sip_msg from buffer\n"); } else { /* set this transaction as active one */ backup_cell = get_t(); set_t( new_cell ); /* set transaction AVP list */ backup = set_avp_list( &new_cell->user_avps ); /* backup script flags */ sflag_bk = getsflags(); /* disable parallel forking */ set_dset_state( 0 /*disable*/); /* run the route */ swap_route_type( backup_route_type, LOCAL_ROUTE); run_top_route( local_rlist.a, req); set_route_type( backup_route_type ); /* transfer current message context back to t */ new_cell->uac[0].br_flags = getb0flags(req); /* restore the prevoius active transaction */ set_t( backup_cell ); set_dset_state( 1 /*enable*/); setsflagsval(sflag_bk); set_avp_list( backup ); /* check for changes - if none, do not regenerate the buffer */ dst_changed = 1; if (req->new_uri.s || req->force_send_socket!=dialog->send_sock || req->dst_uri.len != dialog->hooks.next_hop->len || memcmp(req->dst_uri.s,dialog->hooks.next_hop->s,req->dst_uri.len) || (dst_changed=0)==0 || req->add_rm || req->body_lumps){ new_send_sock = NULL; /* do we also need to change the destination? */ if (dst_changed) { /* calculate the socket corresponding to next hop */ new_proxy = uri2proxy( req->dst_uri.s ? &(req->dst_uri) : &req->new_uri, PROTO_NONE ); if (new_proxy==0) goto abort_update; /* use the first address */ hostent2su( &new_to_su, &new_proxy->host, new_proxy->addr_idx, new_proxy->port ? new_proxy->port:SIP_PORT); /* get the send socket */ new_send_sock = get_send_socket( req, &new_to_su, new_proxy->proto); if (!new_send_sock) { free_proxy( new_proxy ); pkg_free( new_proxy ); LM_ERR("no socket found for the new destination\n"); goto abort_update; } } /* if interface change, we need to re-build the via */ if (new_send_sock && new_send_sock != dialog->send_sock) { LM_DBG("Interface change in local route -> " "rebuilding via\n"); if (!del_lump(req,req->h_via1->name.s - req->buf, req->h_via1->len,0)) { LM_ERR("Failed to remove initial via \n"); goto abort_update; } memcpy(req->add_to_branch_s,req->via1->branch->value.s, req->via1->branch->value.len); req->add_to_branch_len = req->via1->branch->value.len; /* update also info about new destination and send sock */ dialog->send_sock = new_send_sock; free_proxy( proxy ); pkg_free( proxy ); proxy = new_proxy; request->dst.send_sock = new_send_sock; request->dst.proto = new_send_sock->proto; request->dst.proto_reserved1 = 0; /* build the shm buffer now */ set_init_lump_flags(LUMPFLAG_BRANCH); buf1 = build_req_buf_from_sip_req(req, (unsigned int*)&buf_len1, new_send_sock, new_send_sock->proto, MSG_TRANS_SHM_FLAG); reset_init_lump_flags(); del_flaged_lumps( &req->add_rm, LUMPFLAG_BRANCH); } else { LM_DBG("Change in local route -> rebuilding buffer\n"); /* build the shm buffer now */ buf1 = build_req_buf_from_sip_req(req, (unsigned int*)&buf_len1, dialog->send_sock, dialog->send_sock->proto, MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG); /* now as it used, hide the original VIA header */ del_lump(req,req->h_via1->name.s - req->buf, req->h_via1->len, 0); } if (!buf1) { LM_ERR("no more shm mem\n"); /* keep original buffer */ goto abort_update; } /* update shortcuts */ if(!req->add_rm && !req->new_uri.s) { /* headers are not affected, simply tranlate */ new_cell->from.s = new_cell->from.s - buf + buf1; new_cell->to.s = new_cell->to.s - buf + buf1; new_cell->callid.s = new_cell->callid.s - buf + buf1; new_cell->cseq_n.s = new_cell->cseq_n.s - buf + buf1; } else { /* use heavy artilery :D */ if (extract_ftc_hdrs( buf1, buf_len1, &h_from, &h_to, &h_cseq, &h_callid)!=0 ) { LM_ERR("failed to update shortcut pointers\n"); shm_free(buf1); goto abort_update; } new_cell->from = h_from; new_cell->to = h_to; new_cell->callid = h_callid; new_cell->cseq_n = h_cseq; } /* here we rely on how build_uac_req() builds the first line */ new_cell->uac[0].uri.s = buf1 + req->first_line.u.request.method.len + 1; new_cell->uac[0].uri.len = GET_RURI(req)->len; /* update also info about new destination and send sock */ if (new_send_sock) request->dst.to = new_to_su; shm_free(buf); buf = buf1; buf_len = buf_len1; /* use new buffer */ } else { /* no changes over the message, buffer is already generated, just hide the original VIA for potential further branches */ del_lump(req,req->h_via1->name.s-req->buf,req->h_via1->len,0); } abort_update: /* save the SIP message into transaction */ new_cell->uas.request = sip_msg_cloner( req, &sip_msg_len, 1); if (new_cell->uas.request==NULL) { /* reset any T triggering */ new_cell->on_negative = 0; new_cell->on_reply = 0; } else { new_cell->uas.end_request= ((char*)new_cell->uas.request)+sip_msg_len; } /* no parallel support in UAC transactions */ new_cell->on_branch = 0; free_sip_msg(req); } } /* for DNS based failover, copy the DNS proxy into transaction */ if (!disable_dns_failover) { new_cell->uac[0].proxy = shm_clone_proxy( proxy, 1/*do_free*/); if (new_cell->uac[0].proxy==NULL) LM_ERR("failed to store DNS info -> no DNS based failover\n"); } new_cell->method.s = buf; new_cell->method.len = method->len; request->buffer.s = buf; request->buffer.len = buf_len; new_cell->nr_of_outgoings++; if(last_localT) { *last_localT = new_cell; REF_UNSAFE(new_cell); } if (SEND_BUFFER(request) == -1) { LM_ERR("attempt to send to '%.*s' failed\n", dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); } if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) { t_release_transaction(new_cell); } else { start_retr(request); } free_proxy( proxy ); pkg_free( proxy ); return 1; error1: LOCK_HASH(hi); remove_from_hash_table_unsafe(new_cell); UNLOCK_HASH(hi); free_cell(new_cell); error2: free_proxy( proxy ); pkg_free( proxy ); error3: return ret; }
/* * This function creates and submits radius authentication request as per * draft-sterman-aaa-sip-00.txt. In addition, _user parameter is included * in the request as value of a SER specific attribute type SIP-URI-User, * which can be be used as a check item in the request. Service type of * the request is Authenticate-Only. */ int radius_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) { static char msg[4096]; VALUE_PAIR *send, *received; uint32_t service; str method, user, user_name; str *ruri; int extra_cnt, offset, i; send = received = 0; if (!(_cred && _method && _user)) { LM_ERR("invalid parameter value\n"); return -1; } method = *_method; user = *_user; /* * Add all the user digest parameters according to the qop defined. * Most devices tested only offer support for the simplest digest. */ if (_cred->username.domain.len || !append_realm_to_username) { if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, _cred->username.whole.s, _cred->username.whole.len, 0)) { LM_ERR("unable to add User-Name attribute\n"); goto err; } } else { user_name.len = _cred->username.user.len + _cred->realm.len + 1; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LM_ERR("no pkg memory left\n"); return -3; } memcpy(user_name.s, _cred->username.whole.s, _cred->username.whole.len); user_name.s[_cred->username.whole.len] = '@'; memcpy(user_name.s + _cred->username.whole.len + 1, _cred->realm.s, _cred->realm.len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LM_ERR("unable to add User-Name attribute\n"); pkg_free(user_name.s); goto err; } pkg_free(user_name.s); } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_USER_NAME].v, _cred->username.whole.s, _cred->username.whole.len, 0)) { LM_ERR("unable to add Digest-User-Name attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_REALM].v, _cred->realm.s, _cred->realm.len, 0)) { LM_ERR("unable to add Digest-Realm attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE].v, _cred->nonce.s, _cred->nonce.len, 0)) { LM_ERR("unable to add Digest-Nonce attribute\n"); goto err; } if (use_ruri_flag < 0 || isflagset(_msg, use_ruri_flag) != 1) { ruri = &_cred->uri; } else { ruri = GET_RURI(_msg); } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_URI].v, ruri->s, ruri->len, 0)) { LM_ERR("unable to add Digest-URI attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_METHOD].v, method.s, method.len, 0)) { LM_ERR("unable to add Digest-Method attribute\n"); goto err; } /* * Add the additional authentication fields according to the QOP. */ if (_cred->qop.qop_parsed == QOP_AUTH) { if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v, "auth", 4, 0)) { LM_ERR("unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v, _cred->nc.s, _cred->nc.len, 0)) { LM_ERR("unable to add Digest-CNonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v, _cred->cnonce.s, _cred->cnonce.len, 0)) { LM_ERR("unable to add Digest-CNonce attribute\n"); goto err; } } else if (_cred->qop.qop_parsed == QOP_AUTHINT) { if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v, "auth-int", 8, 0)) { LM_ERR("unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v, _cred->nc.s, _cred->nc.len, 0)) { LM_ERR("unable to add Digest-Nonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v, _cred->cnonce.s, _cred->cnonce.len, 0)) { LM_ERR("unable to add Digest-CNonce attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_BODY_DIGEST].v, _cred->opaque.s, _cred->opaque.len, 0)) { LM_ERR("unable to add Digest-Body-Digest attribute\n"); goto err; } } else { /* send nothing for qop == "" */ } /* Add the response... What to calculate against... */ if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_RESPONSE].v, _cred->response.s, _cred->response.len, 0)) { LM_ERR("unable to add Digest-Response attribute\n"); goto err; } /* Indicate the service type, Authenticate only in our case */ service = vals[V_SIP_SESSION].v; if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("unable to add Service-Type attribute\n"); goto err; } /* Add SIP URI as a check item */ if (!rc_avpair_add(rh,&send,attrs[A_SIP_URI_USER].v,user.s,user.len,0)) { LM_ERR("unable to add Sip-URI-User attribute\n"); goto err; } if (attrs[A_CISCO_AVPAIR].n != NULL) { if (add_cisco_vsa(&send, _msg)) { goto err; } } /* Add extra attributes */ extra_cnt = extra2strar(auth_extra, _msg, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of extra attributes\n"); goto err; } offset = A_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } /* Send request */ if ((i = rc_auth(rh, SIP_PORT, send, &received, msg)) == OK_RC) { LM_DBG("Success\n"); rc_avpair_free(send); send = 0; generate_avps(received); rc_avpair_free(received); return 1; } else { #ifdef REJECT_RC if (i == REJECT_RC) { LM_DBG("Failure\n"); goto err; } #endif LM_ERR("authorization failed. RC auth returned %d\n", i); } err: if (send) rc_avpair_free(send); if (received) rc_avpair_free(received); return -1; }