comparison extensions/app_radgw/rgwx_sip.c @ 361:22e7110bf46d

Initial import of SIP plugin for gateway
author Alexandre Westfahl <awestfahl@freediameter.net>
date Fri, 02 Jul 2010 12:09:18 +0900
parents
children b8ad6f9a7748
comparison
equal deleted inserted replaced
360:1740bee6c821 361:22e7110bf46d
1 /*********************************************************************************************************
2 * Software License Agreement (BSD License) *
3 * Author: Sebastien Decugis <sdecugis@nict.go.jp> *
4 * *
5 * Copyright (c) 2010, WIDE Project and NICT *
6 * All rights reserved. *
7 * *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are *
9 * permitted provided that the following conditions are met: *
10 * *
11 * * Redistributions of source code must retain the above *
12 * copyright notice, this list of conditions and the *
13 * following disclaimer. *
14 * *
15 * * Redistributions in binary form must reproduce the above *
16 * copyright notice, this list of conditions and the *
17 * following disclaimer in the documentation and/or other *
18 * materials provided with the distribution. *
19 * *
20 * * Neither the name of the WIDE Project or NICT nor the *
21 * names of its contributors may be used to endorse or *
22 * promote products derived from this software without *
23 * specific prior written permission of WIDE Project and *
24 * NICT. *
25 * *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34 *********************************************************************************************************/
35
36 /* RADIUS Access-Request messages translation plugin */
37
38 #include "rgw_common.h"
39 #include <string.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43
44 /* Other constants we use */
45 #define AI_SIP 6 /* Diameter SIP application */
46 #define CC_MULTIMEDIA_AUTH_REQUEST 286 /* MAR */
47 #define CC_MULTIMEDIA_AUTH_ANSWER 286 /* MAA */
48 #define ACV_ART_AUTHORIZE_AUTHENTICATE 3 /* AUTHORIZE_AUTHENTICATE */
49 #define ACV_OAP_RADIUS 1 /* RADIUS */
50 #define ACV_ASS_STATE_MAINTAINED 0 /* STATE_MAINTAINED */
51 #define ACV_ASS_NO_STATE_MAINTAINED 1 /* NO_STATE_MAINTAINED */
52 #define ER_DIAMETER_MULTI_ROUND_AUTH 1001
53 #define ER_DIAMETER_SUCCESS 2001
54 #define ER_DIAMETER_LIMITED_SUCCESS 2002
55 #define ER_DIAMETER_SUCCESS_AUTH_SENT_SERVER_NOT_STORED 2008
56 #define ER_DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED 2006
57
58
59
60 /* This macro converts a RADIUS attribute to a Diameter AVP of type OctetString */
61 #define CONV2DIAM_STR( _dictobj_ ) \
62 CHECK_PARAMS( attr->length >= 2 ); \
63 /* Create the AVP with the specified dictionary model */ \
64 CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) ); \
65 value.os.len = attr->length - 2; \
66 value.os.data = (unsigned char *)(attr + 1); \
67 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); \
68 /* Add the AVP in the Diameter message. */ \
69 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) ); \
70
71 #define CONV2DIAM_STR_AUTH( _dictobj_ ) \
72 CHECK_PARAMS( attr->length >= 2 ); \
73 /* Create the AVP with the specified dictionary model */ \
74 CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) ); \
75 value.os.len = attr->length - 2; \
76 value.os.data = (unsigned char *)(attr + 1); \
77 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); \
78 /* Add the AVP in the Diameter message. */ \
79 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) ); \
80
81 /* Same thing, for scalar AVPs of 32 bits */
82 #define CONV2DIAM_32B( _dictobj_ ) \
83 CHECK_PARAMS( attr->length == 6 ); \
84 CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) ); \
85 { \
86 uint8_t * v = (uint8_t *)(attr + 1); \
87 value.u32 = (v[0] << 24) \
88 | (v[1] << 16) \
89 | (v[2] << 8) \
90 | v[3] ; \
91 } \
92 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); \
93 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
94
95
96
97
98
99 /* The state we keep for this plugin */
100 struct rgwp_config {
101 struct {
102 struct dict_object * Session_Id;
103 struct dict_object * Auth_Application_Id;
104 struct dict_object * Auth_Session_State;
105 struct dict_object * Origin_Host;
106 struct dict_object * Origin_Realm;
107 struct dict_object * Destination_Realm;
108 struct dict_object * SIP_AOR;
109 struct dict_object * SIP_Method;
110 struct dict_object * Destination_Host;
111 struct dict_object * User_Name;
112 struct dict_object * SIP_Server_URI;
113 struct dict_object * SIP_Number_Auth_Items;
114 struct dict_object * SIP_Authorization;
115 struct dict_object * SIP_Authentication_Scheme;
116 struct dict_object * SIP_Authentication_Info;
117 struct dict_object * SIP_Auth_Data_Item;
118 struct dict_object * Proxy_Info;
119 struct dict_object * Route_Record;
120 struct dict_object * Service_Type;
121 struct dict_object * Result_Code;
122 struct dict_object * Digest_URI;
123 struct dict_object * Digest_Nonce;
124 struct dict_object * Digest_CNonce;
125 struct dict_object * Digest_Nonce_Count;
126 struct dict_object * Digest_Realm;
127 struct dict_object * Digest_Response;
128 struct dict_object * Digest_Method;
129 struct dict_object * Digest_Response_Auth;
130 struct dict_object * Digest_Username;
131 struct dict_object * Digest_Algorithm;
132 struct dict_object * Digest_QOP;
133
134
135
136 } dict; /* cache of the dictionary objects we use */
137 struct session_handler * sess_hdl; /* We store RADIUS request authenticator information in the session */
138 char * confstr;
139 //Global variable which points to chained list of nonce
140 struct fd_list listnonce;
141 //This will be used to lock access to chained list
142 pthread_mutex_t nonce_mutex;
143 };
144
145 typedef struct noncechain noncechain;
146 struct noncechain
147 {
148 struct fd_list chain;
149 char * sid;
150 char * nonce;
151
152 };
153
154
155
156
157
158
159 int nonce_add_element(char * nonce, char * sid, struct rgwp_config *state)
160 {
161 noncechain *newelt;
162 CHECK_MALLOC(newelt=malloc(sizeof(noncechain)));
163 int lenghtsid=strlen(sid);
164
165 CHECK_MALLOC(newelt->nonce=malloc(33));
166 memcpy(newelt->nonce,nonce,32);
167 newelt->nonce[32]='\0';
168 CHECK_MALLOC(newelt->sid=malloc(lenghtsid+1));
169 strncpy(newelt->sid,sid,lenghtsid);
170 newelt->sid[lenghtsid]='\0';
171
172 FD_LIST_INITIALIZER(&newelt->chain);
173
174 CHECK_POSIX(pthread_mutex_lock(&state->nonce_mutex));
175 fd_list_insert_before(&state->listnonce,&newelt->chain);
176 CHECK_POSIX(pthread_mutex_unlock(&state->nonce_mutex));
177 }
178
179 void nonce_del_element(char * nonce, struct rgwp_config *state)
180 {
181 if(!FD_IS_LIST_EMPTY(&state->listnonce))
182 {
183 /*
184 noncechain *temp=listnonce, *tempbefore=NULL;
185
186 if(listnonce->next==NULL && strcmp(listnonce->nonce,nonce)==0)
187 {
188 free(listnonce->nonce);
189 free(listnonce->sid);
190 free(listnonce);
191 listnonce=NULL;
192 return;
193 }
194 while(temp->next != NULL)
195 {
196 if(strcmp(temp->nonce,nonce)==0)
197 {
198 if(tempbefore==NULL)
199 {
200 listnonce=temp->next;
201 free(temp->nonce);
202 free(temp->sid);
203 free(temp);
204 return;
205 }
206 tempbefore->next=temp->next;
207 free(temp->nonce);
208 free(temp->sid);
209 free(temp);
210 break;
211 }
212 tempbefore=temp;
213 temp = temp->next;
214 }*/
215 }
216
217 }
218 //Retrieve sid from nonce
219 char * nonce_check_element(char * nonce)
220 {
221 /*
222 if(listnonce==NULL)
223 {
224 //Not found
225 return NULL;
226 }
227 else
228 {
229 noncechain* temp=listnonce;
230
231 if(strcmp(temp->nonce,nonce)==0)
232 return temp->sid;
233
234 while(temp->next != NULL)
235 {
236
237 if(strcmp(temp->nonce,nonce)==0)
238 {
239 TRACE_DEBUG(FULL,"We found the nonce!");
240 return temp->sid;
241 }
242 else
243 temp = temp->next;
244 }
245
246
247 }
248 return NULL;
249 */
250 }
251
252 void nonce_deletelistnonce()
253 {
254 /*
255 if(listnonce !=NULL)
256 {
257 while(listnonce->next != NULL)
258 {
259 noncechain* temp=listnonce->next;
260
261 free(listnonce->nonce);
262 free(listnonce->sid);
263 free(listnonce);
264
265 listnonce=temp;
266 }
267 free(listnonce->nonce);
268 free(listnonce->sid);
269 free(listnonce);
270 listnonce=NULL;
271 }
272 */
273 }
274
275 /* Initialize the plugin */
276 static int sip_conf_parse(char * conffile, struct rgwp_config ** state)
277 {
278 struct rgwp_config * new;
279 struct dict_object * app;
280
281
282 TRACE_ENTRY("%p %p", conffile, state);
283 CHECK_PARAMS( state );
284
285 CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
286 memset(new, 0, sizeof(struct rgwp_config));
287
288 CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free ) );
289 new->confstr = conffile;
290
291 /* Resolve all dictionary objects we use */
292 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &new->dict.Session_Id, ENOENT) );
293 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Application-Id", &new->dict.Auth_Application_Id, ENOENT) );
294 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Session-State", &new->dict.Auth_Session_State, ENOENT) );
295 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &new->dict.Origin_Host, ENOENT) );
296 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &new->dict.Origin_Realm, ENOENT) );
297 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &new->dict.Destination_Realm, ENOENT) );
298 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-AOR", &new->dict.SIP_AOR, ENOENT) );
299 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Method", &new->dict.SIP_Method, ENOENT) );
300 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &new->dict.Destination_Host, ENOENT) );
301 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "User-Name", &new->dict.User_Name, ENOENT) );
302 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Server-URI", &new->dict.SIP_Server_URI, ENOENT) );
303 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Number-Auth-Items", &new->dict.SIP_Number_Auth_Items, ENOENT) );
304 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Authorization", &new->dict.SIP_Authorization, ENOENT) );
305 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Auth-Data-Item", &new->dict.SIP_Auth_Data_Item, ENOENT) );
306 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Authentication-Scheme", &new->dict.SIP_Authentication_Scheme, ENOENT) );
307 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Authentication-Info", &new->dict.SIP_Authentication_Info, ENOENT) );
308 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Info", &new->dict.Proxy_Info, ENOENT) );
309 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &new->dict.Route_Record, ENOENT) );
310 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &new->dict.Result_Code, ENOENT) );
311 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-URI", &new->dict.Digest_URI, ENOENT) );
312 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Nonce", &new->dict.Digest_Nonce, ENOENT) );
313 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Method", &new->dict.Digest_Method, ENOENT) );
314 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-CNonce", &new->dict.Digest_CNonce, ENOENT) );
315 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Nonce-Count", &new->dict.Digest_Nonce_Count, ENOENT) );
316 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Realm", &new->dict.Digest_Realm, ENOENT) );
317 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Response", &new->dict.Digest_Response, ENOENT) );
318 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Response-Auth", &new->dict.Digest_Response_Auth, ENOENT) );
319 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Username", &new->dict.Digest_Username, ENOENT) );
320 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Algorithm", &new->dict.Digest_Algorithm, ENOENT) );
321 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-QoP", &new->dict.Digest_QOP, ENOENT) );
322
323
324
325 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Session Initiation Protocol (SIP) Application", &app, ENOENT) );
326 CHECK_FCT( fd_disp_app_support ( app, NULL, 1, 0 ) );
327
328 //chained list
329 FD_LIST_INITIALIZER(&new->listnonce);
330 CHECK_POSIX(pthread_mutex_init(&new->nonce_mutex,NULL));
331
332 *state = new;
333 return 0;
334 }
335
336 /* deinitialize */
337 static void sip_conf_free(struct rgwp_config * state)
338 {
339 TRACE_ENTRY("%p", state);
340 CHECK_PARAMS_DO( state, return );
341
342 CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl ), );
343
344 nonce_deletelistnonce(&state->listnonce);
345 CHECK_POSIX_DO(pthread_mutex_destroy(&state->nonce_mutex), /*continue*/);
346
347 free(state);
348 return;
349 }
350
351
352 /* Handle an incoming RADIUS request */
353 static int sip_rad_req( struct rgwp_config * cs, struct session ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
354 {
355 int idx;
356 int got_username = 0;
357 int got_AOR = 0;
358 int got_Dusername = 0;
359 int got_Drealm = 0;
360 int got_Duri = 0;
361 int got_Dmethod = 0;
362 int got_Dqop = 0;
363 int got_Dnonce_count = 0;
364 int got_Dnonce = 0;
365 int got_Dcnonce = 0;
366 int got_Dresponse = 0;
367 int got_Dalgorithm = 0;
368
369 uint32_t status_type;
370 size_t nattr_used = 0;
371 struct avp *auth_data=NULL, *auth=NULL, *avp = NULL;
372 union avp_value value;
373
374 TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
375
376 CHECK_PARAMS(rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCESS_REQUEST) && rad_ans && diam_fw && *diam_fw);
377
378 //We check that session is not already filled
379 if(*session)
380 {
381 TRACE_DEBUG(INFO,"We are not supposed to receive a session in radSIP plugin.");
382 return EINVAL;
383 }
384
385 /*
386 RFC5090 RADIUS Extension Digest Application
387 */
388
389 /* Check basic information is there */
390 for (idx = 0; idx < rad_req->attr_used; idx++) {
391 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
392
393
394 switch (attr->type) {
395
396 case RADIUS_ATTR_USER_NAME:
397 got_username = 1;
398 break;
399 case RADIUS_ATTR_DIGEST_USERNAME:
400 got_Dusername = 1;
401 break;
402 case RADIUS_ATTR_DIGEST_REALM:
403 got_Drealm = 1;
404 break;
405 case RADIUS_ATTR_DIGEST_URI:
406 got_Duri = 1;
407 break;
408 case RADIUS_ATTR_DIGEST_METHOD:
409 got_Dmethod = 1;
410 break;
411 case RADIUS_ATTR_DIGEST_QOP:
412 got_Dqop = 1;
413 break;
414 case RADIUS_ATTR_DIGEST_NONCE_COUNT:
415 got_Dnonce_count = 1;
416 break;
417 case RADIUS_ATTR_DIGEST_NONCE:
418 got_Dnonce = 1;
419 break;
420 case RADIUS_ATTR_DIGEST_CNONCE:
421 got_Dcnonce = 1;
422 break;
423 case RADIUS_ATTR_DIGEST_RESPONSE:
424 got_Dresponse = 1;
425 break;
426 case RADIUS_ATTR_DIGEST_ALGORITHM:
427 got_Dalgorithm = 1;
428 break;
429 case RADIUS_ATTR_SIP_AOR:
430 got_AOR = 1;
431 break;
432 }
433 }
434 if(!got_username)
435 {
436 TRACE_DEBUG(INFO,"No Username in request");
437 return 1;
438 }
439 if(!got_Dnonce)
440 {
441 /* Add the Session-Id AVP as first AVP */
442 CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
443
444 char *sid=NULL;
445 fd_sess_getsid (session, &sid );
446 memset(&value, 0, sizeof(value));
447 value.os.data = (unsigned char *)sid;
448 value.os.len = strlen(sid);
449 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
450 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
451 }
452 /*
453 If the RADIUS Access-Request message does not
454 contain any Digest-* attribute, then the RADIUS client does not want
455 to apply HTTP Digest authentication, in which case, actions at the
456 gateway are outside the scope of this document.
457 */
458
459 if(!(got_Dmethod && got_Duri))
460 {
461 TRACE_DEBUG(INFO,"No Digest attributes in request, we drop it...");
462 return 1;
463 }
464
465 /* Add the appropriate command code & Auth-Application-Id */
466 {
467 struct msg_hdr * header = NULL;
468 CHECK_FCT( fd_msg_hdr ( *diam_fw, &header ) );
469 header->msg_flags = CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE;
470 header->msg_code = CC_MULTIMEDIA_AUTH_REQUEST;
471 header->msg_appl = AI_SIP;
472
473
474 /* Add the Auth-Application-Id */
475 {
476 CHECK_FCT( fd_msg_avp_new ( cs->dict.Auth_Application_Id, 0, &avp ) );
477 value.i32 = header->msg_appl;
478 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
479 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
480 }
481 }
482 /*Add Auth_Session_State AVP */
483 {
484 CHECK_FCT( fd_msg_avp_new ( cs->dict.Auth_Session_State, 0, &avp ) );
485 value.i32 = ACV_ASS_NO_STATE_MAINTAINED;
486 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
487 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
488 }
489
490
491 /*Add SIP_Number_Auth_Items AVP */
492 {
493 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Number_Auth_Items, 0, &avp ) );
494 value.i32 = 1; //We just treat one auth per request in gateway
495 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
496 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
497 }
498
499 /* Add SIP_Auth_Data_Item AVP */
500 {
501 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Auth_Data_Item, 0, &auth_data ) );
502 }
503 /* Add SIP_Authentication_Scheme AVP */
504 {
505 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Authentication_Scheme, 0, &avp ) );
506 value.i32=0; //There is only Digest Auth in RFC for now
507 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
508 CHECK_FCT( fd_msg_avp_add ( auth_data, MSG_BRW_LAST_CHILD, avp) );
509
510 }
511
512
513 /* Add SIP_Authorization AVP */
514 {
515 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Authorization, 0, &auth ) );
516 CHECK_FCT( fd_msg_avp_add ( auth_data, MSG_BRW_LAST_CHILD, auth) );
517 }
518 char * temp=NULL,*sipuri=NULL;
519
520 for (idx = 0; idx < rad_req->attr_used; idx++)
521 {
522 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
523
524 switch (attr->type) {
525
526 case RADIUS_ATTR_USER_NAME:
527 CONV2DIAM_STR( User_Name );
528
529 if(!got_Dusername)
530 {
531 CONV2DIAM_STR_AUTH(Digest_Username);
532 got_Dusername=1;
533 }
534
535 break;
536
537 case RADIUS_ATTR_DIGEST_URI:
538
539 CONV2DIAM_STR_AUTH(Digest_URI);
540
541 //All of these attributes are required by Diameter but not defined in RFC5090 so we provide FAKE values (only in first exchange)
542 if(!got_AOR)
543 {
544 CONV2DIAM_STR( SIP_AOR );
545 got_AOR=1;
546 }
547 /*
548 We must provide a fake nonce because of RFC4740 problem
549 TODO: remove when RFC is updated
550 ==START of FAKE
551 */
552 if(!got_Dresponse)
553 {
554 CONV2DIAM_STR_AUTH(Digest_Response);
555 got_Dresponse=1;
556 }
557 /*
558 ==END of FAKE
559 */
560 if(!got_Drealm)
561 {
562 //We extract Realm from Digest_URI
563 char *realm=NULL;
564
565 CHECK_MALLOC(temp=malloc(attr->length -1));
566 strncpy(temp, (char *)(attr + 1), attr->length -2);
567 temp[attr->length-2] = '\0';
568
569 realm = strtok( (char *)(temp), "@" );
570 realm = strtok( NULL, "@" );
571 free(temp);
572 temp=NULL;
573 if(realm!=NULL)
574 {
575 CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Realm, 0, &avp ) );
576 value.os.data=(unsigned char *)realm;
577 value.os.len=strlen(realm);
578 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
579 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );
580
581 //We add SIP-Server-URI AVP because SIP server is registrar (through gateway)
582 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Server_URI, 0, &avp ) );
583 value.os.data=(unsigned char *)realm;
584 value.os.len=strlen(realm);
585 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
586 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
587
588 }
589 else
590 {
591 TRACE_DEBUG(INFO, "Can't extract domain from URI, droping request...");
592 return 1;
593 }
594 got_Drealm=1;
595 }
596 break;
597
598 case RADIUS_ATTR_DIGEST_METHOD:
599 CONV2DIAM_STR(SIP_Method);
600 CONV2DIAM_STR_AUTH(Digest_Method);
601 break;
602 case RADIUS_ATTR_DIGEST_REALM:
603 CONV2DIAM_STR_AUTH(Digest_Realm);
604
605 //We add SIP-Server-URI AVP because SIP server is registrar (through gateway)
606 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Server_URI, 0, &avp ) );
607
608
609 CHECK_MALLOC(temp=malloc(attr->length -1));
610 strncpy(temp, (char *)(attr + 1), attr->length -2);
611
612
613 CHECK_MALLOC(sipuri=malloc(attr->length +3));
614 strcpy(sipuri,"sip:");
615 strcat(sipuri,(unsigned char *)temp);
616 value.os.data=(unsigned char *)sipuri;
617 value.os.len=attr->length +2;
618
619 free(temp);
620 temp=NULL;
621 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
622 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
623 break;
624
625 case RADIUS_ATTR_DIGEST_USERNAME:
626 CONV2DIAM_STR_AUTH(Digest_Username);
627 break;
628
629 case RADIUS_ATTR_DIGEST_QOP:
630 CONV2DIAM_STR_AUTH( Digest_QOP );
631 break;
632 case RADIUS_ATTR_DIGEST_ALGORITHM:
633 CONV2DIAM_STR_AUTH( Digest_Algorithm );
634 break;
635 case RADIUS_ATTR_DIGEST_CNONCE:
636 CONV2DIAM_STR_AUTH( Digest_CNonce );
637 break;
638 case RADIUS_ATTR_DIGEST_NONCE:
639 CONV2DIAM_STR_AUTH( Digest_Nonce );
640
641
642 int new=0;
643 int sidlen=0;
644 struct session * temp;
645 char *nonce=malloc(attr->length-1);
646 char *sid=malloc(sidlen+1);
647
648 strncpy(nonce,(char *)(attr+1), attr->length-2);
649 nonce[attr->length-2]='\0';
650
651 //**Start mutex
652 pthread_mutex_lock(&state->nonce_mutex);
653 sidlen=strlen(nonce_check_element(nonce));
654 strcpy(sid,nonce_check_element(nonce));
655 sid[sidlen+1]='\0';
656 nonce_del_element(nonce);
657 free(nonce); //TODO: free nonce inside delete
658 pthread_mutex_unlock(&state->nonce_mutex);
659 //**Stop mutex
660
661 CHECK_FCT(fd_sess_fromsid ( (char *)sid, (size_t)sidlen, &temp, &new));
662 //free(sid);
663
664 if(new==0)
665 {
666 session=temp;
667 /* Add the Session-Id AVP as first AVP */
668 CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
669 //memset(&value, 0, sizeof(value));
670 value.os.data = (unsigned char *)sid;
671 value.os.len = sidlen;
672 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
673 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
674
675 }
676 else
677 {
678 TRACE_DEBUG(INFO,"Can't find previously established session, message droped!");
679 return 1;
680 }
681 //free(sid);
682 free(nonce);
683 //fd_sess_dump(FULL,session);
684
685
686
687 break;
688 case RADIUS_ATTR_DIGEST_NONCE_COUNT:
689 CONV2DIAM_STR_AUTH( Digest_Nonce_Count );
690 break;
691 case RADIUS_ATTR_DIGEST_RESPONSE:
692 CONV2DIAM_STR_AUTH( Digest_Response );
693 break;
694 case RADIUS_ATTR_SIP_AOR:
695 CONV2DIAM_STR( SIP_AOR );
696 break;
697
698 default:
699 if(!got_Dalgorithm)
700 {
701 //[Note 3] If Digest-Algorithm is missing, 'MD5' is assumed.
702
703 CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Algorithm, 0, &avp ) );
704 value.os.len = 3;
705 value.os.data = "MD5";
706 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
707 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );
708 got_Dalgorithm=1;
709 }
710
711 if(!got_Dnonce)
712 {
713 //We give a fake nonce because it will be calculated at the server.
714 CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Nonce, 0, &avp ) );
715 value.os.data="nonce";
716 value.os.len=5;
717 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
718 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );
719 got_Dnonce=1;
720 }
721 break;
722
723 }
724 }
725
726
727 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, auth_data) );
728
729 /* Update the radius message to remove all handled attributes */
730 rad_req->attr_used = nattr_used;
731
732 //fd_msg_dump_walk(1,*diam_fw);
733
734 /* Store the request identifier in the session (if provided) */
735
736
737 if (session) {
738 unsigned char * req_sip;
739 CHECK_MALLOC(req_sip = malloc(16));
740 memcpy(req_sip, &rad_req->hdr->authenticator[0], 16);
741
742 CHECK_FCT( fd_sess_state_store( cs->sess_hdl, session, &req_sip ) );
743 }
744
745
746 return 0;
747 }
748
749 static int sip_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli, int * statefull )
750 {
751
752 struct msg_hdr * hdr;
753 struct avp *avp, *next, *asid;
754 struct avp_hdr *ahdr, *sid, *oh;
755 char buf[254]; /* to store some attributes values (with final '\0') */
756 int ta_set = 0;
757 int no_str = 0; /* indicate if an STR is required for this server */
758 uint8_t tuntag = 0;
759 unsigned char * req_sip = NULL;
760 int in_success=0;
761
762 TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
763 CHECK_PARAMS(cs && session && diam_ans && *diam_ans && rad_fw && *rad_fw);
764
765
766
767
768
769 /* MACROS to help in the process: convert AVP data to RADIUS attributes. */
770 /* Control large attributes: _trunc_ = 0 => error; _trunc_ = 1 => truncate; _trunc = 2 => create several attributes */
771 #define CONV2RAD_STR( _attr_, _data_, _len_, _trunc_) { \
772 size_t __l = (size_t)(_len_); \
773 size_t __off = 0; \
774 TRACE_DEBUG(FULL, "Converting AVP to "#_attr_); \
775 if ((_trunc_) == 0) { \
776 CHECK_PARAMS( __l <= 253 ); \
777 } \
778 if ((__l > 253) && (_trunc_ == 1)) { \
779 TRACE_DEBUG(INFO, "[authSIP.rgwx] AVP truncated in "#_attr_); \
780 __l = 253; \
781 } \
782 do { \
783 size_t __w = (__l > 253) ? 253 : __l; \
784 CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (_data_) + __off, __w)); \
785 __off += __w; \
786 __l -= __w; \
787 } while (__l); \
788 }
789
790 #define CONV2RAD_32B( _attr_, _data_) { \
791 uint32_t __v = htonl((uint32_t)(_data_)); \
792 TRACE_DEBUG(FULL, "Converting AVP to "#_attr_); \
793 CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (uint8_t *)&__v, sizeof(__v))); \
794 }
795
796
797 /* Search the different AVPs we handle here */
798 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Session_Id, &asid) );
799 CHECK_FCT( fd_msg_avp_hdr ( asid, &sid ) );
800 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Host, &asid) );
801 CHECK_FCT( fd_msg_avp_hdr ( asid, &oh ) );
802
803 /* Check the Diameter error code */
804 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Result_Code, &avp) );
805 ASSERT( avp ); /* otherwise the message should have been discarded a lot earlier because of ABNF */
806 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
807 switch (ahdr->avp_value->u32) {
808 case ER_DIAMETER_MULTI_ROUND_AUTH:
809 case ER_DIAMETER_SUCCESS_AUTH_SENT_SERVER_NOT_STORED:
810 (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_CHALLENGE;
811 *statefull=1;
812 struct timespec nowts;
813 CHECK_SYS(clock_gettime(CLOCK_REALTIME, &nowts));
814 nowts.tv_sec+=600;
815 CHECK_FCT(fd_sess_settimeout(session, &nowts ));
816 break;
817 case ER_DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED:
818 case ER_DIAMETER_SUCCESS:
819 (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_ACCEPT;
820 in_success=1;
821 break;
822
823 default:
824 (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_REJECT;
825 fd_log_debug("[authSIP.rgwx] Received Diameter answer with error code '%d' from server '%.*s', session %.*s, translating into Access-Reject\n",
826 ahdr->avp_value->u32,
827 oh->avp_value->os.len, oh->avp_value->os.data,
828 sid->avp_value->os.len, sid->avp_value->os.data);
829 return 0;
830 }
831 /* Remove this Result-Code avp */
832 CHECK_FCT( fd_msg_free( avp ) );
833
834 /* Creation of the State or Class attribute with session information */
835 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Realm, &avp) );
836 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
837
838
839 /* Now, save the session-id and eventually server info in a STATE or CLASS attribute */
840 if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE) {
841 if (sizeof(buf) < snprintf(buf, sizeof(buf), "Diameter/%.*s/%.*s/%.*s",
842 oh->avp_value->os.len, oh->avp_value->os.data,
843 ahdr->avp_value->os.len, ahdr->avp_value->os.data,
844 sid->avp_value->os.len, sid->avp_value->os.data)) {
845 TRACE_DEBUG(INFO, "Data truncated in State attribute: %s", buf);
846 }
847 CONV2RAD_STR(RADIUS_ATTR_STATE, buf, strlen(buf), 0);
848
849 }
850
851 if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
852 /* Add the Session-Id */
853 if (sizeof(buf) < snprintf(buf, sizeof(buf), "Diameter/%.*s",
854 sid->avp_value->os.len, sid->avp_value->os.data)) {
855 TRACE_DEBUG(INFO, "Data truncated in Class attribute: %s", buf);
856 }
857 CONV2RAD_STR(RADIUS_ATTR_CLASS, buf, strlen(buf), 0);
858 }
859
860 /* Unlink the Origin-Realm now; the others are unlinked at the end of this function */
861 CHECK_FCT( fd_msg_free( avp ) );
862
863
864
865 /* Now loop in the list of AVPs and convert those that we know how */
866 CHECK_FCT( fd_msg_browse(*diam_ans, MSG_BRW_FIRST_CHILD, &next, NULL) );
867
868 while (next) {
869 int handled = 1;
870 avp = next;
871 CHECK_FCT( fd_msg_browse(avp, MSG_BRW_WALK, &next, NULL) );
872
873 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
874
875 if (!(ahdr->avp_flags & AVP_FLAG_VENDOR)) {
876 switch (ahdr->avp_code) {
877
878 case DIAM_ATTR_AUTH_SESSION_STATE:
879 if ((!ta_set) && (ahdr->avp_value->u32 == ACV_ASS_STATE_MAINTAINED)) {
880 CONV2RAD_32B( RADIUS_ATTR_TERMINATION_ACTION, RADIUS_TERMINATION_ACTION_RADIUS_REQUEST );
881 }
882
883 if (ahdr->avp_value->u32 == ACV_ASS_NO_STATE_MAINTAINED) {
884 no_str = 1;
885 }
886 break;
887 case DIAM_ATTR_DIGEST_NONCE:
888 CONV2RAD_STR(DIAM_ATTR_DIGEST_NONCE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
889 /* Retrieve the request identified which was stored in the session */
890 if (session) {
891 char *sid=NULL;
892
893 fd_sess_getsid (session, &sid );
894
895 //***Start mutex
896 CHECK_POSIX(pthread_mutex_lock(&state->nonce_mutex));
897 nonce_add_element(ahdr->avp_value->os.data, sid, state);
898 CHECK_POSIX(pthread_mutex_unlock(&state->nonce_mutex));
899 //***Stop mutex
900 }
901 break;
902 case DIAM_ATTR_DIGEST_REALM:
903 CONV2RAD_STR(DIAM_ATTR_DIGEST_REALM, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
904 break;
905 case DIAM_ATTR_DIGEST_QOP:
906 CONV2RAD_STR(DIAM_ATTR_DIGEST_QOP, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
907 break;
908 case DIAM_ATTR_DIGEST_ALGORITHM:
909 CONV2RAD_STR(DIAM_ATTR_DIGEST_ALGORITHM, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
910 break;
911 case DIAM_ATTR_DIGEST_RESPONSE_AUTH:
912 CONV2RAD_STR(DIAM_ATTR_DIGEST_RESPONSE_AUTH, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
913 break;
914 }
915 }
916 else
917 {
918 /* Vendor-specific AVPs */
919 switch (ahdr->avp_vendor) {
920
921 default: /* unknown vendor */
922 handled = 0;
923 }
924 }
925
926
927 if (session)
928 {
929 CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, session, &req_sip ) );
930 }
931 }
932
933 req_sip=NULL;
934
935 return 0;
936 }
937
938 /* The exported symbol */
939 struct rgw_api rgwp_descriptor = {
940 .rgwp_name = "sip",
941 .rgwp_conf_parse = sip_conf_parse,
942 .rgwp_conf_free = sip_conf_free,
943 .rgwp_rad_req = sip_rad_req,
944 .rgwp_diam_ans = sip_diam_ans
945
946 };
947 /*}
948 /* Add FAKE Digest_Realm AVP
949 {
950 //We give a fake realm because it will be provided in the second access request.
951 CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Realm, 0, &avp ) );
952
953 u8 *realm="example.com";
954
955 value.os.data=(unsigned char *)realm;
956 value.os.len=strlen(realm);
957 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
958 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );
959
960 }
961 else
962 {
963 TRACE_DEBUG(FULL,"\nAnswer to challenge!\n");
964 //We need a client nonce, count nonce, digest realm, username and response to handle authentication
965 if (got_Dnonce_count && got_Dcnonce && got_Dresponse && got_Drealm && got_Dusername)
966 {
967 /* Add SIP_Authorization AVP
968 {
969 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Authorization, 0, &auth ) );
970 CHECK_FCT( fd_msg_avp_add ( auth_data, MSG_BRW_LAST_CHILD, auth) );
971 }
972 for (idx = 0; idx < rad_req->attr_used; idx++)
973 {
974 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
975 char * temp;
976
977 switch (attr->type) {
978
979
980 default:
981
982 if(!got_Dalgorithm)
983 {
984 //[Note 3] If Digest-Algorithm is missing, 'MD5' is assumed.
985
986 CHECK_PARAMS( attr->length >= 2 );
987 CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Algorithm, 0, &avp ) );
988 value.os.len = attr->length - 2;
989 value.os.data = (unsigned char *)(attr + 1);
990 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
991 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );
992 }
993
994 }
995
996 }
997 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, auth_data) );
998
999 }
1000 else
1001 {
1002 TRACE_DEBUG(INFO,"Missing Digest attributes in request, we drop it...");
1003 return 1;
1004 }
1005 }*/
1006
"Welcome to our mercurial repository"