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  * Copyright (C) 2019 Aleksandar Yosifov
7  *
8  * The initial version of this code was written by Dragos Vingarzan
9  * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
10  * Fruanhofer Institute. It was and still is maintained in a separate
11  * branch of the original SER. We are therefore migrating it to
12  * Kamailio/SR and look forward to maintaining it from here on out.
13  * 2011/2012 Smile Communications, Pty. Ltd.
14  * ported/maintained/improved by
15  * Jason Penton (jason(dot)penton(at)smilecoms.com and
16  * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
17  * effort to add full IMS support to Kamailio/SR using a new and
18  * improved architecture
19  *
20  * NB: Alot of this code was originally part of OpenIMSCore,
21  * FhG Fokus.
22  * Copyright (C) 2004-2006 FhG Fokus
23  * Thanks for great work! This is an effort to
24  * break apart the various CSCF functions into logically separate
25  * components. We hope this will drive wider use. We also feel
26  * that in this way the architecture is more complete and thereby easier
27  * to manage in the Kamailio/SR environment
28  *
29  * This file is part of Kamailio, a free SIP server.
30  *
31  * Kamailio is free software; you can redistribute it and/or modify
32  * it under the terms of the GNU General Public License as published by
33  * the Free Software Foundation; either version 2 of the License, or
34  * (at your option) any later version
35  *
36  * Kamailio is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39  * GNU General Public License for more details.
40  *
41  * You should have received a copy of the GNU General Public License
42  * along with this program; if not, write to the Free Software
43  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
44  *
45  */
46 
47 #include "../../core/parser/contact/contact.h"
48 #include "save.h"
49 #include "ims_registrar_pcscf_mod.h"
50 #include "ul_callback.h"
51 #include "subscribe.h"
52 
53 #include "../pua/pua_bind.h"
54 #include "../ims_ipsec_pcscf/cmd.h"
55 #include "sec_agree.h"
56 
57 extern struct tm_binds tmb;
58 extern usrloc_api_t ul;
59 extern time_t time_now;
60 extern unsigned int pending_reg_expires;
61 extern int subscribe_to_reginfo;
62 extern int subscription_expires;
63 extern pua_api_t pua;
64 extern ipsec_pcscf_api_t ipsec_pcscf;
65 
get_request_from_reply(struct sip_msg * reply)66 struct sip_msg* get_request_from_reply(struct sip_msg* reply)
67 {
68 	struct cell *t;
69 	t = tmb.t_gett();
70 	if (!t || t == (void*) -1) {
71 		LM_ERR("Reply without transaction\n");
72 		return 0;
73 	}
74 	if (t)
75 		return t->uas.request;
76 	else
77 		return 0;
78 
79 }
80 
81 /**
82  * Calculates the expiration time for one contact.
83  * Tries to use the Expiration header, if not present then use the
84  * expires parameter of the contact, if param not present it defaults
85  * to the default value.
86  * Also checks
87  * @param c - the contact to calculate for
88  * @param expires_hdr - value of expires hdr if present, if not -1
89  * @param local_time_now - the local time
90  * @returns the time of expiration
91  */
calc_contact_expires(contact_t * c,int expires_hdr,int local_time_now)92 static inline int calc_contact_expires(contact_t *c,int expires_hdr, int local_time_now)
93 {
94 	unsigned int r = 0;
95 	if (expires_hdr >= 0)
96 		r = expires_hdr;
97 
98 	if (c && c->expires && c->expires->body.len) {
99 		str2int(&(c->expires->body), (unsigned int*) &r);
100 	}
101 	return local_time_now + r;
102 }
103 
104 
105 /**
106  * Updates the registrar with the new values
107  * @param req - the REGISTER request - to extract NAT info
108  * @param rpl - the REGISTER reply - to extract contact info
109  * @param is_star - whether this was a STAR contact header
110  * @param expires_hdr - value of the Expires header
111  * @param public_id - array of public identities attached to this contact
112  * @param public_id_cnt - size of the public_id array
113  * @param service_route - array of Service-Routes
114  * @param service_route_cnt - size of the service_route array
115  * @param requires_nat - if to create pinholes
116  * @returns the maximum expiration time, -1 on error
117  */
update_contacts(struct sip_msg * req,struct sip_msg * rpl,udomain_t * _d,unsigned char is_star,int expires_hdr,str * public_id,int public_id_cnt,str * service_route,int service_route_cnt,int requires_nat)118 static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udomain_t* _d, unsigned char is_star,int expires_hdr,
119         str *public_id,int public_id_cnt,str *service_route,int service_route_cnt, int requires_nat)
120 {
121 	int local_time_now, expires=0;
122 	struct hdr_field* h;
123 	contact_t* c;
124 	struct sip_uri puri;
125 	struct pcontact_info ci;
126 	pcontact_t* pcontact;
127 	unsigned short port, proto;
128 	char *alias_start, *p, *port_s, *proto_s;
129 	char portbuf[5];
130 	str alias_s;
131 
132 	pcscf_act_time();
133 	local_time_now = time_now;
134 	if (is_star) {
135 		/* first of all, we shouldn't get here...
136 		 * then, we will update on NOTIFY */
137 		return 0;
138 	}
139 
140 	// Set the structure to "0", to make sure it's properly initialized
141 	memset(&ci, 0, sizeof(struct pcontact_info));
142 
143 	for (h = rpl->contact; h; h = h->next) {
144 		if (h->type == HDR_CONTACT_T && h->parsed) {
145 			for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) {
146 				expires = calc_contact_expires(c, expires_hdr, local_time_now);
147 				if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) {
148 					LM_DBG("Error parsing Contact URI <%.*s>\n", c->uri.len, c->uri.s);
149 					continue;
150 				}
151 				//build contact info
152 				ci.aor = c->uri;
153 				ci.expires = expires;
154 				ci.public_ids = public_id;
155 				ci.num_public_ids = public_id_cnt;
156 				ci.service_routes = service_route;
157 				ci.num_service_routes = service_route_cnt;
158 				ci.reg_state = PCONTACT_REGISTERED|PCONTACT_REG_PENDING|PCONTACT_REG_PENDING_AAR;   //we don't want to add contacts that did not come through us (pcscf)
159 
160 				ci.received_host.len = 0;
161 				ci.received_host.s = 0;
162 				ci.received_port = 0;
163 				ci.received_proto = 0;
164 				port = puri.port_no ? puri.port_no : 5060;
165 				ci.via_host = puri.host;
166 				ci.via_port = port;
167 				ci.via_prot = puri.proto;
168 				ci.searchflag = SEARCH_NORMAL; /* this must be reset for each contact iteration */
169 
170 				if (puri.params.len > 6 && (alias_start = _strnistr(puri.params.s, "alias=", puri.params.len)) != NULL) {
171 					LM_DBG("contact has an alias [%.*s] - we can use that as the received\n", puri.params.len, puri.params.s);
172 					alias_s.len = puri.params.len - (alias_start - puri.params.s) - 6;
173 					alias_s.s = alias_start + 6;
174 					LM_DBG("alias [%.*s]\n", alias_s.len, alias_s.s);
175 					p = _strnistr(alias_s.s, "~", alias_s.len);
176 					if (p!=NULL) {
177 						ci.received_host.s = alias_s.s;
178 						ci.received_host.len = p - alias_s.s;
179 						LM_DBG("alias(host) [%.*s]\n", ci.received_host.len, ci.received_host.s);
180 						port_s = p+1;
181 						p = _strnistr(port_s, "~", alias_s.len - ci.received_host.len);
182 						if (p!=NULL) {
183 							LM_DBG("alias(port) [%.*s]\n", (int)(p - port_s) , port_s);
184 							memset(portbuf, 0, 5);
185 							memcpy(portbuf, port_s, (p-port_s));
186 							port = atoi(portbuf);
187 							LM_DBG("alias(port) [%d]\n", port);
188 
189 							proto_s = p + 1;
190 							memset(portbuf, 0, 5);
191 							memcpy(portbuf, proto_s, 1);
192 							proto = atoi(portbuf);
193 							LM_DBG("alias(proto) [%d]\n", proto);
194 							ci.received_port = port;
195 							ci.received_proto = proto;
196 							ci.searchflag = SEARCH_RECEIVED;
197 						}
198 					}
199 				}
200 
201 				ul.lock_udomain(_d, &puri.host, port, puri.proto);
202 				if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
203 					if ((expires-local_time_now)<=0) { //remove contact - de-register
204 						LM_DBG("This is a de-registration for contact <%.*s> but contact is not in usrloc - ignore\n", c->uri.len, c->uri.s);
205 						goto next_contact;
206 					}
207 					LM_DBG("We don't add contact from the 200OK that did not go through us (ie, not present in explicit REGISTER that went through us\n");
208 				} else { //contact already exists - update
209 					LM_DBG("contact already exists and is in state (%d) : [%s]\n",pcontact->reg_state, reg_state_to_string(pcontact->reg_state));
210 					if ((expires-local_time_now)<=0) { //remove contact - de-register
211 						LM_DBG("This is a de-registration for contact <%.*s>\n", c->uri.len, c->uri.s);
212 						if (ul.delete_pcontact(_d, pcontact) != 0) {
213 							LM_ERR("failed to delete pcscf contact <%.*s>\n", c->uri.len, c->uri.s);
214 						}
215                                                 //TODO_LATEST replace above
216 					} else { //update contact
217 						LM_DBG("Updating contact: <%.*s>, old expires: %li, new expires: %i which is in %i seconds\n", c->uri.len, c->uri.s,
218 								pcontact->expires-local_time_now,
219 								expires,
220 								expires-local_time_now);
221 						ci.reg_state = PCONTACT_REGISTERED;
222 						if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
223 							LM_DBG("failed to update pcscf contact\n");
224 						}else{
225 							// Register callback to destroy related tunnels to this contact.
226 							// The registration should be exact here, after the successfuly registration of the UE
227 							LM_DBG("ul.register_ulcb(pcontact, PCSCF_CONTACT_EXPIRE|PCSCF_CONTACT_DELETE...)\n");
228 							if(ul.register_ulcb(pcontact, PCSCF_CONTACT_EXPIRE|PCSCF_CONTACT_DELETE, ipsec_pcscf.ipsec_on_expire, NULL) != 1){
229 								LM_DBG("Error subscribing for contact\n");
230 							}
231 
232 							// After successful registration try to unregister all callbacks for pending contacts ralated to this contact.
233 							ul.unreg_pending_contacts_cb(_d, pcontact, PCSCF_CONTACT_EXPIRE);
234 						}
235 						pcontact->expires = expires;
236 					}
237 				}
238 next_contact:
239 				ul.unlock_udomain(_d, &puri.host, port, puri.proto);
240 			}
241 		}
242 	}
243 	return 1;
244 }
245 
246 /**
247  * Save contact based on REGISTER request. this will be a pending save, until we receive response
248  * from SCSCF. If no response after pending_timeout seconds, the contacts is removed. Can only be used from REQUEST ROUTE
249  */
save_pending(struct sip_msg * _m,udomain_t * _d)250 int save_pending(struct sip_msg* _m, udomain_t* _d) {
251 	contact_body_t* cb = 0;
252 	int cexpires = 0;
253 	pcontact_t* pcontact;
254 	contact_t* c;
255 	struct pcontact_info ci;
256 	struct via_body* vb;
257 	unsigned short port, proto;
258 	int_str val;
259 	struct sip_uri parsed_received;
260 	char srcip[50];
261 
262 	memset(&ci, 0, sizeof(struct pcontact_info));
263 
264 	vb = cscf_get_ue_via(_m);
265 	port = vb->port?vb->port:5060;
266 	proto = vb->proto;
267 
268 	cb = cscf_parse_contacts(_m);
269 	if (!cb || (!cb->contacts)) {
270 		LM_ERR("No contact headers\n");
271 		goto error;
272 	}
273 
274 	c = cb->contacts;
275 	//TODO: need support for multiple contacts - currently assume one contact
276 	//make sure this is not a de-registration
277 	int expires_hdr = cscf_get_expires_hdr(_m, 0);
278 	if (expires_hdr < 0) {
279 		//no global header we have to check the contact expiry
280 		if (c && c->expires && c->expires->body.len) {
281 				str2int(&(c->expires->body), (unsigned int*) &cexpires);
282 		}
283 		if (!cexpires){ //assume de-registration
284 			LM_DBG("not doing pending reg on de-registration\n");
285 			return 1;
286 		}
287 	}
288 
289 	pcscf_act_time();
290 	int local_time_now = time_now;
291 	int expires = calc_contact_expires(c, expires_hdr, local_time_now);
292 	if (expires <= 0) {
293 		LM_DBG("not doing pending reg on de-registration\n");
294 		return 1;
295 	}
296 
297 	LM_DBG("Save pending contact with AOR [%.*s], proto %d, port %d\n", c->uri.len, c->uri.s, proto, port);
298 	LM_DBG("contact requesting to expire in %d seconds\n", expires-local_time_now);
299 
300 	/*populate CI with bare minimum*/
301 	ci.via_host = vb->host;
302 	ci.via_port = port;
303 	ci.via_prot = proto;
304 	ci.aor = c->uri;
305 	ci.num_public_ids=0;
306 	ci.num_service_routes=0;
307 	ci.expires=local_time_now + pending_reg_expires;
308 	ci.reg_state=PCONTACT_ANY;
309 	ci.searchflag=SEARCH_RECEIVED;  //we want to make sure we are very specific with this search to make sure we get the correct contact to put into reg_pending.
310 
311 	// Received Info: First try AVP, otherwise simply take the source of the request:
312 	memset(&val, 0, sizeof(int_str));
313 	if (rcv_avp_name.n != 0
314 			&& search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0)
315 			&& val.s.len > 0) {
316 		if (val.s.len > RECEIVED_MAX_SIZE) {
317 			LM_ERR("received too long\n");
318 			goto error;
319 		}
320 		if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) {
321 			LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s);
322 			goto error;
323 		}
324 		ci.received_host = parsed_received.host;
325 		ci.received_port = parsed_received.port_no;
326 		ci.received_proto = parsed_received.proto;
327 	} else {
328 		ci.received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip,
329 				sizeof(srcip));
330 		ci.received_host.s = srcip;
331 		ci.received_port = _m->rcv.src_port;
332 		ci.received_proto = _m->rcv.proto;
333 
334 	}
335 	// Set to default, if not set:
336 	if (ci.received_port == 0)
337 		ci.received_port = 5060;
338 
339 	// Parse security parameters
340 	security_t* sec_params = NULL;
341 	if((sec_params = cscf_get_security(_m)) == NULL) {
342 		LM_DBG("Will save pending contact without security parameters\n");
343 	}
344 
345 	// Parse security-verify parameters
346 	security_t* sec_verify_params = NULL;
347 	if((sec_verify_params = cscf_get_security_verify(_m)) == NULL){
348 		LM_DBG("Will save pending contact without security-verify parameters\n");
349 	}else{
350 		if(sec_params){
351 			// for REGISTER request try to set spi pc and spi ps from security-verify header
352 			sec_params->data.ipsec->spi_ps = sec_verify_params->data.ipsec->spi_us;
353 			sec_params->data.ipsec->spi_pc = sec_verify_params->data.ipsec->spi_uc;
354 
355 			// Get from verify header pcscf server and client ports
356 			sec_params->data.ipsec->port_ps = sec_verify_params->data.ipsec->port_us;
357 			sec_params->data.ipsec->port_pc = sec_verify_params->data.ipsec->port_uc;
358 
359 			LM_DBG("Will save pending contact with security-verify parameters, spc_ps %u, spi_pc %u, port_ps %u, port_pc %u\n",
360 					sec_params->data.ipsec->spi_ps, sec_params->data.ipsec->spi_pc, sec_params->data.ipsec->port_ps, sec_params->data.ipsec->port_pc);
361 		}
362 	}
363 
364 	ul.lock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);
365 	if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
366 		ipsec_pcscf.ipsec_reconfig(); // try to clean all ipsec SAs/Policies if there is no registered contacts
367 
368 		LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s);
369 		ci.reg_state=PCONTACT_REG_PENDING;
370 		if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {
371 			LM_ERR("Failed inserting new pcontact\n");
372 		} else {
373 			LM_DBG("registering for UL callback\n");
374 			ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE | PCSCF_CONTACT_UPDATE, callback_pcscf_contact_cb, NULL);
375 
376 			// Update security parameters only for the pending contacts
377 			if(sec_params){
378 				if(ul.update_temp_security(_d, sec_params->type, sec_params, pcontact) != 0){
379 					LM_ERR("Error updating temp security\n");
380 				}
381 			}
382 		}
383 	} else { //contact already exists - update
384         LM_DBG("Contact already exists - not doing anything for now\n");
385 	}
386 
387 	ul.unlock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);
388 
389 
390 	return 1;
391 
392 error:
393 	LM_DBG("Error saving pending contact\n");
394 	return -1;
395 }
396 
397 /**
398  * Save the contacts and their associated public ids.
399  * @param rpl - the SIP Register 200 OK response that contains the Expire and Contact and P-associated-uri headers
400  * @param _d - domain
401  * @param _cflags - flags
402  * @returns #CSCF_RETURN_TRUE if OK, #CSCF_RETURN_ERROR on error
403  */
save(struct sip_msg * _m,udomain_t * _d,int _cflags)404 int save(struct sip_msg* _m, udomain_t* _d, int _cflags) {
405 	struct sip_msg* req;
406 	int expires_hdr = 0;
407 	contact_body_t* cb = 0;
408 	str *public_ids=0;
409 	int num_public_ids = 0;
410 	str *service_routes=0;
411 	int num_service_routes = 0;
412 	pv_elem_t *presentity_uri_pv;
413 	int contact_has_sos=-1;
414 	contact_t* chi; //contact header information
415 	struct hdr_field* h;
416 	//get request from reply
417 	req = get_request_from_reply(_m);
418 	if (!req) {
419 		LM_ERR("Unable to get request from reply for REGISTER. No transaction\n");
420 		goto error;
421 	}
422 	expires_hdr = cscf_get_expires_hdr(_m, 0);
423 
424 	if((parse_headers(_m, HDR_CONTACT_F, 0) == -1) || !_m->contact) {
425 		LM_ERR("cannot get the Contact header from the SIP message in saving action in PCSCF\n");
426 		goto error;
427 	}
428 
429 	if(!_m->contact->parsed && parse_contact(_m->contact) < 0) {
430 		LM_ERR("Couldn t parse Contact Header \n");
431 		goto error;
432 	}
433 
434 	cb = ((contact_body_t *)_m->contact->parsed);
435 	if (!cb || (!cb->contacts && !cb->star)) {
436 		LM_DBG("No contact headers and not *\n");
437 		goto error;
438 	}
439 
440 	for (h = _m->contact; h; h = h->next) {
441 	 if (h->type == HDR_CONTACT_T && h->parsed) {
442 	    for (chi = ((contact_body_t*) h->parsed)->contacts; chi; chi = chi->next) {
443 	      contact_has_sos = cscf_get_sos_uri_param(chi->uri);
444 	      if(contact_has_sos!=-1){
445 	        break;
446 	      }
447 	    }
448 	  }
449 	}
450 
451 	cscf_get_p_associated_uri(_m, &public_ids, &num_public_ids, 1);
452 	service_routes = cscf_get_service_route(_m, &num_service_routes, 1);
453 
454 	//update contacts
455 	if (!update_contacts(req, _m, _d, cb->star, expires_hdr, public_ids, num_public_ids, service_routes, num_service_routes, 0)) {
456 		LM_ERR("failed to update pcontact\n");
457 		goto error;
458 	}
459 
460 	if(subscribe_to_reginfo == 1 && contact_has_sos < 1){
461 
462 	    //use the first p_associated_uri - i.e. the default IMPU
463 	    LM_DBG("Subscribe to reg event for primary p_associated_uri");
464 	    if(num_public_ids > 0){
465 		//find the first routable (not a tel: URI and use that that presentity)
466 		//if you can not find one then exit
467 		int i = 0;
468 		int found_presentity_uri=0;
469 		while (i < num_public_ids && found_presentity_uri == 0)
470 		{
471 		    //check if public_id[i] is NOT a tel URI - if it isn't then concert to pv format and set found presentity_uri to 1
472 		    if (strncasecmp(public_ids[i].s,"tel:",4)==0) {
473 			LM_DBG("This is a tel URI - it is not routable so we don't use it to subscribe");
474 			i++;
475 		    }
476 		    else {
477 			//convert primary p_associated_uri to pv_elem_t
478 			if(pv_parse_format(&public_ids[i], &presentity_uri_pv)<0) {
479 				LM_ERR("wrong format[%.*s]\n",public_ids[i].len, public_ids[i].s);
480 				goto error;
481 			}
482 			found_presentity_uri=1;
483 		    }
484 		}
485 		if(found_presentity_uri!=1){
486 		    LM_ERR("Could not find routable URI in p_assoiated_uri list - failed to subscribe");
487 		    goto error;
488 		}
489 	    }else{
490         //Now some how check if there is a pua record and what the presentity uri is from there - if nothing there
491 		LM_DBG("No p_associated_uri in 200 OK this must be a de-register - we ignore this - will unsubscribe when the notify is received");
492 		goto done;
493 
494 	    }
495 	    reginfo_subscribe_real(_m, presentity_uri_pv, service_routes, subscription_expires);
496 	    pv_elem_free_all(presentity_uri_pv);
497 	}
498 
499 done:
500 	if (public_ids && public_ids->s) pkg_free(public_ids);
501 	if (service_routes && service_routes->s) pkg_free(service_routes);
502 	return 1;
503 
504 error:
505 	if (public_ids && public_ids->s) pkg_free(public_ids);
506 	if (service_routes && service_routes->s) pkg_free(service_routes);
507 	return -1;
508 
509 }
510