1 /*
2 * $Id$
3 *
4 * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
5 * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
6 *
7 * The initial version of this code was written by Dragos Vingarzan
8 * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
9 * Fruanhofer Institute. It was and still is maintained in a separate
10 * branch of the original SER. We are therefore migrating it to
11 * Kamailio/SR and look forward to maintaining it from here on out.
12 * 2011/2012 Smile Communications, Pty. Ltd.
13 * ported/maintained/improved by
14 * Jason Penton (jason(dot)penton(at)smilecoms.com and
15 * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
16 * effort to add full IMS support to Kamailio/SR using a new and
17 * improved architecture
18 *
19 * NB: Alot of this code was originally part of OpenIMSCore,
20 * FhG Fokus.
21 * Copyright (C) 2004-2006 FhG Fokus
22 * Thanks for great work! This is an effort to
23 * break apart the various CSCF functions into logically separate
24 * components. We hope this will drive wider use. We also feel
25 * that in this way the architecture is more complete and thereby easier
26 * to manage in the Kamailio/SR environment
27 *
28 * This file is part of Kamailio, a free SIP server.
29 *
30 * Kamailio is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version
34 *
35 * Kamailio is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
43 *
44 */
45
46 #include "third_party_reg.h"
47 #include "../../core/msg_translator.h"
48
49 extern usrloc_api_t isc_ulb;/*!< Structure containing pointers to usrloc functions*/
50
51 /*! \brief
52 * Combines all Path HF bodies into one string.
53 */
build_path_vector(struct sip_msg * _m,str * path,str * received)54 int build_path_vector(struct sip_msg *_m, str *path, str *received) {
55 static char buf[MAX_PATH_SIZE];
56 char *p;
57 struct hdr_field *hdr;
58 struct sip_uri puri;
59
60 rr_t *route = 0;
61
62 path->len = 0;
63 path->s = 0;
64 received->s = 0;
65 received->len = 0;
66
67 if (parse_headers(_m, HDR_EOH_F, 0) < 0) {
68 LM_ERR("failed to parse the message\n");
69 goto error;
70 }
71
72 for (hdr = _m->path, p = buf; hdr; hdr = next_sibling_hdr(hdr)) {
73 /* check for max. Path length */
74 if (p - buf + hdr->body.len + 1 >= MAX_PATH_SIZE) {
75 LM_ERR("Overall Path body exceeds max. length of %d\n",
76 MAX_PATH_SIZE);
77 goto error;
78 }
79 if (p != buf)
80 *(p++) = ',';
81 memcpy(p, hdr->body.s, hdr->body.len);
82 p += hdr->body.len;
83 }
84
85 if (p != buf) {
86 /* check if next hop is a loose router */
87 if (parse_rr_body(buf, p - buf, &route) < 0) {
88 LM_ERR("failed to parse Path body, no head found\n");
89 goto error;
90 }
91 if (parse_uri(route->nameaddr.uri.s, route->nameaddr.uri.len, &puri) < 0) {
92 LM_ERR("failed to parse the first Path URI\n");
93 goto error;
94 }
95 if (!puri.lr.s) {
96 LM_ERR("first Path URI is not a loose-router, not supported\n");
97 goto error;
98 }
99 free_rr(&route);
100 }
101
102 path->s = buf;
103 path->len = p - buf;
104 return 0;
105 error:
106 if (route) free_rr(&route);
107 return -1;
108 }
109
110 #define PASSOCIATEDURI "P-Associated-URI: "
111 #define PASSOCIATEDURI_LEN (sizeof(PASSOCIATEDURI)-1)
112
113 static struct {
114 char* buf;
115 int buf_len;
116 int data_len;
117 } p_associated_uri = {0, 0, 0};
118
calc_associateduri_buf_len(ims_subscription * s)119 static inline unsigned int calc_associateduri_buf_len(ims_subscription* s) {
120 unsigned int len;
121 int i, j;
122 ims_public_identity* id;
123
124 len = 0;
125 for (i = 0; i < s->service_profiles_cnt; i++)
126 for (j = 0; j < s->service_profiles[i].public_identities_cnt; j++) {
127 id = &(s->service_profiles[i].public_identities[j]);
128 if (!id->barring)
129 len += 4 + id->public_identity.len;
130 }
131
132 if (len) len += PASSOCIATEDURI_LEN + 2 + CRLF_LEN;
133
134 return len;
135 }
136
build_p_associated_uri(ims_subscription * s)137 int build_p_associated_uri(ims_subscription* s) {
138 char *p;
139 int i, j, cnt = 0,cnttel = 0;;
140 ims_public_identity* id;
141
142 LM_DBG("Building P-Associated-URI\n");
143
144 if (!s) {
145 LM_ERR("No ims_subscription present\n");
146 return -1;
147 }
148 p_associated_uri.data_len = calc_associateduri_buf_len(s);
149 if (!p_associated_uri.data_len)
150 return -1;
151
152 if (!p_associated_uri.buf || (p_associated_uri.buf_len < p_associated_uri.data_len)) {
153 if (p_associated_uri.buf)
154 pkg_free(p_associated_uri.buf);
155 p_associated_uri.buf = (char*) pkg_malloc(p_associated_uri.data_len);
156 if (!p_associated_uri.buf) {
157 p_associated_uri.data_len = 0;
158 p_associated_uri.buf_len = 0;
159 LM_ERR("no pkg memory left\n");
160 return -1;
161 } else {
162 p_associated_uri.buf_len = p_associated_uri.data_len;
163 }
164 }
165
166 p = p_associated_uri.buf;
167 memcpy(p, PASSOCIATEDURI, PASSOCIATEDURI_LEN);
168 p += PASSOCIATEDURI_LEN;
169
170 for (i = 0; i < s->service_profiles_cnt; i++)
171 for (j = 0; j < s->service_profiles[i].public_identities_cnt; j++) {
172 id = &(s->service_profiles[i].public_identities[j]);
173 if (!id->barring && !(strncmp(id->public_identity.s,"tel",3) == 0) ) {
174 if (cnt == 0 && cnttel == 0){
175 *p++ = '<';
176 } else if(cnttel != 0 && cnt == 0){
177 memcpy(p, ", <", 3);
178 p += 3;
179 } else {
180 memcpy(p, ">, <", 4);
181 p += 4;
182 }
183 memcpy(p, id->public_identity.s, id->public_identity.len);
184 p += id->public_identity.len;
185 cnt++;
186 }else if(!id->barring && strncmp(id->public_identity.s,"tel",3) == 0){
187
188 if(cnttel != 0 || cnt != 0){
189 memcpy(p, ", ", 2);
190 p += 2;
191 }
192 memcpy(p, id->public_identity.s, id->public_identity.len);
193 p += id->public_identity.len;
194 cnttel++;
195 }
196 }
197 if (cnt)
198 *p++ = '>';
199
200 memcpy(p, "\r\n", CRLF_LEN);
201 p += CRLF_LEN;
202 p_associated_uri.data_len = p - p_associated_uri.buf;
203 LM_DBG("Created P-Associated-URI HF %.*s\n", p_associated_uri.data_len, p_associated_uri.buf);
204
205 return 0;
206 }
207
208 static str reg_resp_200OK = {"OK", 2};
209
210 /**
211 * Handle third party registration
212 * @param msg - the SIP REGISTER message
213 * @param m - the isc_match that matched with info about where to forward it
214 * @param mark - the isc_mark that should be used to mark the message
215 * @returns #ISC_RETURN_TRUE if allowed, #ISC_RETURN_FALSE if not
216 */
isc_third_party_reg(struct sip_msg * msg,isc_match * m,isc_mark * mark,udomain_t * d)217 int isc_third_party_reg(struct sip_msg *msg, isc_match *m, isc_mark *mark, udomain_t* d) {
218 r_third_party_registration r;
219 str path, path_received;
220 int expires = 0;
221 str req_uri = {0, 0};
222 str to = {0, 0};
223 str pvni = {0, 0};
224 str pani = {0, 0};
225 str cv = {0, 0};
226 str s = {0, 0};
227
228 impurecord_t *p;
229
230 struct hdr_field *hdr;
231
232 LM_DBG("isc_third_party_reg: Enter\n");
233
234 /* Set Request Uri to IFC matching server name */
235 req_uri.len = m->server_name.len;
236 req_uri.s = m->server_name.s;
237
238 /* Get To header*/
239 to = cscf_get_public_identity(msg);
240
241 if (cscf_get_originating_user(msg, &s)) {
242
243 isc_ulb.lock_udomain(d, &s);
244 if ( isc_ulb.get_impurecord(d,&s,&p) != 0) {
245 isc_ulb.unlock_udomain(d, &s);
246 LM_ERR("Failed to get IMPU domain from usrloc\n");
247 goto no_pai;
248 }
249 if ( build_p_associated_uri(p->s) != 0) {
250 isc_ulb.unlock_udomain(d, &s);
251 LM_ERR("Failed to build P-Associated URI for 3rd party reg\n");
252 goto no_pai;
253 }
254 isc_ulb.unlock_udomain(d, &s);
255 }
256
257 /*TODO - check if the min/max expires is in the acceptable limits
258 * this does not work correctly if the user has multiple contacts
259 * and register/deregisters them individually!!!
260 */
261 no_pai:
262 expires = cscf_get_max_expires(msg, 0);
263
264 /* Get P-Visited-Network-Id header */
265 pvni = cscf_get_visited_network_id(msg, &hdr);
266 /* Get P-Access-Network-Info header */
267 pani = cscf_get_access_network_info(msg, &hdr);
268
269 if (build_path_vector(msg, &path, &path_received) < 0) {
270 LM_ERR("Failed to parse PATH header for third-party reg\n");
271 return ISC_RETURN_FALSE;
272 }
273 LM_DBG("PATH header in REGISTER is [%.*s]\n", path.len, path.s);
274
275 /* Get P-Charging-Vector header */
276 /* Just forward the charging header received from P-CSCF */
277 /* Todo: implement also according to TS 24.229, chap 5.4.1.7 */
278 cv = cscf_get_charging_vector(msg, &hdr);
279
280 if (req_uri.s) {
281
282 memset(&r, 0, sizeof (r_third_party_registration));
283
284 r.req_uri = req_uri;
285 r.to = to;
286 r.from = isc_my_uri_sip;
287 r.pvni = pvni;
288 r.pani = pani;
289 r.cv = cv;
290 if (m->service_info.s && m->service_info.len) {
291 r.body.content_type = CT_SERVICE_INFO;
292 r.body.content = m->service_info;
293 } else if (m->include_register_request) {
294 r.body.content_type = CT_REGISTER_REQ;
295 r.body.content.s = msg->first_line.u.request.method.s;
296 r.body.content.len = msg->len;
297 } else if (m->include_register_response) {
298 struct bookmark dummy_bm;
299 r.body.content_type = CT_REGISTER_RESP;
300 r.body.content.s = build_res_buf_from_sip_req(200, ®_resp_200OK, 0, msg, (unsigned int*)&r.body.content.len, &dummy_bm);
301 if (!r.body.content.s) {
302 LM_DBG("response building failed for body of third party register request");
303 r.body.content_type = CT_NONE;
304 }
305 } else {
306 r.body.content_type = CT_NONE;
307 }
308 r.path = path;
309
310 if (expires <= 0)
311 r_send_third_party_reg(&r, 0);
312 else
313 r_send_third_party_reg(&r, expires + isc_expires_grace);
314 return ISC_RETURN_TRUE;
315 } else {
316 return ISC_RETURN_FALSE;
317 }
318 }
319
320 static str method = {"REGISTER", 8};
321 static str event_hdr = {"Event: registration\r\n", 21};
322 static str max_fwds_hdr = {"Max-Forwards: 10\r\n", 18};
323 static str expires_s = {"Expires: ", 9};
324 static str expires_e = {"\r\n", 2};
325 static str contact_s = {"Contact: <", 10};
326 static str contact_e = {">\r\n", 3};
327
328 static str p_visited_network_id_s = {"P-Visited-Network-ID: ", 22};
329 static str p_visited_network_id_e = {"\r\n", 2};
330
331 static str p_access_network_info_s = {"P-Access-Network-Info: ", 23};
332 static str p_access_network_info_e = {"\r\n", 2};
333
334 static str p_charging_vector_s = {"P-Charging-Vector: ", 19};
335 static str p_charging_vector_e = {"\r\n", 2};
336
337 static str path_s = {"Path: ", 6};
338 static str path_e = {"\r\n", 2};
339
340 static str comma = {",", 1};
341
342 static str path_mine_s = {"<", 1};
343 static str path_mine_e = {";lr>", 4};
344
345 static str content_type_s = {"Content-Type: ", 14};
346 static str content_type_e = {"\r\n", 2};
347
348 static str ct_service_info = {"application/3gpp-ims+xml", 24};
349 static str ct_register_req = {"message/sip", 11};
350 static str ct_register_resp = {"message/sip", 11};
351
352 static str body_s = {"<ims-3gpp version=\"1\"><service-info>", 36};
353 static str body_e = {"</service-info></ims-3gpp>", 26};
354
355 /**
356 * Send a third party registration
357 * @param r - the register to send for
358 * @param expires - expires time
359 * @returns true if OK, false if not
360 */
361
r_send_third_party_reg(r_third_party_registration * r,int expires)362 int r_send_third_party_reg(r_third_party_registration *r, int expires) {
363 str h = {0, 0};
364 str b = {0, 0};
365 uac_req_t req;
366
367 LM_DBG("r_send_third_party_reg: REGISTER to <%.*s>\n",
368 r->req_uri.len, r->req_uri.s);
369
370 h.len = event_hdr.len + max_fwds_hdr.len;
371 h.len += expires_s.len + 12 + expires_e.len;
372
373 h.len += contact_s.len + isc_my_uri_sip.len + contact_e.len;
374
375 if (r->pvni.len) {
376 h.len += p_visited_network_id_s.len + p_visited_network_id_e.len
377 + r->pvni.len;
378 }
379 if (r->pani.len) {
380 h.len += p_access_network_info_s.len + p_access_network_info_e.len
381 + r->pani.len;
382 }
383 if (r->cv.len) {
384 h.len += p_charging_vector_s.len + p_charging_vector_e.len + r->cv.len;
385 }
386 if (r->path.len) {
387 h.len += path_s.len + path_e.len + r->path.len + 6/*',' and ';lr' and '<' and '>'*/
388 + r->from.len /*adding our own address to path*/;
389 }
390 str pauri = {0,0};
391
392 if (p_associated_uri.data_len > 0)
393 {
394 pauri.s = p_associated_uri.buf;
395 pauri.len = p_associated_uri.data_len;
396 h.len += pauri.len;
397 }
398
399 if (r->body.content_type == CT_SERVICE_INFO) {
400 h.len += content_type_s.len;
401 h.len += ct_service_info.len;
402 h.len += content_type_e.len;
403 } else if (r->body.content_type == CT_REGISTER_REQ) {
404 h.len += content_type_s.len;
405 h.len += ct_register_req.len;
406 h.len += content_type_e.len;
407 } else if (r->body.content_type == CT_REGISTER_RESP) {
408 h.len += content_type_s.len;
409 h.len += ct_register_resp.len;
410 h.len += content_type_e.len;
411 }
412
413 h.s = pkg_malloc(h.len);
414 if (!h.s) {
415 LM_ERR("r_send_third_party_reg: Error allocating %d bytes\n", h.len);
416 h.len = 0;
417 return 0;
418 }
419
420 h.len = 0;
421 STR_APPEND(h, event_hdr);
422
423 STR_APPEND(h, max_fwds_hdr);
424
425 STR_APPEND(h, expires_s);
426 sprintf(h.s + h.len, "%d", expires);
427 h.len += strlen(h.s + h.len);
428 STR_APPEND(h, expires_e);
429
430 if (r->path.len) {
431 STR_APPEND(h, path_s);
432 STR_APPEND(h, path_mine_s);
433 STR_APPEND(h, r->from);
434 STR_APPEND(h, path_mine_e);
435 STR_APPEND(h, comma);
436 STR_APPEND(h, r->path);
437 STR_APPEND(h, path_e);
438 }
439
440 STR_APPEND(h, contact_s);
441 STR_APPEND(h, isc_my_uri_sip);
442 STR_APPEND(h, contact_e);
443
444 if (r->pvni.len) {
445 STR_APPEND(h, p_visited_network_id_s);
446 STR_APPEND(h, r->pvni);
447 STR_APPEND(h, p_visited_network_id_e);
448 }
449
450 if (r->pani.len) {
451 STR_APPEND(h, p_access_network_info_s);
452 STR_APPEND(h, r->pani);
453 STR_APPEND(h, p_access_network_info_e);
454 }
455
456 if (r->cv.len) {
457 STR_APPEND(h, p_charging_vector_s);
458 STR_APPEND(h, r->cv);
459 STR_APPEND(h, p_charging_vector_e);
460 }
461
462 if (p_associated_uri.data_len > 0) {
463 STR_APPEND(h, pauri);
464 }
465 LM_DBG("BODY TYPE(3rd PARTY REGISTER):<%d>\n", r->body.content_type);
466 if (r->body.content_type != CT_NONE) {
467 if (r->body.content_type == CT_SERVICE_INFO) {
468 LM_ERR("BODY (3rd PARTY REGISTER) \"SI\": <%.*s>\n", r->body.content.len, r->body.content.s);
469 b.len = body_s.len + r->body.content.len + body_e.len;
470 b.s = pkg_malloc(b.len);
471 if (!b.s) {
472 LM_ERR("r_send_third_party_reg: Error allocating %d bytes\n", b.len);
473 b.len = 0;
474 goto error;
475 }
476 b.len = 0;
477 STR_APPEND(b, body_s);
478 STR_APPEND(b, r->body.content);
479 STR_APPEND(b, body_e);
480 STR_APPEND(h, content_type_s);
481 STR_APPEND(h, ct_service_info);
482 STR_APPEND(h, content_type_e);
483 } else if (r->body.content_type == CT_REGISTER_REQ) {
484 LM_ERR("BODY (3rd PARTY REGISTER) \"REQ\": <%.*s>\n", r->body.content.len, r->body.content.s);
485 b.len = r->body.content.len;
486 b.s = pkg_malloc(b.len);
487 if (!b.s) {
488 LM_ERR("r_send_third_party_reg: Error allocating %d bytes\n", b.len);
489 b.len = 0;
490 goto error;
491 }
492 b.len = 0;
493 STR_APPEND(b, r->body.content);
494 STR_APPEND(h, content_type_s);
495 STR_APPEND(h, ct_register_req);
496 STR_APPEND(h, content_type_e);
497 } else if (r->body.content_type == CT_REGISTER_RESP) {
498 LM_ERR("BODY (3rd PARTY REGISTER) \"RESP\": <%.*s>\n", r->body.content.len, r->body.content.s);
499 b.len = r->body.content.len;
500 b.s = pkg_malloc(b.len);
501 if (!b.s) {
502 LM_ERR("r_send_third_party_reg: Error allocating %d bytes\n", b.len);
503 b.len = 0;
504 goto error;
505 }
506 b.len = 0;
507 STR_APPEND(b, r->body.content);
508 STR_APPEND(h, content_type_s);
509 STR_APPEND(h, ct_register_resp);
510 STR_APPEND(h, content_type_e);
511 }
512 }
513
514 set_uac_req(&req, &method, &h, &b, 0,
515 TMCB_RESPONSE_IN | TMCB_ON_FAILURE | TMCB_LOCAL_COMPLETED,
516 r_third_party_reg_response, &(r->req_uri));
517 if (isc_tmb.t_request(&req, &(r->req_uri), &(r->to), &(r->from), 0) < 0) {
518 LM_ERR("r_send_third_party_reg: Error sending in transaction\n");
519 goto error;
520 }
521 if (h.s)
522 pkg_free(h.s);
523 if (b.s)
524 pkg_free(b.s);
525 if (r->body.content_type == CT_REGISTER_RESP)
526 pkg_free(r->body.content.s);
527 return 1;
528
529 error:
530 if (h.s)
531 pkg_free(h.s);
532 if (b.s)
533 pkg_free(b.s);
534 if (r->body.content_type == CT_REGISTER_RESP)
535 pkg_free(r->body.content.s);
536 return 0;
537 }
538
539 /**
540 * Response callback for third party register
541 */
r_third_party_reg_response(struct cell * t,int type,struct tmcb_params * ps)542 void r_third_party_reg_response(struct cell *t, int type, struct tmcb_params *ps) {
543 LM_DBG("r_third_party_reg_response: code %d\n", ps->code);
544 if (!ps->rpl) {
545 LM_ERR("r_third_party_reg_response: No reply\n");
546 return;
547 }
548
549 if (ps->code >= 200 && ps->code < 300) {
550 if (ps->rpl)
551 cscf_get_expires_hdr(ps->rpl, 0);
552 else
553 return;
554 } else if (ps->code == 404) {
555 } else {
556 LM_DBG("r_third_party_reg_response: code %d\n", ps->code);
557 }
558 }
559