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 
47 #include "../cdp/cdp_load.h"
48 #include "../../modules/tm/tm_load.h"
49 #include "cxdx_avp.h"
50 
51 
52 
53 static str s_empty = {0, 0};
54 
55 /**
56  * Create and add an AVP to a Diameter message.
57  * @param m - Diameter message to add to
58  * @param d - the payload data
59  * @param len - length of the payload data
60  * @param avp_code - the code of the AVP
61  * @param flags - flags for the AVP
62  * @param vendorid - the value of the vendor id or 0 if none
63  * @param data_do - what to do with the data when done
64  * @param func - the name of the calling function, for debugging purposes
65  * @returns 1 on success or 0 on failure
66  */
cxdx_add_avp(AAAMessage * m,char * d,int len,int avp_code,int flags,int vendorid,int data_do,const char * func)67 static int cxdx_add_avp(AAAMessage *m,char *d,int len,int avp_code,
68 	int flags,int vendorid,int data_do,const char *func)
69 {
70 	AAA_AVP *avp;
71 	if (vendorid!=0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
72 	avp = cdpb.AAACreateAVP(avp_code,flags,vendorid,d,len,data_do);
73 	if (!avp) {
74 		LM_ERR("%s: Failed creating avp\n",func);
75 		return 0;
76 	}
77 	if (cdpb.AAAAddAVPToMessage(m,avp,m->avpList.tail)!=AAA_ERR_SUCCESS) {
78 		LM_ERR("%s: Failed adding avp to message\n",func);
79 		cdpb.AAAFreeAVP(&avp);
80 		return 0;
81 	}
82 	return 1;
83 }
84 
85 /**
86  * Create and add an AVP to a list of AVPs.
87  * @param list - the AVP list to add to
88  * @param d - the payload data
89  * @param len - length of the payload data
90  * @param avp_code - the code of the AVP
91  * @param flags - flags for the AVP
92  * @param vendorid - the value of the vendor id or 0 if none
93  * @param data_do - what to do with the data when done
94  * @param func - the name of the calling function, for debugging purposes
95  * @returns 1 on success or 0 on failure
96  */
cxdx_add_avp_list(AAA_AVP_LIST * list,char * d,int len,int avp_code,int flags,int vendorid,int data_do,const char * func)97 static int cxdx_add_avp_list(AAA_AVP_LIST *list,char *d,int len,int avp_code,
98 	int flags,int vendorid,int data_do,const char *func)
99 {
100 	AAA_AVP *avp;
101 	if (vendorid!=0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
102 	avp = cdpb.AAACreateAVP(avp_code,flags,vendorid,d,len,data_do);
103 	if (!avp) {
104 		LM_ERR("%s: Failed creating avp\n",func);
105 		return 0;
106 	}
107 	if (list->tail) {
108 		avp->prev=list->tail;
109 		avp->next=0;
110 		list->tail->next = avp;
111 		list->tail=avp;
112 	} else {
113 		list->head = avp;
114 		list->tail = avp;
115 		avp->next=0;
116 		avp->prev=0;
117 	}
118 
119 	return 1;
120 }
121 
122 /**
123  * Returns the value of a certain AVP from a Diameter message.
124  * @param m - Diameter message to look into
125  * @param avp_code - the code to search for
126  * @param vendorid - the value of the vendor id to look for or 0 if none
127  * @param func - the name of the calling function, for debugging purposes
128  * @returns the str with the payload on success or an empty string on failure
129  */
cxdx_get_avp(AAAMessage * msg,int avp_code,int vendor_id,const char * func)130 static str cxdx_get_avp(AAAMessage *msg,int avp_code,int vendor_id,
131 							const char *func)
132 {
133 	AAA_AVP *avp;
134 	str r={0,0};
135 
136 	avp = cdpb.AAAFindMatchingAVP(msg,0,avp_code,vendor_id,0);
137 	if (avp==0){
138 		LM_INFO("%s: Failed finding avp\n",func);
139 		return r;
140 	}
141 	else
142 		return avp->data;
143 }
144 
cxdx_add_call_id(AAAMessage * msg,str data)145 int cxdx_add_call_id(AAAMessage *msg, str data)
146 {
147     return
148 	cxdx_add_avp(msg,data.s,data.len,
149 		AVP_Call_Id,
150 		AAA_AVP_FLAG_VENDOR_SPECIFIC,
151 		50,
152 		AVP_DUPLICATE_DATA,
153 		__FUNCTION__);
154 }
155 
156 /**
157  * Creates and adds a Destination-Realm AVP.
158  * @param msg - the Diameter message to add to.
159  * @param data - the value for the AVP payload
160  * @returns 1 on success or 0 on error
161  */
cxdx_add_destination_realm(AAAMessage * msg,str data)162 int cxdx_add_destination_realm(AAAMessage *msg,str data)
163 {
164 	return
165 	cxdx_add_avp(msg,data.s,data.len,
166 		AVP_Destination_Realm,
167 		AAA_AVP_FLAG_MANDATORY,
168 		0,
169 		AVP_DUPLICATE_DATA,
170 		__FUNCTION__);
171 }
172 
173 
174 /**
175  * Creates and adds a Vendor-Specifig-Application-ID AVP.
176  * @param msg - the Diameter message to add to.
177  * @param vendor_id - the value of the vendor_id,
178  * @param auth_id - the authorization application id
179  * @param acct_id - the accounting application id
180  * @returns 1 on success or 0 on error
181  */
cxdx_add_vendor_specific_appid(AAAMessage * msg,unsigned int vendor_id,unsigned int auth_id,unsigned int acct_id)182 int cxdx_add_vendor_specific_appid(AAAMessage *msg,unsigned int vendor_id,
183 	unsigned int auth_id,unsigned int acct_id)
184 {
185 	AAA_AVP_LIST list;
186 	str group;
187 	char x[4];
188 
189 	list.head=0;list.tail=0;
190 
191 	set_4bytes(x,vendor_id);
192 	cxdx_add_avp_list(&list,
193 		x,4,
194 		AVP_Vendor_Id,
195 		AAA_AVP_FLAG_MANDATORY,
196 		0,
197 		AVP_DUPLICATE_DATA,
198 		__FUNCTION__);
199 
200 	if (auth_id) {
201 		set_4bytes(x,auth_id);
202 		cxdx_add_avp_list(&list,
203 			x,4,
204 			AVP_Auth_Application_Id,
205 			AAA_AVP_FLAG_MANDATORY,
206 			0,
207 			AVP_DUPLICATE_DATA,
208 			__FUNCTION__);
209 	}
210 	if (acct_id) {
211 		set_4bytes(x,acct_id);
212 		cxdx_add_avp_list(&list,
213 			x,4,
214 			AVP_Acct_Application_Id,
215 			AAA_AVP_FLAG_MANDATORY,
216 			0,
217 			AVP_DUPLICATE_DATA,
218 			__FUNCTION__);
219 	}
220 
221 	group = cdpb.AAAGroupAVPS(list);
222 
223 	cdpb.AAAFreeAVPList(&list);
224 
225 	return
226 	cxdx_add_avp(msg,group.s,group.len,
227 		AVP_Vendor_Specific_Application_Id,
228 		AAA_AVP_FLAG_MANDATORY,
229 		0,
230 		AVP_FREE_DATA,
231 		__FUNCTION__);
232 }
233 
234 /**
235  * Creates and adds a Auth-Session-State AVP.
236  * @param msg - the Diameter message to add to.
237  * @param data - the value for the AVP payload
238  * @returns 1 on success or 0 on error
239  */
cxdx_add_auth_session_state(AAAMessage * msg,unsigned int data)240 int cxdx_add_auth_session_state(AAAMessage *msg,unsigned int data)
241 {
242 	char x[4];
243 	set_4bytes(x,data);
244 	return
245 	cxdx_add_avp(msg,x,4,
246 		AVP_Auth_Session_State,
247 		AAA_AVP_FLAG_MANDATORY,
248 		0,
249 		AVP_DUPLICATE_DATA,
250 		__FUNCTION__);
251 }
252 
253 /**
254  * Creates and adds a User-Name AVP.
255  * @param msg - the Diameter message to add to.
256  * @param data - the value for the AVP payload
257  * @returns 1 on success or 0 on error
258  */
cxdx_add_user_name(AAAMessage * msg,str data)259 int cxdx_add_user_name(AAAMessage *msg,str data)
260 {
261 	return
262 	cxdx_add_avp(msg,data.s,data.len,
263 		AVP_User_Name,
264 		AAA_AVP_FLAG_MANDATORY,
265 		0,
266 		AVP_DUPLICATE_DATA,
267 		__FUNCTION__);
268 }
269 
270 /**
271  * Creates and adds a Public Identity AVP.
272  * @param msg - the Diameter message to add to.
273  * @param data - the value for the AVP payload
274  * @returns 1 on success or 0 on error
275  */
cxdx_add_public_identity(AAAMessage * msg,str data)276 int cxdx_add_public_identity(AAAMessage *msg,str data)
277 {
278 	return
279 	cxdx_add_avp(msg,data.s,data.len,
280 		AVP_IMS_Public_Identity,
281 		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
282 		IMS_vendor_id_3GPP,
283 		AVP_DUPLICATE_DATA,
284 		__FUNCTION__);
285 }
286 
287 /**
288  * Creates and adds a Visited-Network-ID AVP.
289  * @param msg - the Diameter message to add to.
290  * @param data - the value for the AVP payload
291  * @returns 1 on success or 0 on error
292  */
cxdx_add_visited_network_id(AAAMessage * msg,str data)293 int cxdx_add_visited_network_id(AAAMessage *msg,str data)
294 {
295 	return
296 	cxdx_add_avp(msg,data.s,data.len,
297 		AVP_IMS_Visited_Network_Identifier,
298 		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
299 		IMS_vendor_id_3GPP,
300 		AVP_DUPLICATE_DATA,
301 		__FUNCTION__);
302 }
303 
304 /**
305  * Creates and adds a UAR-Flags AVP.
306  * @param msg - the Diameter message to add to.
307  * @param data - the value for the AVP payload
308  * @returns 1 on success or 0 on error
309  */
cxdx_add_UAR_flags(AAAMessage * msg,unsigned int sos_reg)310 int cxdx_add_UAR_flags(AAAMessage *msg, unsigned int sos_reg)
311 {
312 
313 	char x[4];
314 	/* optional AVP*/
315 	if(!sos_reg)
316 		return 1;
317 
318 	set_4bytes(x, AVP_IMS_UAR_Flags_Emergency_Registration);
319 	return
320 	cxdx_add_avp(msg,x,4,
321 		AVP_IMS_UAR_Flags,
322 		AAA_AVP_FLAG_VENDOR_SPECIFIC,
323 		IMS_vendor_id_3GPP,
324 		AVP_DUPLICATE_DATA,
325 		__FUNCTION__);
326 
327 }
328 /**
329  * Creates and adds a Authorization-Type AVP.
330  * @param msg - the Diameter message to add to.
331  * @param data - the value for the AVP payload
332  * @returns 1 on success or 0 on error
333  */
cxdx_add_authorization_type(AAAMessage * msg,unsigned int data)334 int cxdx_add_authorization_type(AAAMessage *msg,unsigned int data)
335 {
336 	char x[4];
337 	set_4bytes(x,data);
338 	return
339 	cxdx_add_avp(msg,x,4,
340 		AVP_IMS_User_Authorization_Type,
341 		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
342 		IMS_vendor_id_3GPP,
343 		AVP_DUPLICATE_DATA,
344 		__FUNCTION__);
345 }
346 
347 /**
348  * Returns the Result-Code AVP from a Diameter message.
349  * @param msg - the Diameter message
350  * @returns the AVP payload on success or an empty string on error
351  */
cxdx_get_result_code(AAAMessage * msg,int * data)352 int cxdx_get_result_code(AAAMessage *msg, int *data)
353 {
354 	str s;
355 	s = cxdx_get_avp(msg,
356 		AVP_Result_Code,
357 		0,
358 		__FUNCTION__);
359 	if (!s.s) return 0;
360 	*data = get_4bytes(s.s);
361 	return 1;
362 }
363 
364 /**
365  * Returns the Experimental-Result-Code AVP from a Diameter message.
366  * @param msg - the Diameter message
367  * @returns the AVP payload on success or an empty string on error
368  */
cxdx_get_experimental_result_code(AAAMessage * msg,int * data)369 int cxdx_get_experimental_result_code(AAAMessage *msg, int *data)
370 {
371 	AAA_AVP_LIST list;
372 	AAA_AVP *avp;
373 	str grp;
374 	grp = cxdx_get_avp(msg,
375 		AVP_IMS_Experimental_Result,
376 		0,
377 		__FUNCTION__);
378 	if (!grp.s) return 0;
379 
380 	list = cdpb.AAAUngroupAVPS(grp);
381 
382 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Experimental_Result_Code,0,0);
383 	if (!avp||!avp->data.s) {
384 		cdpb.AAAFreeAVPList(&list);
385 		return 0;
386 	}
387 
388 	*data = get_4bytes(avp->data.s);
389 	cdpb.AAAFreeAVPList(&list);
390 
391 	return 1;
392 }
393 
394 /**
395  * Returns the Server-Name AVP from a Diameter message.
396  * @param msg - the Diameter message
397  * @returns the AVP payload on success or an empty string on error
398  */
cxdx_get_server_name(AAAMessage * msg)399 str cxdx_get_server_name(AAAMessage *msg)
400 {
401 	return cxdx_get_avp(msg,
402 		AVP_IMS_Server_Name,
403 		IMS_vendor_id_3GPP,
404 		__FUNCTION__);
405 }
406 
407 /**
408  * Returns the Capabilities from the grouped AVP from a Diameter message.
409  * @param msg - the Diameter message
410  * @param m - array to be filled with the retrieved mandatory capabilities
411  * @param m_cnt - size of the array above to be filled
412  * @param o - array to be filled with the retrieved optional capabilities
413  * @param o_cnt - size of the array above to be filled
414  * @returns 1 on success 0 on fail
415  */
cxdx_get_capabilities(AAAMessage * msg,int ** m,int * m_cnt,int ** o,int * o_cnt,str ** p,int * p_cnt)416 int cxdx_get_capabilities(AAAMessage *msg,int **m,int *m_cnt,int **o,int *o_cnt,
417 	str **p,int *p_cnt)
418 {
419 	AAA_AVP_LIST list;
420 	AAA_AVP *avp;
421 	str grp;
422 	grp = cxdx_get_avp(msg,
423 		AVP_IMS_Server_Capabilities,
424 		IMS_vendor_id_3GPP,
425 		__FUNCTION__);
426 	if (!grp.s) return 0;
427 
428 	list = cdpb.AAAUngroupAVPS(grp);
429 
430 	avp = list.head;
431 	*m_cnt=0;
432 	*o_cnt=0;
433 	*p_cnt=0;
434 	while(avp){
435 		if (avp->code == AVP_IMS_Mandatory_Capability) (*m_cnt)++;
436 		if (avp->code == AVP_IMS_Optional_Capability) (*o_cnt)++;
437 		if (avp->code == AVP_IMS_Server_Name) (*p_cnt)++;
438 		avp = avp->next;
439 	}
440 	avp = list.head;
441 	*m=shm_malloc(sizeof(int)*(*m_cnt));
442 	if (!*m){
443 		LM_ERR("cannot allocated %lx bytes of shm.\n",
444 			sizeof(int)*(*m_cnt));
445 		goto error;
446 	}
447 	*o=shm_malloc(sizeof(int)*(*o_cnt));
448 	if (!*o){
449 		LM_ERR("cannot allocated %lx bytes of shm.\n",
450 			sizeof(int)*(*o_cnt));
451 		goto error;
452 	}
453 	*p=shm_malloc(sizeof(str)*(*p_cnt));
454 	if (!*p){
455 		LM_ERR("cannot allocated %lx bytes of shm.\n",
456 			sizeof(str)*(*p_cnt));
457 		goto error;
458 	}
459 
460 	*m_cnt=0;
461 	*o_cnt=0;
462 	*p_cnt=0;
463 	while(avp){
464 		if (avp->code == AVP_IMS_Mandatory_Capability)
465 			(*m)[(*m_cnt)++]=get_4bytes(avp->data.s);
466 		if (avp->code == AVP_IMS_Optional_Capability)
467 			(*o)[(*o_cnt)++]=get_4bytes(avp->data.s);
468 		if (avp->code == AVP_IMS_Server_Name)
469 			(*p)[(*p_cnt)++]=avp->data;
470 		avp = avp->next;
471 	}
472 	cdpb.AAAFreeAVPList(&list);
473 	return 1;
474 
475 error:
476 	cdpb.AAAFreeAVPList(&list);
477 	if (*m) shm_free(*m);
478 	if (*o) shm_free(*o);
479 	if (*p) shm_free(*p);
480 	*m_cnt=0;
481 	*o_cnt=0;
482 	*p_cnt=0;
483 	return 0;
484 }
485 
486 /**
487  * Transactional SIP response - tries to create a transaction if none found.
488  * @param msg - message to reply to
489  * @param code - the Status-code for the response
490  * @param text - the Reason-Phrase for the response
491  * @returns the tmb.t_reply() result
492  */
cscf_reply_transactional(struct sip_msg * msg,int code,char * text)493 int cscf_reply_transactional(struct sip_msg *msg, int code, char *text)
494 {
495 	unsigned int hash,label;
496 	if (tmb.t_get_trans_ident(msg,&hash,&label)<0){
497 
498 		if (tmb.t_newtran(msg)<0)
499 			LM_ERR("Failed creating SIP transaction\n");
500 	}
501 	return tmb.t_reply(msg,code,text);
502 }
503 
504 /**
505  * Creates and adds a SIP-Number-Auth-Items AVP.
506  * @param msg - the Diameter message to add to.
507  * @param data - the value for the AVP payload
508  * @returns 1 on success or 0 on error
509  */
cxdx_add_sip_number_auth_items(AAAMessage * msg,unsigned int data)510 int cxdx_add_sip_number_auth_items(AAAMessage *msg,unsigned int data)
511 {
512 	char x[4];
513 	set_4bytes(x,data);
514 	return
515 	cxdx_add_avp(msg,x,4,
516 		AVP_IMS_SIP_Number_Auth_Items,
517 		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
518 		IMS_vendor_id_3GPP,
519 		AVP_DUPLICATE_DATA,
520 		__FUNCTION__);
521 }
522 
523 /**
524  * Creates and adds a SIP-Auth-Data-Item AVP.
525  * @param msg - the Diameter message to add to.
526  * @param auth_scheme - the value for the authorization scheme AVP
527  * @param auth - the value for the authorization AVP
528  * @returns 1 on success or 0 on error
529  */
cxdx_add_sip_auth_data_item_request(AAAMessage * msg,str auth_scheme,str auth,str username,str realm,str method,str server_name)530 int cxdx_add_sip_auth_data_item_request(AAAMessage *msg, str auth_scheme, str auth, str username, str realm,str method, str server_name)
531 {
532 	AAA_AVP_LIST list;
533 	str group;
534 	str etsi_authorization = {0, 0};
535 	list.head=0;list.tail=0;
536 
537 	if (auth_scheme.len){
538 		cxdx_add_avp_list(&list,
539 			auth_scheme.s,auth_scheme.len,
540 			AVP_IMS_SIP_Authentication_Scheme,
541 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
542 			IMS_vendor_id_3GPP,
543 			AVP_DONT_FREE_DATA,
544 			__FUNCTION__);
545 	}
546 	if (auth.len){
547 		cxdx_add_avp_list(&list,
548 			auth.s,auth.len,
549 			AVP_IMS_SIP_Authorization,
550 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
551 			IMS_vendor_id_3GPP,
552 			AVP_DONT_FREE_DATA,
553 			__FUNCTION__);
554 	}
555 
556 	if (server_name.len)
557 	{
558 		etsi_authorization = cxdx_ETSI_sip_authorization(username, realm, s_empty, server_name, s_empty, s_empty, method, s_empty);
559 
560 		if (etsi_authorization.len){
561 			cxdx_add_avp_list(&list,
562 				etsi_authorization.s,etsi_authorization.len,
563 				AVP_ETSI_SIP_Authorization,
564 				AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
565 				IMS_vendor_id_ETSI,
566 				AVP_FREE_DATA,
567 				__FUNCTION__);
568 		}
569 	}
570 
571 	if (!list.head) return 1;
572 	group = cdpb.AAAGroupAVPS(list);
573 
574 	cdpb.AAAFreeAVPList(&list);
575 
576 	return
577 	cxdx_add_avp(msg,group.s,group.len,
578 		AVP_IMS_SIP_Auth_Data_Item,
579 		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
580 		IMS_vendor_id_3GPP,
581 		AVP_FREE_DATA,
582 		__FUNCTION__);
583 }
584 
585 /**
586  * Creates and adds a Server-Name AVP.
587  * @param msg - the Diameter message to add to.
588  * @param data - the value for the AVP payload
589  * @returns 1 on success or 0 on error
590  */
cxdx_add_server_name(AAAMessage * msg,str data)591 int cxdx_add_server_name(AAAMessage *msg,str data)
592 {
593 	return
594 	cxdx_add_avp(msg,data.s,data.len,
595 		AVP_IMS_Server_Name,
596 		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
597 		IMS_vendor_id_3GPP,
598 		AVP_DUPLICATE_DATA,
599 		__FUNCTION__);
600 }
601 
602 /**
603  * Returns the SIP-Number-Auth-Items AVP from a Diameter message.
604  * @param msg - the Diameter message
605  * @returns the number or 0 on error
606  */
cxdx_get_sip_number_auth_items(AAAMessage * msg,int * data)607 int cxdx_get_sip_number_auth_items(AAAMessage *msg, int *data)
608 {
609 	str s;
610 	s = cxdx_get_avp(msg,
611 		AVP_IMS_SIP_Number_Auth_Items,
612 		IMS_vendor_id_3GPP,
613 		__FUNCTION__);
614 	if (!s.s) return 0;
615 	*data = get_4bytes(s.s);
616 	return 1;
617 }
618 
619 /**
620  * Returns the Auth-Data-Item from a Diameter answer message.
621  * @param msg - the Diameter message
622  * @param auth_date - the string to fill with the authorization data
623  * @param item_number - the int to fill with the item number
624  * @param auth_scheme - the string to fill with the authentication scheme data
625  * @param authenticate - the string to fill with the authenticate data
626  * @param authorization - the string to fill with the authorization data
627  * @param ck - the string to fill with the cipher key
628  * @param ik - the string to fill with the integrity key
629  * @returns the AVP payload on success or an empty string on error
630  */
cxdx_get_auth_data_item_answer(AAAMessage * msg,AAA_AVP ** auth_data,int * item_number,str * auth_scheme,str * authenticate,str * authorization,str * ck,str * ik,str * ip,str * ha1,str * response_auth,str * digest_realm,str * line_identifier)631 int cxdx_get_auth_data_item_answer(AAAMessage *msg, AAA_AVP **auth_data,
632 	int *item_number,str *auth_scheme,str *authenticate,str *authorization,
633 	str *ck,str *ik,
634 	str *ip,
635 	str *ha1, str *response_auth, str *digest_realm,
636 	str *line_identifier)
637 {
638 	AAA_AVP_LIST list;
639 	AAA_AVP_LIST list2;
640 	AAA_AVP *avp;
641 	AAA_AVP *avp2;
642 	str grp;
643 	ha1->s = 0; ha1->len = 0;
644 	*auth_data = cdpb.AAAFindMatchingAVP(msg,*auth_data,AVP_IMS_SIP_Auth_Data_Item,
645 		IMS_vendor_id_3GPP,0);
646 	if (!*auth_data) return 0;
647 
648 	grp = (*auth_data)->data;
649 	if (!grp.len) return 0;
650 
651 	list = cdpb.AAAUngroupAVPS(grp);
652 
653 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Item_Number,
654 		IMS_vendor_id_3GPP,0);
655 	if (!avp||avp->data.len!=4) *item_number=0;
656 	else *item_number = get_4bytes(avp->data.s);
657 
658 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Authentication_Scheme,
659 		IMS_vendor_id_3GPP,0);
660 	if (!avp||!avp->data.s) {auth_scheme->s=0;auth_scheme->len=0;}
661 	else *auth_scheme = avp->data;
662 
663 	/* Early-IMS */
664 	ip->s=0;ip->len=0;
665 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_Framed_IP_Address,0,0);
666 	if (avp && avp->data.s){
667 		if (avp->data.len!=4){
668 			LM_ERR("Invalid length of AVP Framed IP Address (should be 4 for AVP_Framed_IP_Address) >%d.\n",
669 				avp->data.len);
670 		}
671 		ip->len = 4;
672 		ip->s = avp->data.s;
673 	} else {
674 		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_Framed_IPv6_Prefix,0,0);
675 		if (avp && avp->data.s){
676 			if (avp->data.len==0){
677 				LM_ERR("Invalid length of AVP Framed IPv6 Prefix (should be >0 for AVP_Framed_IPv6_Prefix) >%d.\n",
678 					avp->data.len);
679 			}
680 			ip->len = avp->data.len;
681 			ip->s = avp->data.s;
682 		}
683 	}
684 
685 	/* Digest */
686 
687 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_CableLabs_SIP_Digest_Authenticate,IMS_vendor_id_CableLabs,0);
688 	if (avp  && avp->data.s)
689 	{
690 		list2 = cdpb.AAAUngroupAVPS(avp->data);
691 
692 		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_CableLabs_Digest_HA1,IMS_vendor_id_CableLabs,0);
693 		if (!avp2||!avp2->data.s) {
694 			ha1->s = 0; ha1->len = 0;
695 			cdpb.AAAFreeAVPList(&list2);
696 			return 0;
697 		}
698 		*ha1 = avp2->data;
699 		cdpb.AAAFreeAVPList(&list2);
700 	}
701 
702 
703 	/* SIP Digest */
704 
705 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Digest_Authenticate,IMS_vendor_id_3GPP,0);
706 	if (avp  && avp->data.s)
707 	{
708 		list2 = cdpb.AAAUngroupAVPS(avp->data);
709 
710 		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_IMS_Digest_HA1,0,0);
711 		if (!avp2||!avp2->data.s) {
712 			ha1->s = 0; ha1->len = 0;
713 			cdpb.AAAFreeAVPList(&list2);
714 			return 0;
715 		}
716 		*ha1 = avp2->data;
717 		cdpb.AAAFreeAVPList(&list2);
718 	}
719 
720 
721 	/* AKA, MD5 */
722 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Authenticate,
723 		IMS_vendor_id_3GPP,0);
724 	if (!avp||!avp->data.s) {authenticate->s=0;authenticate->len=0;}
725 	else *authenticate = avp->data;
726 
727 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Authorization,
728 		IMS_vendor_id_3GPP,0);
729 	if (!avp||!avp->data.s) {authorization->s=0;authorization->len=0;}
730 	else *authorization = avp->data;
731 
732 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Confidentiality_Key,
733 		IMS_vendor_id_3GPP,0);
734 	if (!avp||!avp->data.s) {ck->s=0;ck->len=0;}
735 	else *ck = avp->data;
736 
737 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Integrity_Key,
738 		IMS_vendor_id_3GPP,0);
739 	if (!avp||!avp->data.s) {ik->s=0;ik->len=0;}
740 	else *ik = avp->data;
741 
742 	/* ETSI HTTP Digest */
743 
744 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_ETSI_SIP_Authenticate,IMS_vendor_id_ETSI,0);
745 	if (avp  && avp->data.s)
746 	{
747 		list2 = cdpb.AAAUngroupAVPS(avp->data);
748 
749 		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_ETSI_Digest_Realm, IMS_vendor_id_ETSI,0);
750 		if (!avp2||!avp2->data.s) {
751 			digest_realm->s=0;digest_realm->len=0;
752 			cdpb.AAAFreeAVPList(&list2);
753 			return 0;
754 		}
755 		*digest_realm = avp2->data;
756 
757 		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_ETSI_Digest_Nonce, IMS_vendor_id_ETSI,0);
758 		if (!avp2||!avp2->data.s) {
759 			authenticate->s=0;authenticate->len=0;
760 			cdpb.AAAFreeAVPList(&list2);
761 			return 0;
762 		}
763 		*authenticate = avp2->data;
764 
765 		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_ETSI_Digest_HA1, IMS_vendor_id_ETSI,0);
766 		if (!avp2||!avp2->data.s) {
767 			ha1->s = 0; ha1->len = 0;
768 			cdpb.AAAFreeAVPList(&list2);
769 			return 0;
770 		}
771 		*ha1 = avp2->data;
772 
773 		cdpb.AAAFreeAVPList(&list2);
774 	}
775 
776 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_ETSI_SIP_Authentication_Info,IMS_vendor_id_ETSI,0);
777 	if (avp  && avp->data.s)
778 	{
779 		list2 = cdpb.AAAUngroupAVPS(avp->data);
780 
781 		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_ETSI_Digest_Response_Auth, IMS_vendor_id_ETSI,0);
782 		if (!avp2||!avp2->data.s) {
783 			response_auth->s=0;response_auth->len=0;
784 			cdpb.AAAFreeAVPList(&list2);
785 			return 0;
786 		}
787 		*response_auth = avp2->data;
788 		cdpb.AAAFreeAVPList(&list2);
789 	}
790 	else
791 	{
792 		response_auth->s=0;response_auth->len=0;
793 	}
794 
795 	/* NASS Bundled */
796 	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_ETSI_Line_Identifier, IMS_vendor_id_ETSI,0);
797 	if (!avp||!avp->data.s) {line_identifier->s=0;line_identifier->len=0;}
798 	else *line_identifier = avp->data;
799 
800 	cdpb.AAAFreeAVPList(&list);
801 	return 1;
802 }
803 
804 /**
805  * Creates and adds a ETSI_sip_authorization AVP.
806  * @param username - UserName
807  * @param realm - Realm
808  * @param nonce - Nonce
809  * @param URI - URI
810  * @param response - Response
811  * @param algoritm - Algorithm
812  * @param method - Method
813  * @param hash - Enitity-Body-Hash
814  * @returns grouped str on success
815  */
cxdx_ETSI_sip_authorization(str username,str realm,str nonce,str URI,str response,str algorithm,str method,str hash)816 str cxdx_ETSI_sip_authorization(str username, str realm, str nonce, str URI, str response, str algorithm, str method, str hash)
817 {
818 	AAA_AVP_LIST list;
819 	str group = {0, 0};
820 	list.head=0;list.tail=0;
821 
822 	if (username.len){
823 		cxdx_add_avp_list(&list,
824 			username.s,username.len,
825 			AVP_ETSI_Digest_Username,
826 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
827 			IMS_vendor_id_ETSI,
828 			AVP_DONT_FREE_DATA,
829 			__FUNCTION__);
830 	}
831 
832 	if (realm.len){
833 		cxdx_add_avp_list(&list,
834 			realm.s,realm.len,
835 			AVP_ETSI_Digest_Realm,
836 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
837 			IMS_vendor_id_ETSI,
838 			AVP_DONT_FREE_DATA,
839 			__FUNCTION__);
840 	}
841 
842 	if (nonce.len){
843 		cxdx_add_avp_list(&list,
844 			nonce.s,nonce.len,
845 			AVP_ETSI_Digest_Nonce,
846 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
847 			IMS_vendor_id_ETSI,
848 			AVP_DONT_FREE_DATA,
849 			__FUNCTION__);
850 	}
851 
852 	if (URI.len){
853 		cxdx_add_avp_list(&list,
854 			URI.s,URI.len,
855 			AVP_ETSI_Digest_URI,
856 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
857 			IMS_vendor_id_ETSI,
858 			AVP_DONT_FREE_DATA,
859 			__FUNCTION__);
860 	}
861 
862 	if (response.len){
863 		cxdx_add_avp_list(&list,
864 			response.s,response.len,
865 			AVP_ETSI_Digest_Response,
866 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
867 			IMS_vendor_id_ETSI,
868 			AVP_DONT_FREE_DATA,
869 			__FUNCTION__);
870 	}
871 
872 	if (algorithm.len){
873 		cxdx_add_avp_list(&list,
874 			algorithm.s,algorithm.len,
875 			AVP_ETSI_Digest_Algorithm,
876 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
877 			IMS_vendor_id_ETSI,
878 			AVP_DONT_FREE_DATA,
879 			__FUNCTION__);
880 	}
881 
882 	if (method.len){
883 		cxdx_add_avp_list(&list,
884 			method.s,method.len,
885 			AVP_ETSI_Digest_Method,
886 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
887 			IMS_vendor_id_ETSI,
888 			AVP_DONT_FREE_DATA,
889 			__FUNCTION__);
890 	}
891 
892 	if (hash.len){
893 		cxdx_add_avp_list(&list,
894 			hash.s,hash.len,
895 			AVP_ETSI_Digest_Entity_Body_Hash,
896 			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
897 			IMS_vendor_id_ETSI,
898 			AVP_DONT_FREE_DATA,
899 			__FUNCTION__);
900 	}
901 
902 	if (!list.head) return group;
903 	group = cdpb.AAAGroupAVPS(list);
904 
905 	cdpb.AAAFreeAVPList(&list);
906 
907 	return group;
908 }
909 
910 /**
911  * Returns the User-Data from a Diameter message.
912  * @param msg - the Diameter message
913  * @returns the AVP payload on success or an empty string on error
914  */
915 
cxdx_get_user_data(AAAMessage * msg)916 str cxdx_get_user_data(AAAMessage *msg)
917 {
918 	return cxdx_get_avp(msg,
919 		AVP_IMS_User_Data_Cx,
920 		IMS_vendor_id_3GPP,
921 		__FUNCTION__);
922 }
923 
924 /**
925  * Returns the Charging-Information from a Diameter message.
926  * @param msg - the Diameter message
927  * @returns the AVP payload on success or an empty string on error
928  */
cxdx_get_charging_info(AAAMessage * msg,str * ccf1,str * ccf2,str * ecf1,str * ecf2)929 int cxdx_get_charging_info(AAAMessage *msg,str *ccf1,str *ccf2,str *ecf1,str *ecf2)
930 {
931 	AAA_AVP_LIST list;
932 	AAA_AVP *avp;
933 	str grp;
934 	grp = cxdx_get_avp(msg,
935 		AVP_IMS_Charging_Information,
936 		IMS_vendor_id_3GPP,
937 		__FUNCTION__);
938 	if (!grp.s) return 0;
939 
940 	list = cdpb.AAAUngroupAVPS(grp);
941 
942 	if (ccf1){
943 		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Primary_Charging_Collection_Function_Name,
944 			IMS_vendor_id_3GPP,0);
945 		if (avp) *ccf1 = avp->data;
946 	}
947 	if (ccf2){
948 		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Secondary_Charging_Collection_Function_Name,
949 			IMS_vendor_id_3GPP,0);
950 		if (avp) *ccf2 = avp->data;
951 	}
952 	if (ecf1){
953 		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Primary_Event_Charging_Function_Name,
954 			IMS_vendor_id_3GPP,0);
955 		if (avp) *ecf1 = avp->data;
956 	}
957 	if (ecf2){
958 		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Secondary_Event_Charging_Function_Name,
959 			IMS_vendor_id_3GPP,0);
960 		if (avp) *ecf2 = avp->data;
961 	}
962 
963 	cdpb.AAAFreeAVPList(&list);
964 	return 1;
965 
966 }
967 
968 /**
969  * Creates and adds a Server-Assignment-Type AVP.
970  * @param msg - the Diameter message to add to.
971  * @param data - the value for the AVP payload
972  * @returns 1 on success or 0 on error
973  */
cxdx_add_server_assignment_type(AAAMessage * msg,unsigned int data)974 int cxdx_add_server_assignment_type(AAAMessage *msg,unsigned int data)
975 {
976 	char x[4];
977 	set_4bytes(x,data);
978 	return
979 	cxdx_add_avp(msg,x,4,
980 		AVP_IMS_Server_Assignment_Type,
981 		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
982 		IMS_vendor_id_3GPP,
983 		AVP_DUPLICATE_DATA,
984 		__FUNCTION__);
985 }
986 
987 /**
988  * Creates and adds Userdata-Available AVP.
989  * @param msg - the Diameter message to add to.
990  * @param data - the value for the AVP payload
991  * @returns 1 on success or 0 on error
992  */
cxdx_add_userdata_available(AAAMessage * msg,unsigned int data)993 int cxdx_add_userdata_available(AAAMessage *msg,unsigned int data)
994 {
995 	char x[4];
996 	set_4bytes(x,data);
997 	return
998 	cxdx_add_avp(msg,x,4,
999 		AVP_IMS_User_Data_Already_Available,
1000 		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
1001 		IMS_vendor_id_3GPP,
1002 		AVP_DUPLICATE_DATA,
1003 		__FUNCTION__);
1004 }
1005 
1006 /**
1007  * Finds out the next Public-Identity AVP from a Diameter message.
1008  * @param msg - the Diameter message
1009  * @param pos - position to resume search or NULL if to start from the first AVP
1010  * @param avp_code - the code of the AVP to look for
1011  * @param vendor_id - the vendor id of the AVP to look for
1012  * @param func - the name of the calling function for debugging purposes
1013  * @returns the AVP payload on success or an empty string on error
1014  */
cxdx_get_next_public_identity(AAAMessage * msg,AAA_AVP * pos,int avp_code,int vendor_id,const char * func)1015 AAA_AVP* cxdx_get_next_public_identity(AAAMessage *msg,AAA_AVP* pos,int avp_code,int vendor_id,const char *func)
1016 {
1017 	AAA_AVP *avp;
1018 
1019 	avp = cdpb.AAAFindMatchingAVP(msg,pos,avp_code,vendor_id,0);
1020 	if (avp==0){
1021 		LM_DBG("INFO:%s: Failed finding avp\n",func);
1022 		return avp;
1023 	}
1024 	else
1025 		return avp;
1026 }
1027 
1028 /**
1029  * Returns the User-Name AVP from a Diameter message.
1030  * @param msg - the Diameter message
1031  * @returns the AVP payload on success or an empty string on error
1032  */
cxdx_get_user_name(AAAMessage * msg)1033 str cxdx_get_user_name(AAAMessage *msg)
1034 {
1035 	return cxdx_get_avp(msg,
1036 		AVP_User_Name,
1037 		0,
1038 		__FUNCTION__);
1039 }
1040 
1041 /**
1042  * Creates and adds a Result-Code AVP.
1043  * @param msg - the Diameter message to add to.
1044  * @param data - the value for the AVP payload
1045  * @returns 1 on success or 0 on error
1046  */
cxdx_add_result_code(AAAMessage * msg,unsigned int data)1047 int cxdx_add_result_code(AAAMessage *msg,unsigned int data)
1048 {
1049 	char x[4];
1050 	set_4bytes(x,data);
1051 	return
1052 	cxdx_add_avp(msg,x,4,
1053 		AVP_Result_Code,
1054 		AAA_AVP_FLAG_MANDATORY,
1055 		0,
1056 		AVP_DUPLICATE_DATA,
1057 		__FUNCTION__);
1058 }
1059