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, &reg_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