1 /*
2  * pua_usrloc module - usrloc pua module
3  *
4  * Copyright (C) 2006 Voice Sistem S.R.L.
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <libxml/parser.h>
27 #include <time.h>
28 
29 #include "../../core/parser/parse_expires.h"
30 #include "../../core/parser/msg_parser.h"
31 #include "../../core/str.h"
32 #include "../../core/str_list.h"
33 #include "../../core/name_alias.h"
34 #include "../../core/socket_info.h"
35 #include "../usrloc/usrloc.h"
36 #include "../usrloc/ul_callback.h"
37 #include "../../modules/tm/tm_load.h"
38 #include "../pua/pua.h"
39 #include "pua_dialoginfo.h"
40 
41 /* global modul parameters */
42 extern int include_callid;
43 extern int include_localremote;
44 extern int include_tags;
45 
46 
47 /* for debug purpose only */
print_publ(publ_info_t * p)48 void print_publ(publ_info_t* p)
49 {
50 	LM_DBG("publ:\n");
51 	LM_DBG("uri= %.*s\n", p->pres_uri->len, p->pres_uri->s);
52 	LM_DBG("id= %.*s\n", p->id.len, p->id.s);
53 	LM_DBG("expires= %d\n", p->expires);
54 }
55 
build_dialoginfo(char * state,str * entity,str * peer,str * callid,unsigned int initiator,str * localtag,str * remotetag,str * localtarget,str * remotetarget)56 str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
57 		unsigned int initiator, str *localtag, str *remotetag,
58 		str *localtarget, str *remotetarget)
59 {
60 	xmlDocPtr  doc = NULL;
61 	xmlNodePtr root_node = NULL;
62 	xmlNodePtr dialog_node = NULL;
63 	xmlNodePtr state_node = NULL;
64 	xmlNodePtr remote_node = NULL;
65 	xmlNodePtr local_node = NULL;
66 	xmlNodePtr tag_node = NULL;
67 	str *body= NULL;
68 	char buf[MAX_URI_SIZE+1];
69 
70 	if (entity->len > MAX_URI_SIZE) {
71 		LM_ERR("entity URI '%.*s' too long, maximum=%d\n",entity->len,
72 				entity->s, MAX_URI_SIZE);
73 		return NULL;
74 	}
75 	memcpy(buf, entity->s, entity->len);
76 	buf[entity->len]= '\0';
77 
78 	/* create the Publish body */
79 	doc = xmlNewDoc(BAD_CAST "1.0");
80 	if(doc==0)
81 		return NULL;
82 
83 	root_node = xmlNewNode(NULL, BAD_CAST "dialog-info");
84 	if(root_node==0)
85 		goto error;
86 
87 	xmlDocSetRootElement(doc, root_node);
88 
89 	xmlNewProp(root_node, BAD_CAST "xmlns",
90 			BAD_CAST "urn:ietf:params:xml:ns:dialog-info");
91 	/* we set the version to 0 but it should be set to the correct value
92 	 * in the pua module */
93 	xmlNewProp(root_node, BAD_CAST "version",
94 			BAD_CAST "0");
95 	xmlNewProp(root_node, BAD_CAST  "state",
96 			BAD_CAST "full" );
97 	xmlNewProp(root_node, BAD_CAST "entity",
98 			BAD_CAST buf);
99 
100 	/* RFC 3245 differs between id and call-id. For example if a call
101 	 * is forked and 2 early dialogs are established, we should send 2
102 	 * PUBLISH requests, both have the same call-id but different id.
103 	 * Thus, id could be for example derived from the totag.
104 	 *
105 	 * Currently the dialog module does not support multiple dialogs.
106 	 * Thus, it does no make sense to differ here between multiple dialog.
107 	 * Thus, id and call-id will be populated identically */
108 
109 	/* dialog tag */
110 	dialog_node =xmlNewChild(root_node, NULL, BAD_CAST "dialog", NULL) ;
111 	if( dialog_node ==NULL)
112 	{
113 		LM_ERR("while adding child\n");
114 		goto error;
115 	}
116 
117 	if (callid->len > MAX_URI_SIZE) {
118 		LM_ERR("call-id '%.*s' too long, maximum=%d\n", callid->len,
119 				callid->s, MAX_URI_SIZE);
120 		goto error;
121 	}
122 	memcpy(buf, callid->s, callid->len);
123 	buf[callid->len]= '\0';
124 
125 	xmlNewProp(dialog_node, BAD_CAST "id", BAD_CAST buf);
126 	if (include_callid) {
127 		xmlNewProp(dialog_node, BAD_CAST "call-id", BAD_CAST buf);
128 	}
129 	if (include_tags) {
130 		if (localtag && localtag->s) {
131 			if (localtag->len > MAX_URI_SIZE) {
132 				LM_ERR("localtag '%.*s' too long, maximum=%d\n",
133 						localtag->len, localtag->s, MAX_URI_SIZE);
134 				goto error;
135 			}
136 			memcpy(buf, localtag->s, localtag->len);
137 			buf[localtag->len]= '\0';
138 			xmlNewProp(dialog_node, BAD_CAST "local-tag", BAD_CAST buf);
139 		}
140 		if (remotetag && remotetag->s) {
141 			if (remotetag->len > MAX_URI_SIZE) {
142 				LM_ERR("remotetag '%.*s' too long, maximum=%d\n",
143 						remotetag->len, remotetag->s, MAX_URI_SIZE);
144 				goto error;
145 			}
146 			memcpy(buf, remotetag->s, remotetag->len);
147 			buf[remotetag->len]= '\0';
148 			xmlNewProp(dialog_node, BAD_CAST "remote-tag", BAD_CAST buf);
149 		}
150 	}
151 
152 	if (initiator) {
153 		xmlNewProp(dialog_node, BAD_CAST "direction", BAD_CAST "initiator");
154 	}else {
155 		xmlNewProp(dialog_node, BAD_CAST "direction", BAD_CAST "recipient");
156 	}
157 
158 	/* state tag */
159 	state_node = xmlNewChild(dialog_node, NULL, BAD_CAST "state",
160 			BAD_CAST state) ;
161 	if( state_node ==NULL)
162 	{
163 		LM_ERR("while adding child\n");
164 		goto error;
165 	}
166 
167 	if (include_localremote) {
168 		/* remote tag*/
169 		remote_node = xmlNewChild(dialog_node, NULL, BAD_CAST "remote", NULL) ;
170 		if( remote_node ==NULL)
171 		{
172 			LM_ERR("while adding child\n");
173 			goto error;
174 		}
175 
176 		if (peer->len > MAX_URI_SIZE) {
177 			LM_ERR("peer '%.*s' too long, maximum=%d\n", peer->len, peer->s,
178 					MAX_URI_SIZE);
179 			goto error;
180 		}
181 		memcpy(buf, peer->s, peer->len);
182 		buf[peer->len]= '\0';
183 
184 		tag_node = xmlNewChild(remote_node, NULL, BAD_CAST "identity",
185 				BAD_CAST buf) ;
186 		if( tag_node ==NULL)
187 		{
188 			LM_ERR("while adding child\n");
189 			goto error;
190 		}
191 		tag_node = xmlNewChild(remote_node, NULL, BAD_CAST "target", NULL);
192 		if( tag_node ==NULL)
193 		{
194 			LM_ERR("while adding child\n");
195 			goto error;
196 		}
197 		if (remotetarget && remotetarget->s) {
198 			memcpy(buf, remotetarget->s, remotetarget->len);
199 			buf[remotetarget->len]= '\0';
200 		}
201 		xmlNewProp(tag_node, BAD_CAST "uri", BAD_CAST buf);
202 
203 		/* local tag*/
204 		local_node = xmlNewChild(dialog_node, NULL, BAD_CAST "local", NULL);
205 		if( local_node ==NULL)
206 		{
207 			LM_ERR("while adding child\n");
208 			goto error;
209 		}
210 
211 		if (entity->len > MAX_URI_SIZE) {
212 			LM_ERR("entity '%.*s' too long, maximum=%d\n",
213 					entity->len, entity->s, MAX_URI_SIZE);
214 			goto error;
215 		}
216 		memcpy(buf, entity->s, entity->len);
217 		buf[entity->len]= '\0';
218 
219 		tag_node = xmlNewChild(local_node, NULL, BAD_CAST "identity",
220 				BAD_CAST buf) ;
221 		if( tag_node ==NULL)
222 		{
223 			LM_ERR("while adding child\n");
224 			goto error;
225 		}
226 		tag_node = xmlNewChild(local_node, NULL, BAD_CAST "target", NULL);
227 		if( tag_node ==NULL)
228 		{
229 			LM_ERR("while adding child\n");
230 			goto error;
231 		}
232 		if (localtarget && localtarget->s) {
233 			memcpy(buf, localtarget->s, localtarget->len);
234 			buf[localtarget->len]= '\0';
235 		}
236 		xmlNewProp(tag_node, BAD_CAST "uri", BAD_CAST buf);
237 	}
238 
239 	/* create the body */
240 	body = (str*)pkg_malloc(sizeof(str));
241 	if(body == NULL)
242 	{
243 		PKG_MEM_ERROR;
244 		goto error;
245 	}
246 	memset(body, 0, sizeof(str));
247 
248 	xmlDocDumpFormatMemory(doc,(unsigned char**)(void*)&body->s,&body->len,1);
249 
250 	if(body->s==NULL || body->len==0) {
251 		LM_ERR("failure formatting xml doc from memory or empty doc\n");
252 		goto error;
253 	}
254 
255 	LM_DBG("new_body:\n%.*s\n", body->len, body->s);
256 
257 	/*free the document */
258 	xmlFreeDoc(doc);
259 	xmlCleanupParser();
260 
261 	return body;
262 
263 error:
264 	if(body)
265 	{
266 		if(body->s)
267 			xmlFree(body->s);
268 		pkg_free(body);
269 	}
270 	if(doc) {
271 		xmlFreeDoc(doc);
272 		xmlCleanupParser();
273 	}
274 
275 	return NULL;
276 }
277 
dialog_publish(char * state,str * ruri,str * entity,str * peer,str * callid,unsigned int initiator,unsigned int lifetime,str * localtag,str * remotetag,str * localtarget,str * remotetarget,unsigned short do_pubruri_localcheck)278 void dialog_publish(char *state, str* ruri, str *entity, str *peer, str *callid,
279 		unsigned int initiator, unsigned int lifetime, str *localtag,
280 		str *remotetag, str *localtarget, str *remotetarget,
281 		unsigned short do_pubruri_localcheck)
282 {
283 	str* body= NULL;
284 	str uri= {NULL, 0};
285 	publ_info_t* publ= NULL;
286 	int size= 0;
287 	str content_type;
288 	struct sip_uri ruri_uri;
289 
290 
291 	if (parse_uri(ruri->s, ruri->len, &ruri_uri) < 0) {
292 		LM_ERR("failed to parse the PUBLISH R-URI\n");
293 		return;
294 	}
295 
296 	if(do_pubruri_localcheck) {
297 
298 		/* send PUBLISH only if the receiver PUBLISH R-URI is local*/
299 		if (!check_self(&(ruri_uri.host), 0, 0)) {
300 			LM_DBG("do not send PUBLISH to external URI %.*s\n",
301 					ruri->len, ruri->s);
302 			return;
303 		}
304 
305 	}
306 
307 	content_type.s= "application/dialog-info+xml";
308 	content_type.len= 27;
309 
310 	body= build_dialoginfo(state, entity, peer, callid, initiator, localtag,
311 			remotetag, localtarget, remotetarget);
312 	if(body == NULL || body->s == NULL)
313 		goto error;
314 
315 	LM_DBG("publish uri= %.*s\n", ruri->len, ruri->s);
316 
317 	size= sizeof(publ_info_t)
318 		+ sizeof(str) 			/* *pres_uri */
319 		+ ( ruri->len 		/* pres_uri->s */
320 				+ callid->len + 16	/* id.s */
321 				+ content_type.len	/* content_type.s */
322 			)*sizeof(char);
323 
324 	if(body)
325 		size+= sizeof(str)+ body->len* sizeof(char);
326 
327 	publ= (publ_info_t*)pkg_malloc(size);
328 	if(publ== NULL)
329 	{
330 		PKG_MEM_ERROR;
331 		goto error;
332 	}
333 	memset(publ, 0, size);
334 	size= sizeof(publ_info_t);
335 
336 	publ->pres_uri= (str*)((char*)publ + size);
337 	size+= sizeof(str);
338 	publ->pres_uri->s= (char*)publ+ size;
339 	memcpy(publ->pres_uri->s, ruri->s, ruri->len);
340 	publ->pres_uri->len= ruri->len;
341 	size+= ruri->len;
342 
343 	if(body)
344 	{
345 		publ->body= (str*)( (char*)publ + size);
346 		size+= sizeof(str);
347 
348 		publ->body->s= (char*)publ + size;
349 		memcpy(publ->body->s, body->s, body->len);
350 		publ->body->len= body->len;
351 		size+= body->len;
352 	}
353 	publ->id.s= (char*)publ+ size;
354 	memcpy(publ->id.s, "DIALOG_PUBLISH.", 15);
355 	memcpy(publ->id.s+15, callid->s, callid->len);
356 	publ->id.len= 15+ callid->len;
357 	size+= publ->id.len;
358 
359 	publ->content_type.s= (char*)publ+ size;
360 	memcpy(publ->content_type.s, content_type.s, content_type.len);
361 	publ->content_type.len= content_type.len;
362 	size+= content_type.len;
363 
364 	publ->expires= lifetime;
365 
366 	/* make UPDATE_TYPE, as if this "publish dialog" is not found
367 	 * by pua it will fallback to INSERT_TYPE anyway */
368 	publ->flag|= UPDATE_TYPE;
369 
370 	publ->source_flag|= DIALOG_PUBLISH;
371 	publ->event|= DIALOG_EVENT;
372 	publ->extra_headers= NULL;
373 	print_publ(publ);
374 	if(pua_send_publish(publ)< 0)
375 	{
376 		LM_ERR("while sending publish\n");
377 	}
378 
379 error:
380 
381 	if(publ)
382 		pkg_free(publ);
383 
384 	if(body)
385 	{
386 		if(body->s)
387 			xmlFree(body->s);
388 		pkg_free(body);
389 	}
390 
391 	if(uri.s)
392 		pkg_free(uri.s);
393 
394 	return;
395 }
396 
397 
398 
dialog_publish_multi(char * state,struct str_list * ruris,str * entity,str * peer,str * callid,unsigned int initiator,unsigned int lifetime,str * localtag,str * remotetag,str * localtarget,str * remotetarget,unsigned short do_pubruri_localcheck)399 void dialog_publish_multi(char *state, struct str_list* ruris, str *entity,
400 		str *peer, str *callid, unsigned int initiator, unsigned int lifetime,
401 		str *localtag, str *remotetag,
402 		str *localtarget, str *remotetarget, unsigned short
403 		do_pubruri_localcheck)
404 {
405 	while(ruris) {
406 		LM_DBG("CALLING dialog_publish for URI %.*s\n",
407 				ruris->s.len, ruris->s.s);
408 		dialog_publish(state,&(ruris->s),entity,peer,callid,initiator,
409 				lifetime,localtag,remotetag,localtarget,remotetarget,
410 				do_pubruri_localcheck);
411 		ruris=ruris->next;
412 	}
413 }
414