1 /*
2  * lost module utility functions
3  *
4  * Copyright (C) 2020 Wolfgang Kampichler
5  * DEC112, FREQUENTIS AG
6  *
7  * This file is part of Kamailio, a free SIP server.
8  *
9  * Kamailio is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * Kamailio is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 
25 /*!
26  * \file
27  * \brief Kamailio lost :: utilities
28  * \ingroup lost
29  * Module: \ref lost
30  */
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <time.h>
37 
38 #include "../../core/parser/msg_parser.h"
39 #include "../../core/parser/parse_content.h"
40 #include "../../core/parser/parse_uri.h"
41 #include "../../core/parser/parse_from.h"
42 #include "../../core/parser/parse_ppi_pai.h"
43 #include "../../core/dprint.h"
44 #include "../../core/mem/mem.h"
45 #include "../../core/mem/shm_mem.h"
46 #include "../../core/rand/kam_rand.h"
47 
48 #include "pidf.h"
49 #include "utilities.h"
50 
51 /*
52  * lost_trim_content(dest, lgth)
53  * removes whitespace that my occur in a content of an xml element
54  */
lost_trim_content(char * str,int * lgth)55 char *lost_trim_content(char *str, int *lgth)
56 {
57 	char *end;
58 
59 	while(isspace(*str))
60 		str++;
61 
62 	if(*str == 0)
63 		return NULL;
64 
65 	end = str + strlen(str) - 1;
66 
67 	while(end > str && isspace(*end))
68 		end--;
69 
70 	*(end + 1) = '\0';
71 
72 	*lgth = (end + 1) - str;
73 
74 	return str;
75 }
76 
77 /*
78  * lost_rand_str(dest, length)
79  * creates a random string used as temporary id in a findService request
80  */
lost_rand_str(char * dest,size_t lgth)81 void lost_rand_str(char *dest, size_t lgth)
82 {
83 	size_t index;
84 	char charset[] = "0123456789"
85 					 "abcdefghijklmnopqrstuvwxyz"
86 					 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
87 	while(lgth-- > 0) {
88 		index = (double)kam_rand() / RAND_MAX * (sizeof charset - 1);
89 		*dest++ = charset[index];
90 	}
91 	*dest = '\0';
92 }
93 
94 /*
95  * lost_new_loc(urn)
96  * creates a new location object in private memory and returns a pointer
97  */
lost_new_loc(str rurn)98 p_loc_t lost_new_loc(str rurn)
99 {
100 	s_loc_t *ptr = NULL;
101 
102 	char *id = NULL;
103 	char *urn = NULL;
104 
105 	ptr = (s_loc_t *)pkg_malloc(sizeof(s_loc_t));
106 	if(ptr == NULL) {
107 		goto err;
108 	}
109 
110 	id = (char *)pkg_malloc(RANDSTRSIZE * sizeof(char) + 1);
111 	if(id == NULL) {
112 		pkg_free(ptr);
113 		goto err;
114 	}
115 
116 	urn = (char *)pkg_malloc(rurn.len + 1);
117 	if(urn == NULL) {
118 		pkg_free(id);
119 		pkg_free(ptr);
120 		goto err;
121 	}
122 
123 	memset(urn, 0, rurn.len + 1);
124 	memcpy(urn, rurn.s, rurn.len);
125 	urn[rurn.len] = '\0';
126 
127 	lost_rand_str(id, RANDSTRSIZE);
128 
129 	ptr->identity = id;
130 	ptr->urn = urn;
131 	ptr->longitude = NULL;
132 	ptr->latitude = NULL;
133 	ptr->geodetic = NULL;
134 	ptr->xpath = NULL;
135 	ptr->profile = NULL;
136 	ptr->radius = 0;
137 	ptr->recursive = LOST_RECURSION_TRUE; /* set recursion to true */
138 	ptr->boundary = 0;					  /* set boundary to reference */
139 
140 	return ptr;
141 
142 err:
143 	LM_ERR("no more private memory\n");
144 	return NULL;
145 }
146 
147 /*
148  * lost_new_held(uri, type, time, exact)
149  * creates a new held object in private memory and returns a pointer
150  */
lost_new_held(str s_uri,str s_type,int time,int exact)151 p_held_t lost_new_held(str s_uri, str s_type, int time, int exact)
152 {
153 	s_held_t *ptr = NULL;
154 
155 	char *uri = NULL;
156 	char *type = NULL;
157 
158 	ptr = (s_held_t *)pkg_malloc(sizeof(s_held_t));
159 	if(ptr == NULL) {
160 		goto err;
161 	}
162 
163 	uri = (char *)pkg_malloc(s_uri.len + 1);
164 	if(uri == NULL) {
165 		pkg_free(ptr);
166 		goto err;
167 	}
168 
169 	type = (char *)pkg_malloc(s_type.len + 1);
170 	if(type == NULL) {
171 		pkg_free(uri);
172 		pkg_free(ptr);
173 		goto err;
174 	}
175 
176 	memset(uri, 0, s_uri.len + 1);
177 	memcpy(uri, s_uri.s, s_uri.len);
178 	uri[s_uri.len] = '\0';
179 
180 	memset(type, 0, s_type.len + 1);
181 	memcpy(type, s_type.s, s_type.len);
182 	type[s_type.len] = '\0';
183 
184 	ptr->identity = uri;
185 	ptr->type = type;
186 	ptr->time = time;
187 	ptr->exact = exact;
188 
189 	return ptr;
190 
191 err:
192 	LM_ERR("no more private memory\n");
193 	return NULL;
194 }
195 
196 /*
197  * lost_free_loc(ptr)
198  * frees a location object
199  */
lost_free_loc(p_loc_t ptr)200 void lost_free_loc(p_loc_t ptr)
201 {
202 	pkg_free(ptr->identity);
203 	pkg_free(ptr->urn);
204 	if(ptr->xpath)
205 		pkg_free(ptr->xpath);
206 	if(ptr->geodetic)
207 		pkg_free(ptr->geodetic);
208 	if(ptr->longitude)
209 		pkg_free(ptr->longitude);
210 	if(ptr->latitude)
211 		pkg_free(ptr->latitude);
212 	if(ptr->profile)
213 		pkg_free(ptr->profile);
214 
215 	pkg_free(ptr);
216 	ptr = NULL;
217 }
218 
219 /*
220  * lost_free_loc(ptr)
221  * frees a held location request object
222  */
lost_free_held(p_held_t ptr)223 void lost_free_held(p_held_t ptr)
224 {
225 	pkg_free(ptr->identity);
226 	pkg_free(ptr->type);
227 
228 	pkg_free(ptr);
229 	ptr = NULL;
230 }
231 
232 /*
233  * lost_free_string(ptr)
234  * frees and resets a string
235  */
lost_free_string(str * string)236 void lost_free_string(str *string)
237 {
238 	str ptr = *string;
239 
240 	if(ptr.s) {
241 		pkg_free(ptr.s);
242 		ptr.s = NULL;
243 		ptr.len = 0;
244 	}
245 }
246 
247 /*
248  * lost_get_content(node, name, lgth)
249  * gets a nodes "name" content and returns string allocated in private memory
250  */
lost_get_content(xmlNodePtr node,const char * name,int * lgth)251 char *lost_get_content(xmlNodePtr node, const char *name, int *lgth)
252 {
253 	xmlNodePtr cur = node;
254 	char *content = NULL;
255 	char *cnt = NULL;
256 	int len;
257 
258 	*lgth = 0;
259 
260 	content = xmlNodeGetNodeContentByName(cur, name, NULL);
261 	if(content == NULL) {
262 		LM_ERR("could not get XML node content\n");
263 		return cnt;
264 	} else {
265 		len = strlen(content);
266 		cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
267 		if(cnt == NULL) {
268 			LM_ERR("no more private memory\n");
269 			xmlFree(content);
270 			return cnt;
271 		}
272 		memset(cnt, 0, len + 1);
273 		memcpy(cnt, content, len);
274 		cnt[len] = '\0';
275 	}
276 
277 	xmlFree(content);
278 	*lgth = strlen(cnt);
279 
280 	return cnt;
281 }
282 
283 /*
284  * lost_get_property(node, name, lgth)
285  * gets a nodes property "name" and returns string allocated in private memory
286  */
lost_get_property(xmlNodePtr node,const char * name,int * lgth)287 char *lost_get_property(xmlNodePtr node, const char *name, int *lgth)
288 {
289 	xmlNodePtr cur = node;
290 	char *content;
291 	char *cnt = NULL;
292 	int len;
293 
294 	*lgth = 0;
295 
296 	content = xmlNodeGetAttrContentByName(cur, name);
297 	if(content == NULL) {
298 		LM_ERR("could not get XML node content\n");
299 		return cnt;
300 	} else {
301 		len = strlen(content);
302 		cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
303 		if(cnt == NULL) {
304 			LM_ERR("no more private memory\n");
305 			xmlFree(content);
306 			return cnt;
307 		}
308 		memset(cnt, 0, len + 1);
309 		memcpy(cnt, content, len);
310 		cnt[len] = '\0';
311 	}
312 
313 	xmlFree(content);
314 	*lgth = strlen(cnt);
315 
316 	return cnt;
317 }
318 
319 /*
320  * lost_get_childname(name, lgth)
321  * gets a nodes child name and returns string allocated in private memory
322  */
lost_get_childname(xmlNodePtr node,const char * name,int * lgth)323 char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth)
324 {
325 	xmlNodePtr cur = node;
326 	xmlNodePtr parent = NULL;
327 	xmlNodePtr child = NULL;
328 	char *cnt = NULL;
329 	int len;
330 
331 	*lgth = 0;
332 
333 	parent = xmlNodeGetNodeByName(cur, name, NULL);
334 	if(parent == NULL) {
335 		LM_ERR("xmlNodeGetNodeByName() failed\n");
336 		return cnt;
337 	}
338 
339 	child = parent->children;
340 	if(child == NULL) {
341 		LM_ERR("%s has no children '%s'\n", parent->name, name);
342 		return cnt;
343 	}
344 
345 	len = strlen((char *)child->name);
346 	cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
347 	if(cnt == NULL) {
348 		LM_ERR("no more private memory\n");
349 		return cnt;
350 	}
351 
352 	memset(cnt, 0, len + 1);
353 	memcpy(cnt, child->name, len);
354 	cnt[len] = '\0';
355 
356 	*lgth = strlen(cnt);
357 
358 	return cnt;
359 }
360 
361 /*
362  * lost_get_geolocation_header(msg, lgth)
363  * gets the Geolocation header value and returns string allocated in
364  * private memory
365  */
lost_get_geolocation_header(struct sip_msg * msg,int * lgth)366 char *lost_get_geolocation_header(struct sip_msg *msg, int *lgth)
367 {
368 	struct hdr_field *hf;
369 	char *res = NULL;
370 
371 	*lgth = 0;
372 
373 	if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
374 		LM_ERR("failed to parse geolocation header\n");
375 		return res;
376 	}
377 
378 	for(hf = msg->headers; hf; hf = hf->next) {
379 		if((hf->type == HDR_OTHER_T)
380 				&& (hf->name.len == LOST_GEOLOC_HEADER_SIZE - 2)) {
381 			/* possible hit */
382 			if(strncasecmp(hf->name.s, LOST_GEOLOC_HEADER,
383 					   LOST_GEOLOC_HEADER_SIZE)	== 0) {
384 
385 				res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char));
386 				if(res == NULL) {
387 					LM_ERR("no more private memory\n");
388 					return res;
389 				} else {
390 					memset(res, 0, hf->body.len + 1);
391 					memcpy(res, hf->body.s, hf->body.len + 1);
392 					res[hf->body.len] = '\0';
393 
394 					*lgth = strlen(res);
395 				}
396 			} else {
397 				LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
398 						hf->body.len);
399 			}
400 			break;
401 		}
402 	}
403 
404 	return res;
405 }
406 
407 /*
408  * lost_get_pai_header(msg, lgth)
409  * gets the P-A-I header value and returns string allocated in
410  * private memory
411  */
lost_get_pai_header(struct sip_msg * msg,int * lgth)412 char *lost_get_pai_header(struct sip_msg *msg, int *lgth)
413 {
414 	struct hdr_field *hf;
415 	to_body_t *pai_body;
416 	char *res = NULL;
417 
418 	*lgth = 0;
419 
420 	if(parse_headers(msg, HDR_PAI_F, 0) == -1) {
421 		LM_ERR("could not parse P-A-I header\n");
422 		return res;
423 	}
424 
425 	for(hf = msg->headers; hf; hf = hf->next) {
426 		if((hf->type == HDR_PAI_T)
427 				&& (hf->name.len == LOST_PAI_HEADER_SIZE - 2)) {
428 			/* possible hit */
429 			if(strncasecmp(hf->name.s, LOST_PAI_HEADER,
430 						LOST_PAI_HEADER_SIZE) == 0) {
431 
432 				LM_DBG("P-A-I body:  [%.*s]\n", hf->body.len, hf->body.s);
433 
434 				/* first, get some memory */
435 				pai_body = pkg_malloc(sizeof(to_body_t));
436 				if(pai_body == NULL) {
437 					LM_ERR("no more private memory\n");
438 					return res;
439 				}
440 				/* parse P-A-I body */
441 				memset(pai_body, 0, sizeof(to_body_t));
442 				parse_to(hf->body.s, hf->body.s + hf->body.len + 1, pai_body);
443 				if(pai_body->error == PARSE_ERROR) {
444 					LM_ERR("bad P-A-I header\n");
445 					pkg_free(pai_body);
446 					return res;
447 				}
448 				if(pai_body->error == PARSE_OK) {
449 					res = (char *)pkg_malloc(
450 							(pai_body->uri.len + 1) * sizeof(char));
451 					if(res == NULL) {
452 						LM_ERR("no more private memory\n");
453 						pkg_free(pai_body);
454 						return res;
455 					} else {
456 						memset(res, 0, pai_body->uri.len + 1);
457 						memcpy(res, pai_body->uri.s, pai_body->uri.len + 1);
458 						res[pai_body->uri.len] = '\0';
459 						pkg_free(pai_body);
460 
461 						*lgth = strlen(res);
462 					}
463 				}
464 			} else {
465 				LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
466 						hf->body.len);
467 			}
468 			break;
469 		}
470 	}
471 
472 	return res;
473 }
474 
475 /*
476  * lost_get_from_header(msg, lgth)
477  * gets the From header value and returns string allocated in
478  * private memory
479  */
lost_get_from_header(struct sip_msg * msg,int * lgth)480 char *lost_get_from_header(struct sip_msg *msg, int *lgth)
481 {
482 	to_body_t *f_body;
483 	char *res = NULL;
484 
485 	*lgth = 0;
486 
487 	if(parse_headers(msg, HDR_FROM_F, 0) == -1) {
488 		LM_ERR("failed to parse From header\n");
489 		return res;
490 	}
491 
492 	if(msg->from == NULL || get_from(msg) == NULL) {
493 		LM_ERR("From header not found\n");
494 		return res;
495 	}
496 	f_body = get_from(msg);
497 
498 	LM_DBG("From body:  [%.*s]\n", f_body->body.len, f_body->body.s);
499 
500 	res = (char *)pkg_malloc((f_body->uri.len + 1) * sizeof(char));
501 	if(res == NULL) {
502 		LM_ERR("no more private memory\n");
503 		return res;
504 	} else {
505 		memset(res, 0, f_body->uri.len + 1);
506 		memcpy(res, f_body->uri.s, f_body->uri.len + 1);
507 		res[f_body->uri.len] = '\0';
508 
509 		*lgth = strlen(res);
510 	}
511 
512 	return res;
513 }
514 
515 /*
516  * lost_parse_geo(node, loc)
517  * parses locationResponse (pos|circle) and writes
518  * results to location object
519  */
lost_parse_geo(xmlNodePtr node,p_loc_t loc)520 int lost_parse_geo(xmlNodePtr node, p_loc_t loc)
521 {
522 	xmlNodePtr cur = NULL;
523 
524 	char bufLat[BUFSIZE];
525 	char bufLon[BUFSIZE];
526 	char *content = NULL;
527 
528 	char s_profile[] = LOST_PRO_GEO2D;
529 
530 	int iRadius = 0;
531 	int len = 0;
532 
533 	cur = node;
534 	/* find <pos> element */
535 	content = xmlNodeGetNodeContentByName(cur, "pos", NULL);
536 
537 	if(content == NULL) {
538 		LM_WARN("could not find pos element\n");
539 		return -1;
540 	}
541 
542 	sscanf(content, "%s %s", bufLat, bufLon);
543 	xmlFree(content);
544 
545 	len = strlen((char *)bufLat);
546 	loc->latitude = (char *)pkg_malloc(len + 1);
547 	if(loc->latitude == NULL)
548 		goto err;
549 
550 	snprintf(loc->latitude, len, "%s", (char *)bufLat);
551 
552 	len = strlen((char *)bufLon);
553 	loc->longitude = (char *)pkg_malloc(len + 1);
554 	if(loc->longitude == NULL) {
555 		pkg_free(loc->latitude);
556 		goto err;
557 	}
558 
559 	snprintf(loc->longitude, len, "%s", (char *)bufLon);
560 
561 	len = strlen((char *)bufLat) + strlen((char *)bufLon) + 1;
562 	loc->geodetic = (char *)pkg_malloc(len + 1);
563 	if(loc->longitude == NULL) {
564 		pkg_free(loc->latitude);
565 		pkg_free(loc->longitude);
566 		goto err;
567 	}
568 
569 	snprintf(loc->geodetic, len, "%s %s", (char *)bufLat, (char *)bufLon);
570 
571 	/* find <radius> element */
572 	content = xmlNodeGetNodeContentByName(cur, "radius", NULL);
573 	if(content != NULL) {
574 		sscanf(content, "%d", &iRadius);
575 		xmlFree(content);
576 	}
577 
578 	/* write results */
579 	loc->radius = iRadius;
580 	loc->profile = (char *)pkg_malloc(strlen(s_profile) + 1);
581 	strcpy(loc->profile, s_profile);
582 
583 	return 0;
584 
585 err:
586 	LM_ERR("no more private memory\n");
587 	return -1;
588 }
589 /*
590  * lost_xpath_location(doc, path, loc)
591  * performs xpath expression on locationResponse and writes
592  * results (location-info child element) to location object
593  */
lost_xpath_location(xmlDocPtr doc,char * path,p_loc_t loc)594 int lost_xpath_location(xmlDocPtr doc, char *path, p_loc_t loc)
595 {
596 	xmlXPathObjectPtr result = NULL;
597 	xmlNodeSetPtr nodes = NULL;
598 	xmlNodePtr root = NULL;
599 	xmlNodePtr cur = NULL;
600 	xmlDocPtr new = NULL;
601 	xmlChar *xpath = NULL;
602 	xmlChar *xmlbuff = NULL;
603 	xmlChar *cname = NULL;
604 
605 	const unsigned char s_point[] = LOST_PNT;
606 	const unsigned char s_circle[] = LOST_CIR;
607 	const unsigned char s_civic[] = LOST_CIV;
608 
609 	char *ptr = NULL;
610 	char *tmp = NULL;
611 	char *s_profile = NULL;
612 
613 	int buffersize = 0;
614 	int remove = 0;
615 	int size = 0;
616 	int len = 0;
617 	int i = 0;
618 	int nok = -1;
619 
620 	xpath = (xmlChar *)path;
621 	/* get location via xpath expression */
622 	result = xmlGetNodeSet(doc, xpath, BAD_CAST XPATH_NS);
623 
624 	if(result == NULL) {
625 		LM_DBG("xmlGetNodeSet() returned no result\n");
626 		return -1;
627 	}
628 
629 	nodes = result->nodesetval;
630 	if(nodes != NULL) {
631 		size = nodes->nodeNr;
632 		for(i = 0; i < size; ++i) {
633 			if(nodes->nodeTab[i] == NULL) {
634 				LM_WARN("xpath '%s' failed\n", xpath);
635 				xmlXPathFreeObject(result);
636 				return -1;
637 			}
638 			if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
639 				cur = nodes->nodeTab[i];
640 				/* check if child element is point, circle or civic */
641 				while(nok < LOST_XPATH_DPTH) {
642 					if(cur->children == NULL) {
643 						/* no additional DOM level */
644 						break;
645 					} else {
646 						/* check current DOM level */
647 						nok++;
648 						cname = BAD_CAST cur->name;
649 						if(xmlStrcasecmp(cname, s_point) == 0) {
650 							s_profile = LOST_PRO_GEO2D;
651 							break;
652 						}
653 						if(xmlStrcasecmp(cname, s_circle) == 0) {
654 							s_profile = LOST_PRO_GEO2D;
655 							break;
656 						}
657 						if(xmlStrcasecmp(cname, s_civic) == 0) {
658 							s_profile = LOST_PRO_CIVIC;
659 							break;
660 						}
661 						/* nothing found ... try next DOM level */
662 						cur = cur->children;
663 					}
664 				}
665 
666 				if(nok == 0) {
667 					LM_DBG("xpath '%s' returned valid element (level %d/%d)\n",
668 							xpath, nok, LOST_XPATH_DPTH);
669 				} else if(nok < LOST_XPATH_DPTH) {
670 					/* malformed pidf-lo but still ok */
671 					LM_WARN("xpath '%s' returned malformed pidf-lo (level "
672 							"%d/%d)\n",
673 							xpath, nok, LOST_XPATH_DPTH);
674 				} else {
675 					/* really bad pidf-lo */
676 					LM_WARN("xpath '%s' failed (level %d/%d)\n", xpath, nok,
677 							LOST_XPATH_DPTH);
678 					xmlXPathFreeObject(result);
679 					return -1;
680 				}
681 
682 				if(cur == NULL) {
683 					LM_ERR("xpath xmlCopyNode() failed\n");
684 					xmlXPathFreeObject(result);
685 					return -1;
686 				}
687 
688 				root = xmlCopyNode(cur, 1);
689 				if(root == NULL) {
690 					LM_ERR("xpath xmlCopyNode() failed\n");
691 					xmlXPathFreeObject(result);
692 					return -1;
693 				}
694 
695 				new = xmlNewDoc(BAD_CAST "1.0");
696 				if(new == NULL) {
697 					LM_ERR("xpath xmlNewDoc() failed\n");
698 					xmlXPathFreeObject(result);
699 					return -1;
700 				}
701 				xmlDocSetRootElement(new, root);
702 				xmlDocDumpFormatMemory(new, &xmlbuff, &buffersize, 0);
703 				if(xmlbuff == NULL) {
704 					LM_ERR("xpath xmlDocDumpFormatMemory() failed\n");
705 					xmlFreeDoc(new);
706 					xmlXPathFreeObject(result);
707 					return -1;
708 				}
709 				/* take the first location-info element only */
710 				if(i == 0) {
711 					/* return the current profile */
712 					loc->profile = (char *)pkg_malloc(strlen(s_profile) + 1);
713 					if(loc->profile == NULL) {
714 						xmlFree(xmlbuff);
715 						xmlFreeDoc(new);
716 						xmlXPathFreeObject(result);
717 						goto err;
718 					}
719 					memset(loc->profile, 0, strlen(s_profile) + 1);
720 					memcpy(loc->profile, s_profile, strlen(s_profile));
721 
722 					/* remove xml header from location element */
723 					remove = strlen("<?xml version='1.0'?>\n");
724 					buffersize = buffersize - remove;
725 					ptr = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
726 					if(ptr == NULL) {
727 						xmlFree(xmlbuff);
728 						xmlFreeDoc(new);
729 						xmlXPathFreeObject(result);
730 						goto err;
731 					}
732 
733 					memset(ptr, 0, buffersize);
734 					memcpy(ptr, (char *)(xmlbuff + remove), buffersize);
735 					ptr[buffersize] = '\0';
736 
737 					/* trim the result */
738 					tmp = lost_trim_content(ptr, &len);
739 
740 					/* return the location DOM */
741 					loc->xpath = (char *)pkg_malloc(len + 1);
742 					if(loc->xpath == NULL) {
743 						pkg_free(ptr);
744 						ptr = NULL;
745 						xmlFree(xmlbuff);
746 						xmlFreeDoc(new);
747 						xmlXPathFreeObject(result);
748 						goto err;
749 					}
750 					memset(loc->xpath, 0, len + 1);
751 					memcpy(loc->xpath, tmp, len);
752 					/* free memory */
753 					pkg_free(ptr);
754 					ptr = NULL;
755 				} else {
756 					LM_WARN("xpath location-info element(%d) ignored\n", i + 1);
757 				}
758 				xmlFree(xmlbuff);
759 				xmlFreeDoc(new);
760 			}
761 		}
762 	} else {
763 		LM_WARN("xpath '%s' failed\n", xpath);
764 		xmlXPathFreeObject(result);
765 		return -1;
766 	}
767 	xmlXPathFreeObject(result);
768 
769 	return 0;
770 
771 err:
772 	LM_ERR("no more private memory\n");
773 	return -1;
774 }
775 
776 /*
777  * lost_parse_location_info(node, loc)
778  * wrapper to call xpath or simple pos|circle parser (last resort)
779  */
lost_parse_location_info(xmlNodePtr root,p_loc_t loc)780 int lost_parse_location_info(xmlNodePtr root, p_loc_t loc)
781 {
782 
783 	if(lost_xpath_location(root->doc, LOST_XPATH_GP, loc) == 0) {
784 		return 0;
785 	}
786 
787 	LM_WARN("xpath expression failed ... trying pos|circle\n");
788 
789 	if(lost_parse_geo(root, loc) == 0) {
790 		return 0;
791 	}
792 
793 	return -1;
794 }
795 
796 /*
797  * lost_held_location_request(id, lgth, responsetime, exact, type)
798  * assembles and returns locationRequest string (allocated in private memory)
799  */
lost_held_location_request(p_held_t held,int * lgth)800 char *lost_held_location_request(p_held_t held, int *lgth)
801 {
802 	int buffersize = 0;
803 
804 	char buf[BUFSIZE];
805 	char *doc = NULL;
806 
807 	xmlChar *xmlbuff = NULL;
808 	xmlDocPtr request = NULL;
809 
810 	xmlNodePtr ptrLocationRequest = NULL;
811 	xmlNodePtr ptrLocationType = NULL;
812 	xmlNodePtr ptrDevice = NULL;
813 
814 	xmlKeepBlanksDefault(1);
815 	*lgth = 0;
816 
817 	/*
818 https://tools.ietf.org/html/rfc6155
819 https://tools.ietf.org/html/rfc5985
820 
821 <?xml version="1.0" encoding="UTF-8"?>
822 <locationRequest xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="8">
823     <locationType exact="true">geodetic locationURI</locationType>
824     <device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">
825         <uri>sip:user@example.net</uri>
826     </device>
827 </locationRequest>
828 */
829 
830 	/* create request */
831 	request = xmlNewDoc(BAD_CAST "1.0");
832 	if(request == NULL) {
833 		LM_ERR("locationRequest xmlNewDoc() failed\n");
834 		return doc;
835 	}
836 	/* locationRequest - element */
837 	ptrLocationRequest = xmlNewNode(NULL, BAD_CAST "locationRequest");
838 	if(ptrLocationRequest == NULL) {
839 		LM_ERR("locationRequest xmlNewNode() failed\n");
840 		xmlFreeDoc(request);
841 		return doc;
842 	}
843 	xmlDocSetRootElement(request, ptrLocationRequest);
844 	/* properties */
845 	xmlNewProp(ptrLocationRequest, BAD_CAST "xmlns",
846 			BAD_CAST "urn:ietf:params:xml:ns:geopriv:held");
847 	/* responseTime - element (optional) */
848 	if(held->time > 0) {
849 		snprintf(buf, BUFSIZE, "%d", held->time);
850 		xmlNewProp(ptrLocationRequest, BAD_CAST "responseTime", BAD_CAST buf);
851 	}
852 	/* locationType - element (optional) */
853 	ptrLocationType = xmlNewChild(ptrLocationRequest, NULL,
854 			BAD_CAST "locationType", BAD_CAST held->type);
855 	/* properties */
856 	xmlNewProp(ptrLocationType, BAD_CAST "exact",
857 			(held->exact == HELD_EXACT_TRUE) ? BAD_CAST "true"
858 											 : BAD_CAST "false");
859 	/* device - element */
860 	ptrDevice = xmlNewChild(ptrLocationRequest, NULL, BAD_CAST "device", NULL);
861 	if(ptrDevice == NULL) {
862 		LM_ERR("locationRequest xmlNewChild() failed\n");
863 		xmlFreeDoc(request);
864 		return doc;
865 	}
866 	/* properties */
867 	xmlNewProp(ptrDevice, BAD_CAST "xmlns",
868 			BAD_CAST "urn:ietf:params:xml:ns:geopriv:held:id");
869 	/* uri - element */
870 	xmlNewChild(ptrDevice, NULL, BAD_CAST "uri", BAD_CAST held->identity);
871 
872 	xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
873 	if(xmlbuff == NULL) {
874 		LM_ERR("locationRequest xmlDocDumpFormatMemory() failed\n");
875 		xmlFreeDoc(request);
876 		return doc;
877 	}
878 
879 	doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
880 	if(doc == NULL) {
881 		LM_ERR("no more private memory\n");
882 		xmlFree(xmlbuff);
883 		xmlFreeDoc(request);
884 		return doc;
885 	}
886 
887 	memset(doc, 0, buffersize + 1);
888 	memcpy(doc, (char *)xmlbuff, buffersize);
889 	doc[buffersize] = '\0';
890 
891 	*lgth = strlen(doc);
892 
893 	xmlFree(xmlbuff);
894 	xmlFreeDoc(request);
895 
896 	return doc;
897 }
898 
899 /*
900  * lost_find_service_request(loc, lgth)
901  * assembles and returns findService request string (allocated in private memory)
902  */
lost_find_service_request(p_loc_t loc,int * lgth)903 char *lost_find_service_request(p_loc_t loc, int *lgth)
904 {
905 	int buffersize = 0;
906 
907 	char buf[BUFSIZE];
908 	char *doc = NULL;
909 
910 	xmlChar *xmlbuff = NULL;
911 	xmlDocPtr request = NULL;
912 
913 	xmlNodePtr ptrFindService = NULL;
914 	xmlNodePtr ptrLocation = NULL;
915 	xmlNodePtr ptrPoint = NULL;
916 	xmlNodePtr ptrCircle = NULL;
917 	xmlNodePtr ptrRadius = NULL;
918 	xmlNodePtr ptrNode = NULL;
919 
920 	xmlKeepBlanksDefault(1);
921 
922 	*lgth = 0;
923 
924 	/*
925 https://tools.ietf.org/html/rfc5222
926 
927 <?xml version="1.0" encoding="UTF-8"?>
928 <findService
929  xmlns="urn:ietf:params:xml:ns:lost1"
930  xmlns:p2="http://www.opengis.net/gml"
931  serviceBoundary="value"
932  recursive="true">
933     <location id="6020688f1ce1896d" profile="geodetic-2d">
934         <p2:Point id="point1" srsName="urn:ogc:def:crs:EPSG::4326">
935             <p2:pos>37.775 -122.422</p2:pos>
936         </p2:Point>
937     </location>
938     <service>urn:service:sos.police</service>
939 </findService>
940  */
941 	/* create request */
942 	request = xmlNewDoc(BAD_CAST "1.0");
943 	if(request == NULL) {
944 		LM_ERR("findService request xmlNewDoc() failed\n");
945 		return doc;
946 	}
947 	/* findService - element */
948 	ptrFindService = xmlNewNode(NULL, BAD_CAST "findService");
949 	if(ptrFindService == NULL) {
950 		LM_ERR("findService xmlNewNode() failed\n");
951 		xmlFreeDoc(request);
952 		return doc;
953 	}
954 	xmlDocSetRootElement(request, ptrFindService);
955 	/* set properties */
956 	xmlNewProp(ptrFindService, BAD_CAST "xmlns",
957 			BAD_CAST "urn:ietf:params:xml:ns:lost1");
958 	xmlNewProp(ptrFindService, BAD_CAST "xmlns:p2",
959 			BAD_CAST "http://www.opengis.net/gml");
960 	xmlNewProp(ptrFindService, BAD_CAST "serviceBoundary",
961 			(loc->boundary == 1) ? BAD_CAST "value" : BAD_CAST "reference");
962 	xmlNewProp(ptrFindService, BAD_CAST "recursive",
963 			(loc->recursive == 1) ? BAD_CAST "true" : BAD_CAST "false");
964 	/* location - element */
965 	ptrLocation = xmlNewChild(ptrFindService, NULL, BAD_CAST "location", NULL);
966 	xmlNewProp(ptrLocation, BAD_CAST "id", BAD_CAST loc->identity);
967 	xmlNewProp(ptrLocation, BAD_CAST "profile", BAD_CAST loc->profile);
968 	/* set pos */
969 	snprintf(buf, BUFSIZE, "%s %s", loc->latitude, loc->longitude);
970 	/* xpath result */
971 	if(loc->xpath != NULL) {
972 		xmlParseInNodeContext(
973 				ptrLocation, loc->xpath, strlen(loc->xpath), 0, &ptrNode);
974 		if(ptrNode == NULL) {
975 			LM_ERR("locationRequest xmlParseInNodeContext() failed\n");
976 			xmlFreeDoc(request);
977 			return doc;
978 		} else {
979 			xmlAddChild(ptrLocation, ptrNode);
980 		}
981 	}
982 	/* Point */
983 	else if(loc->radius == 0) {
984 		ptrPoint = xmlNewChild(ptrLocation, NULL, BAD_CAST "Point", NULL);
985 		if(ptrPoint == NULL) {
986 			LM_ERR("locationRequest xmlNewChild() failed\n");
987 			xmlFreeDoc(request);
988 			return doc;
989 		}
990 		xmlNewProp(ptrPoint, BAD_CAST "xmlns",
991 				BAD_CAST "http://www.opengis.net/gml");
992 		xmlNewProp(ptrPoint, BAD_CAST "srsName",
993 				BAD_CAST "urn:ogc:def:crs:EPSG::4326");
994 		/* pos */
995 		xmlNewChild(ptrPoint, NULL, BAD_CAST "pos", BAD_CAST buf);
996 	}
997 	/* circle - Point */
998 	else {
999 		ptrCircle = xmlNewChild(ptrLocation, NULL, BAD_CAST "gs:Circle", NULL);
1000 		if(ptrCircle == NULL) {
1001 			LM_ERR("locationRequest xmlNewChild() failed\n");
1002 			xmlFreeDoc(request);
1003 			return doc;
1004 		}
1005 		xmlNewProp(ptrCircle, BAD_CAST "xmlns:gml",
1006 				BAD_CAST "http://www.opengis.net/gml");
1007 		xmlNewProp(ptrCircle, BAD_CAST "xmlns:gs",
1008 				BAD_CAST "http://www.opengis.net/pidflo/1.0");
1009 		xmlNewProp(ptrCircle, BAD_CAST "srsName",
1010 				BAD_CAST "urn:ogc:def:crs:EPSG::4326");
1011 		/* pos */
1012 		xmlNewChild(ptrCircle, NULL, BAD_CAST "gml:pos", BAD_CAST buf);
1013 		/* circle - radius */
1014 		snprintf(buf, BUFSIZE, "%d", loc->radius);
1015 		ptrRadius = xmlNewChild(
1016 				ptrCircle, NULL, BAD_CAST "gs:radius", BAD_CAST buf);
1017 		if(ptrRadius == NULL) {
1018 			LM_ERR("locationRequest xmlNewChild() failed\n");
1019 			xmlFreeDoc(request);
1020 			return doc;
1021 		}
1022 		xmlNewProp(ptrRadius, BAD_CAST "uom",
1023 				BAD_CAST "urn:ogc:def:uom:EPSG::9001");
1024 	}
1025 	/* service - element */
1026 	snprintf(buf, BUFSIZE, "%s", loc->urn);
1027 	xmlNewChild(ptrFindService, NULL, BAD_CAST "service", BAD_CAST buf);
1028 
1029 	xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
1030 	if(xmlbuff == NULL) {
1031 		LM_ERR("findService request xmlDocDumpFormatMemory() failed\n");
1032 		xmlFreeDoc(request);
1033 		return doc;
1034 	}
1035 
1036 	doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
1037 	if(doc == NULL) {
1038 		LM_ERR("no more private memory\n");
1039 		xmlFree(xmlbuff);
1040 		xmlFreeDoc(request);
1041 		return doc;
1042 	}
1043 
1044 	memset(doc, 0, buffersize + 1);
1045 	memcpy(doc, (char *)xmlbuff, buffersize);
1046 	doc[buffersize] = '\0';
1047 
1048 	*lgth = strlen(doc);
1049 
1050 	xmlFree(xmlbuff);
1051 	xmlFreeDoc(request);
1052 
1053 	return doc;
1054 }
1055