/* * Create an AVP to be used by registrar with the source IP and port * of the REGISTER */ static int fix_nated_register_f(struct sip_msg* msg, char* str1, char* str2) { contact_t* c; struct lump* anchor; char* param; str uri; if (create_rcv_uri(&uri, msg) < 0) { return -1; } if (contact_iterator(&c, msg, 0) < 0) { return -1; } while(c) { param = (char*)pkg_malloc(RECEIVED_LEN + 2 + uri.len); if (!param) { ERR("No memory left\n"); return -1; } memcpy(param, RECEIVED, RECEIVED_LEN); param[RECEIVED_LEN] = '\"'; memcpy(param + RECEIVED_LEN + 1, uri.s, uri.len); param[RECEIVED_LEN + 1 + uri.len] = '\"'; anchor = anchor_lump(msg, c->name.s + c->len - msg->buf, 0, 0); if (anchor == NULL) { ERR("anchor_lump failed\n"); return -1; } if (insert_new_lump_after(anchor, param, RECEIVED_LEN + 1 + uri.len + 1, 0) == 0) { ERR("insert_new_lump_after failed\n"); pkg_free(param); return -1; } if (contact_iterator(&c, msg, c) < 0) { return -1; } } return 1; }
static int sel_rewrite_contact(str* res, select_t* s, struct sip_msg* msg) { static char buf[500]; contact_t* c; int n, def_port_fl, len; char *cp; str hostport; struct sip_uri uri; res->len = 0; n = s->params[2].v.i; if (n <= 0) { LOG(L_ERR, "ERROR: rewrite_contact[%d]: zero or negative index not supported\n", n); return -1; } c = 0; do { if (contact_iterator(&c, msg, c) < 0 || !c) return -1; n--; } while (n > 0); if (parse_uri(c->uri.s, c->uri.len, &uri) < 0 || uri.host.len <= 0) { LOG(L_ERR, "rewrite_contact[%d]: Error while parsing Contact URI\n", s->params[2].v.i); return -1; } len = c->len - uri.host.len; if (uri.port.len > 0) len -= uri.port.len; def_port_fl = (msg->rcv.proto == PROTO_TLS && msg->rcv.src_port == SIPS_PORT) || (msg->rcv.proto != PROTO_TLS && msg->rcv.src_port == SIP_PORT); if (!def_port_fl) len += 1/*:*/+5/*port*/; if (len > sizeof(buf)) { LOG(L_ERR, "ERROR: rewrite_contact[%d]: contact too long\n", s->params[2].v.i); return -1; } hostport = uri.host; if (uri.port.len > 0) hostport.len = uri.port.s + uri.port.len - uri.host.s; res->s = buf; res->len = hostport.s - c->name.s; memcpy(buf, c->name.s, res->len); cp = ip_addr2a(&msg->rcv.src_ip); if (def_port_fl) { res->len+= snprintf(buf+res->len, sizeof(buf)-res->len, "%s", cp); } else { res->len+= snprintf(buf+res->len, sizeof(buf)-res->len, "%s:%d", cp, msg->rcv.src_port); } memcpy(buf+res->len, hostport.s+hostport.len, c->len-(hostport.s+hostport.len-c->name.s)); res->len+= c->len-(hostport.s+hostport.len-c->name.s); return 0; }
void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps) { char *uuid; str suuid; reg_uac_t *ri = NULL; contact_t* c; int expires; struct sip_uri puri; struct hdr_field *hdr; HASHHEX response; str *new_auth_hdr = NULL; static struct authenticate_body auth; struct uac_credential cred; char b_ruri[MAX_URI_SIZE]; str s_ruri; #ifdef UAC_OLD_AUTH char b_turi[MAX_URI_SIZE]; str s_turi; #endif char b_hdrs[MAX_UACH_SIZE]; str s_hdrs; uac_req_t uac_r; str method = {"REGISTER", 8}; int ret; dlg_t tmdlg; if(ps->param==NULL || *ps->param==0) { LM_DBG("uuid not received\n"); return; } uuid = *((char**)ps->param); LM_DBG("completed with status %d [uuid: %s]\n", ps->code, uuid); suuid.s = uuid; suuid.len = strlen(suuid.s); ri = reg_ht_get_byuuid(&suuid); if(ri==NULL) { LM_DBG("no user with uuid %s\n", uuid); goto done; } if(ps->code == 200) { if (parse_headers(ps->rpl, HDR_EOH_F, 0) == -1) { LM_ERR("failed to parse headers\n"); goto error; } if (ps->rpl->contact==NULL) { LM_ERR("no Contact found\n"); goto error; } if (parse_contact(ps->rpl->contact) < 0) { LM_ERR("failed to parse Contact HF\n"); goto error; } if (((contact_body_t*)ps->rpl->contact->parsed)->star) { LM_DBG("* Contact found\n"); goto done; } if (contact_iterator(&c, ps->rpl, 0) < 0) goto done; while(c) { if(parse_uri(c->uri.s, c->uri.len, &puri)!=0) { LM_ERR("failed to parse c-uri\n"); goto error; } if(suuid.len==puri.user.len && (strncmp(puri.user.s, suuid.s, suuid.len)==0)) { /* calculate expires */ expires=0; if(c->expires==NULL || c->expires->body.len<=0) { if(ps->rpl->expires!=NULL && ps->rpl->expires->body.len>0) expires = atoi(ps->rpl->expires->body.s); } else { str2int(&c->expires->body, (unsigned int*)(&expires)); } ri->timer_expires = ri->timer_expires + expires; ri->flags |= UAC_REG_ONLINE; goto done; } if (contact_iterator(&c, ps->rpl, c) < 0) { LM_DBG("local contact not found\n"); goto done; } } } if(ps->code == 401 || ps->code == 407) { if(ri->flags & UAC_REG_AUTHSENT) { LM_ERR("authentication failed for <%.*s>\n", ri->l_uuid.len, ri->l_uuid.s); goto error; } hdr = get_autenticate_hdr(ps->rpl, ps->code); if (hdr==0) { LM_ERR("failed to extract authenticate hdr\n"); goto error; } LM_DBG("auth header 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; } if (ri->realm.len>0) { /* only check if realms match if it is non-empty */ if(auth.realm.len!=ri->realm.len || strncmp(auth.realm.s, ri->realm.s, ri->realm.len)!=0) { LM_ERR("realms do not match. requested realm: [%.*s]\n", auth.realm.len, auth.realm.s); goto error; } } cred.realm = auth.realm; cred.user = ri->auth_username; cred.passwd = ri->auth_password; cred.next = NULL; snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s", ri->r_domain.len, ri->r_domain.s); s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s); do_uac_auth(&method, &s_ruri, &cred, &auth, response); new_auth_hdr=build_authorization_hdr(ps->code, &s_ruri, &cred, &auth, response); if (new_auth_hdr==0) { LM_ERR("failed to build authorization hdr\n"); goto error; } #ifdef UAC_OLD_AUTH snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s", ri->r_username.len, ri->r_username.s, ri->r_domain.len, ri->r_domain.s); s_turi.s = b_turi; s_turi.len = strlen(s_turi.s); #endif snprintf(b_hdrs, MAX_UACH_SIZE, "Contact: <sip:%.*s@%.*s>\r\n" "Expires: %d\r\n" "%.*s", ri->l_uuid.len, ri->l_uuid.s, reg_contact_addr.len, reg_contact_addr.s, ri->expires, new_auth_hdr->len, new_auth_hdr->s); s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s); pkg_free(new_auth_hdr->s); memset(&uac_r, 0, sizeof(uac_r)); if(uac_reg_tmdlg(&tmdlg, ps->rpl)<0) { LM_ERR("failed to build tm dialog\n"); goto error; } tmdlg.rem_target = s_ruri; if(ri->auth_proxy.len) tmdlg.dst_uri = ri->auth_proxy; uac_r.method = &method; uac_r.headers = &s_hdrs; uac_r.dialog = &tmdlg; uac_r.cb_flags = TMCB_LOCAL_COMPLETED; /* Callback function */ uac_r.cb = uac_reg_tm_callback; /* Callback parameter */ uac_r.cbp = (void*)uuid; #ifdef UAC_OLD_AUTH ret = uac_tmb.t_request(&uac_r, /* UAC Req */ &s_ruri, /* Request-URI */ &s_turi, /* To */ &s_turi, /* From */ (ri->auth_proxy.len)?&ri->auth_proxy:NULL /* outbound uri */ ); #endif ret = uac_tmb.t_request_within(&uac_r); if(ret<0) { LM_ERR("failed to send request with authentication for [%.*s]", ri->l_uuid.len, ri->l_uuid.s); goto error; } ri->flags |= UAC_REG_AUTHSENT; return; } else { LM_ERR("got sip response %d while registering [%.*s]\n", ps->code, ri->l_uuid.len, ri->l_uuid.s); goto error; } error: ri->flags &= ~(UAC_REG_ONGOING|UAC_REG_AUTHSENT); if(reg_retry_interval) { ri->timer_expires = time(NULL) + reg_retry_interval; } else { ri->flags |= UAC_REG_DISABLED; counter_inc(regdisabled); } done: if(ri) ri->flags &= ~(UAC_REG_ONGOING|UAC_REG_AUTHSENT); shm_free(uuid); counter_inc(regactive); }
/* * Test of REGISTER messages. Creates To-Contact pairs and compares them * against rules in allow and deny files passed as parameters. The function * iterates over all Contacts and creates a pair with To for each contact * found. That allows to restrict what IPs may be used in registrations, for * example */ static int check_register(struct sip_msg* msg, int idx) { int len; static char to_str[EXPRESSION_LENGTH + 1]; char* contact_str; contact_t* c; /* turn off control, allow any routing */ if ((!allow[idx].rules) && (!deny[idx].rules)) { LM_DBG("no rules => allow any registration\n"); return 1; } /* * Note: We do not parse the whole header field here although the message can * contain multiple Contact header fields. We try contacts one by one and if one * of them causes reject then we don't look at others, this could improve performance * a little bit in some situations */ if (parse_headers(msg, HDR_TO_F | HDR_CONTACT_F, 0) == -1) { LM_ERR("failed to parse headers\n"); return -1; } if (!msg->to) { LM_ERR("To or Contact not found\n"); return -1; } if (!msg->contact) { /* REGISTER messages that contain no Contact header field * are allowed. Such messages do not modify the contents of * the user location database anyway and thus are not harmful */ LM_DBG("no Contact found, allowing\n"); return 1; } /* Check if the REGISTER message contains start Contact and if * so then allow it */ if (parse_contact(msg->contact) < 0) { LM_ERR("failed to parse Contact HF\n"); return -1; } if (((contact_body_t*)msg->contact->parsed)->star) { LM_DBG("* Contact found, allowing\n"); return 1; } len = ((struct to_body*)msg->to->parsed)->uri.len; if (len > EXPRESSION_LENGTH) { LM_ERR("To header field is too long: %d chars\n", len); return -1; } strncpy(to_str, ((struct to_body*)msg->to->parsed)->uri.s, len); to_str[len] = '\0'; if (contact_iterator(&c, msg, 0) < 0) { return -1; } while(c) { contact_str = get_plain_uri(&c->uri); if (!contact_str) { LM_ERR("can't extract plain Contact URI\n"); return -1; } LM_DBG("looking for To: %s Contact: %s\n", to_str, contact_str); /* rule exists in allow file */ if (search_rule(allow[idx].rules, to_str, contact_str)) { if (check_all_branches) goto skip_deny; } /* rule exists in deny file */ if (search_rule(deny[idx].rules, to_str, contact_str)) { LM_DBG("deny rule found => Register denied\n"); return -1; } skip_deny: if (contact_iterator(&c, msg, c) < 0) { return -1; } } LM_DBG("no contact denied => Allowed\n"); return 1; }
/* * Update existing presentity and watcher list */ static int publish_presentity_pidf(struct sip_msg* _m, struct pdomain* _d, struct presentity* presentity, int *pchanged) { char *body = get_body(_m); presence_tuple_t *tuple = NULL; str contact = { NULL, 0 }; str basic = { NULL, 0 }; str status = { NULL, 0 }; str location = { NULL, 0 }; str site = { NULL, 0 }; str floor = { NULL, 0 }; str room = { NULL, 0 }; str packet_loss = { NULL, 0 }; double x=0, y=0, radius=0; time_t expires = act_time + default_expires; double priority = default_priority; int prescaps = 0; int flags = 0; int changed = 0; int ret = 0; flags = parse_pidf(body, &contact, &basic, &status, &location, &site, &floor, &room, &x, &y, &radius, &packet_loss, &priority, &expires, &prescaps); if (contact.len) { find_presence_tuple(&contact, presentity, &tuple); if (!tuple) { contact_t *sip_contact = NULL; /* get contact from SIP Headers*/ contact_iterator(&sip_contact, _m, NULL); if (sip_contact) { LOG(L_ERR, "publish_presentity: find tuple for contact %.*s\n", sip_contact->uri.len, sip_contact->uri.s); find_presence_tuple(&sip_contact->uri, presentity, &tuple); } } if (!tuple && new_tuple_on_publish) { new_presence_tuple(&contact, expires, presentity, &tuple); add_presence_tuple(presentity, tuple); changed = 1; } } else { tuple = presentity->tuples; } if (!tuple) { contact_t *sip_contact = NULL; /* get contact from SIP Headers*/ contact_iterator(&sip_contact, _m, NULL); if (sip_contact) { LOG(L_ERR, "publish_presentity: find tuple for contact %.*s\n", sip_contact->uri.len, sip_contact->uri.s); find_presence_tuple(&sip_contact->uri, presentity, &tuple); } } if (!tuple) { LOG(L_ERR, "publish_presentity: no tuple for %.*s\n", presentity->uri.len, presentity->uri.s); return -1; } LOG(L_INFO, "publish_presentity_pidf: -1-\n"); if (basic.len && basic.s) { int origstate = tuple->state; tuple->state = ((strcasecmp(basic.s, "online") == 0) || (strcasecmp(basic.s, "open") == 0)) ? PS_ONLINE : PS_OFFLINE; if (tuple->state != origstate) changed = 1; } if (status.len && status.s) { if (tuple->status.len && str_strcasecmp(&tuple->status, &status) != 0) changed = 1; tuple->status.len = status.len; strncpy(tuple->status.s, status.s, status.len); tuple->status.s[status.len] = 0; } LOG(L_INFO, "publish_presentity: -2-\n"); if (location.len && location.s) { if (tuple->location.loc.len && str_strcasecmp(&tuple->location.loc, &location) != 0) changed = 1; tuple->location.loc.len = location.len; strncpy(tuple->location.loc.s, location.s, location.len); tuple->location.loc.s[location.len] = 0; } else if (flags & PARSE_PIDF_LOCATION_MASK) { tuple->location.loc.len = 0; } if (site.len && site.s) { if (tuple->location.site.len && str_strcasecmp(&tuple->location.site, &site) != 0) changed = 1; tuple->location.site.len = site.len; strncpy(tuple->location.site.s, site.s, site.len); tuple->location.site.s[site.len] = 0; } else if (flags & PARSE_PIDF_LOCATION_MASK) { tuple->location.site.len = 0; } if (floor.len && floor.s) { if (tuple->location.floor.len && str_strcasecmp(&tuple->location.floor, &floor) != 0) changed = 1; tuple->location.floor.len = floor.len; strncpy(tuple->location.floor.s, floor.s, floor.len); tuple->location.floor.s[floor.len] = 0; }else if (flags & PARSE_PIDF_LOCATION_MASK) { tuple->location.floor.len = 0; } if (room.len && room.s) { if (tuple->location.room.len && str_strcasecmp(&tuple->location.room, &room) != 0) changed = 1; tuple->location.room.len = room.len; strncpy(tuple->location.room.s, room.s, room.len); tuple->location.room.s[room.len] = 0; } else if (flags & PARSE_PIDF_LOCATION_MASK) { tuple->location.room.len = 0; } if (packet_loss.len && packet_loss.s) { if (tuple->location.packet_loss.len && str_strcasecmp(&tuple->location.packet_loss, &packet_loss) != 0) changed = 1; tuple->location.packet_loss.len = packet_loss.len; strncpy(tuple->location.packet_loss.s, packet_loss.s, packet_loss.len); tuple->location.packet_loss.s[packet_loss.len] = 0; } else if (flags & PARSE_PIDF_LOCATION_MASK) { tuple->location.packet_loss.len = 0; } if (x) { if (tuple->location.x != x) changed = 1; tuple->location.x = x; } else if (flags & PARSE_PIDF_LOCATION_MASK) { tuple->location.x = 0; } if (y) { if (tuple->location.y != y) changed = 1; tuple->location.y = y; } else if (flags & PARSE_PIDF_LOCATION_MASK) { tuple->location.y = 0; } if (radius) { if (tuple->location.radius != radius) changed = 1; tuple->location.radius = radius; } else if (flags & PARSE_PIDF_LOCATION_MASK) { tuple->location.radius = 0; } if (tuple->priority != priority) { changed = 1; tuple->priority = priority; } if (tuple->expires != expires) { changed = 1; tuple->expires = expires; } #ifdef HAVE_LOCATION_PACKAGE if (use_location_package) if (site.len && floor.len && room.len && changed) { location_package_location_add_user(_d, &site, &floor, &room, presentity); } #endif /* HAVE_LOCATION_PACKAGE */ if (flags & PARSE_PIDF_PRESCAPS) { if (tuple->prescaps != prescaps) changed = 1; tuple->prescaps = prescaps; } changed = 1; if (changed) presentity->flags |= PFLAG_PRESENCE_CHANGED; LOG(L_INFO, "publish_presentity: -3-: changed=%d\n", changed); if (pchanged && changed) { *pchanged = 1; } if ((ret = db_update_presentity(presentity)) < 0) { return ret; } LOG(L_INFO, "publish_presentity: -4-\n"); return 0; }