comparison extensions/app_radgw/rgwx_sip.c @ 368:a1f26147ec61

Corrected bugs on app_sip and rgwx_sip
author Alexandre Westfahl <awestfahl@freediameter.net>
date Sat, 03 Jul 2010 00:40:00 +0900
parents b8ad6f9a7748
children 350e1cca3782
comparison
equal deleted inserted replaced
367:a2c268b2d8fe 368:a1f26147ec61
46 46
47 /* Other constants we use */ 47 /* Other constants we use */
48 #define AI_SIP 6 /* Diameter SIP application */ 48 #define AI_SIP 6 /* Diameter SIP application */
49 #define CC_MULTIMEDIA_AUTH_REQUEST 286 /* MAR */ 49 #define CC_MULTIMEDIA_AUTH_REQUEST 286 /* MAR */
50 #define CC_MULTIMEDIA_AUTH_ANSWER 286 /* MAA */ 50 #define CC_MULTIMEDIA_AUTH_ANSWER 286 /* MAA */
51 #define ACV_ART_AUTHORIZE_AUTHENTICATE 3 /* AUTHORIZE_AUTHENTICATE */
52 #define ACV_OAP_RADIUS 1 /* RADIUS */
53 #define ACV_ASS_STATE_MAINTAINED 0 /* STATE_MAINTAINED */ 51 #define ACV_ASS_STATE_MAINTAINED 0 /* STATE_MAINTAINED */
54 #define ACV_ASS_NO_STATE_MAINTAINED 1 /* NO_STATE_MAINTAINED */ 52 #define ACV_ASS_NO_STATE_MAINTAINED 1 /* NO_STATE_MAINTAINED */
55 #define ER_DIAMETER_MULTI_ROUND_AUTH 1001 53 #define ER_DIAMETER_MULTI_ROUND_AUTH 1001
56 #define ER_DIAMETER_SUCCESS 2001 54 #define ER_DIAMETER_SUCCESS 2001
57 #define ER_DIAMETER_LIMITED_SUCCESS 2002 55 #define ER_DIAMETER_LIMITED_SUCCESS 2002
137 135
138 136
139 } dict; /* cache of the dictionary objects we use */ 137 } dict; /* cache of the dictionary objects we use */
140 struct session_handler * sess_hdl; /* We store RADIUS request authenticator information in the session */ 138 struct session_handler * sess_hdl; /* We store RADIUS request authenticator information in the session */
141 char * confstr; 139 char * confstr;
142 //Global variable which points to chained list of nonce 140 //Chained list of nonce
143 struct fd_list listnonce; 141 struct fd_list listnonce;
144 //This will be used to lock access to chained list 142 //This will be used to lock access to chained list
145 pthread_mutex_t nonce_mutex; 143 pthread_mutex_t nonce_mutex;
146 }; 144 };
147 145
148 typedef struct noncechain noncechain; 146 typedef struct noncechain noncechain;
149 struct noncechain 147 struct noncechain
150 { 148 {
151 struct fd_list chain; 149 struct fd_list chain;
152 char * sid; 150 char * sid;
151 size_t sidlen;
153 char * nonce; 152 char * nonce;
153 size_t noncelen;
154 154
155 }; 155 };
156 156
157 157 static int nonce_add_element(char * nonce, size_t noncelen,char * sid, size_t sidlen, struct rgwp_config * state)
158
159
160
161
162 int nonce_add_element(char * nonce, char * sid, struct rgwp_config *state)
163 { 158 {
159 CHECK_PARAMS(nonce && state && sid && sidlen && noncelen);
160
164 noncechain *newelt; 161 noncechain *newelt;
165 CHECK_MALLOC(newelt=malloc(sizeof(noncechain))); 162 CHECK_MALLOC(newelt=malloc(sizeof(noncechain)));
166 int lenghtsid=strlen(sid); 163
167 164 CHECK_MALLOC(newelt->nonce=malloc(noncelen));
168 CHECK_MALLOC(newelt->nonce=malloc(33)); 165 memcpy(newelt->nonce,nonce,noncelen);
169 memcpy(newelt->nonce,nonce,32); 166 newelt->noncelen=noncelen;
170 newelt->nonce[32]='\0'; 167
171 CHECK_MALLOC(newelt->sid=malloc(lenghtsid+1)); 168 CHECK_MALLOC(newelt->sid=malloc(sidlen));
172 strncpy(newelt->sid,sid,lenghtsid); 169 memcpy(newelt->sid,sid,sidlen);
173 newelt->sid[lenghtsid]='\0'; 170 newelt->sidlen=sidlen;
174 171
175 FD_LIST_INITIALIZER(&newelt->chain); 172 fd_list_init(&newelt->chain,NULL);
176 173
177 CHECK_POSIX(pthread_mutex_lock(&state->nonce_mutex)); 174 CHECK_POSIX(pthread_mutex_lock(&state->nonce_mutex));
178 fd_list_insert_before(&state->listnonce,&newelt->chain); 175 fd_list_insert_before(&state->listnonce,&newelt->chain);
179 CHECK_POSIX(pthread_mutex_unlock(&state->nonce_mutex)); 176 CHECK_POSIX(pthread_mutex_unlock(&state->nonce_mutex));
177
178 return 0;
180 } 179 }
181 180
182 void nonce_del_element(char * nonce, struct rgwp_config *state) 181 static void nonce_del_element(char * nonce, struct rgwp_config *state)
183 { 182 {
184 if(!FD_IS_LIST_EMPTY(&state->listnonce)) 183 struct fd_list * li;
185 { 184
186 /* 185 CHECK_PARAMS_DO(nonce && state, return);
187 noncechain *temp=listnonce, *tempbefore=NULL; 186
188 187 for(li=state->listnonce.next;li!=&state->listnonce;li=li->next)
189 if(listnonce->next==NULL && strcmp(listnonce->nonce,nonce)==0) 188 {
189 noncechain *temp=(noncechain *)li;
190
191 if(strcmp(temp->nonce,nonce)==0)
190 { 192 {
191 free(listnonce->nonce); 193 fd_list_unlink (li);
192 free(listnonce->sid); 194 free(temp->sid);
193 free(listnonce); 195 free(temp->nonce);
194 listnonce=NULL; 196 free(temp);
195 return; 197 break;
196 } 198 }
197 while(temp->next != NULL) 199 }
200 }
201
202 //Retrieve sid from nonce
203 static char * nonce_get_sid(char * nonce, size_t noncelen, size_t * sidlen, struct rgwp_config *state)
204 {
205 struct fd_list * li;
206 char *sid=NULL;
207
208 CHECK_PARAMS_DO(nonce && state && noncelen && sidlen, return);
209 *sidlen=0;
210
211 //**Start mutex
212 CHECK_POSIX_DO(pthread_mutex_lock(&state->nonce_mutex),);
213 for(li=state->listnonce.next;li!=&state->listnonce;li=li->next)
214 {
215 noncechain *temp=(noncechain *)li;
216
217 if(temp->noncelen==noncelen && strncmp(temp->nonce,nonce, noncelen)==0)
198 { 218 {
199 if(strcmp(temp->nonce,nonce)==0) 219 fd_list_unlink (li);
200 { 220 sid=temp->sid;
201 if(tempbefore==NULL) 221 *sidlen=temp->sidlen;
202 { 222 free(temp->nonce);
203 listnonce=temp->next; 223 free(temp);
204 free(temp->nonce); 224 break;
205 free(temp->sid); 225 }
206 free(temp); 226
207 return; 227 }
208 } 228 CHECK_POSIX_DO(pthread_mutex_unlock(&state->nonce_mutex),);
209 tempbefore->next=temp->next; 229 //***Stop mutex
210 free(temp->nonce); 230 return sid;
211 free(temp->sid);
212 free(temp);
213 break;
214 }
215 tempbefore=temp;
216 temp = temp->next;
217 }*/
218 }
219
220 } 231 }
221 //Retrieve sid from nonce 232
222 char * nonce_check_element(char * nonce) 233 static void nonce_deletelistnonce(struct rgwp_config *state)
223 { 234 {
224 /* 235 //**Start mutex
225 if(listnonce==NULL) 236 CHECK_POSIX_DO(pthread_mutex_lock(&state->nonce_mutex),);
226 { 237 while(!(FD_IS_LIST_EMPTY(&state->listnonce)) )
227 //Not found 238 {
228 return NULL; 239 noncechain *temp=(noncechain *)state->listnonce.next;
229 } 240
230 else 241 fd_list_unlink (&temp->chain);
231 { 242 free(temp->sid);
232 noncechain* temp=listnonce; 243 free(temp->nonce);
233 244 free(temp);
234 if(strcmp(temp->nonce,nonce)==0) 245
235 return temp->sid; 246 }
236 247 CHECK_POSIX_DO(pthread_mutex_unlock(&state->nonce_mutex),);
237 while(temp->next != NULL) 248 //***Stop mutex
238 {
239
240 if(strcmp(temp->nonce,nonce)==0)
241 {
242 TRACE_DEBUG(FULL,"We found the nonce!");
243 return temp->sid;
244 }
245 else
246 temp = temp->next;
247 }
248
249
250 }
251 return NULL;
252 */
253 }
254
255 void nonce_deletelistnonce()
256 {
257 /*
258 if(listnonce !=NULL)
259 {
260 while(listnonce->next != NULL)
261 {
262 noncechain* temp=listnonce->next;
263
264 free(listnonce->nonce);
265 free(listnonce->sid);
266 free(listnonce);
267
268 listnonce=temp;
269 }
270 free(listnonce->nonce);
271 free(listnonce->sid);
272 free(listnonce);
273 listnonce=NULL;
274 }
275 */
276 } 249 }
277 250
278 /* Initialize the plugin */ 251 /* Initialize the plugin */
279 static int sip_conf_parse(char * conffile, struct rgwp_config ** state) 252 static int sip_conf_parse(char * conffile, struct rgwp_config ** state)
280 { 253 {
327 300
328 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Session Initiation Protocol (SIP) Application", &app, ENOENT) ); 301 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Session Initiation Protocol (SIP) Application", &app, ENOENT) );
329 CHECK_FCT( fd_disp_app_support ( app, NULL, 1, 0 ) ); 302 CHECK_FCT( fd_disp_app_support ( app, NULL, 1, 0 ) );
330 303
331 //chained list 304 //chained list
332 FD_LIST_INITIALIZER(&new->listnonce); 305 fd_list_init(&new->listnonce,NULL);
333 CHECK_POSIX(pthread_mutex_init(&new->nonce_mutex,NULL)); 306 CHECK_POSIX(pthread_mutex_init(&new->nonce_mutex,NULL));
334 307
335 *state = new; 308 *state = new;
336 return 0; 309 return 0;
337 } 310 }
342 TRACE_ENTRY("%p", state); 315 TRACE_ENTRY("%p", state);
343 CHECK_PARAMS_DO( state, return ); 316 CHECK_PARAMS_DO( state, return );
344 317
345 CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl ), ); 318 CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl ), );
346 319
347 nonce_deletelistnonce(&state->listnonce); 320 nonce_deletelistnonce(state);
348 CHECK_POSIX_DO(pthread_mutex_destroy(&state->nonce_mutex), /*continue*/); 321 CHECK_POSIX_DO(pthread_mutex_destroy(&state->nonce_mutex), /*continue*/);
349 322
350 free(state); 323 free(state);
351 return; 324 return;
352 } 325 }
354 327
355 /* Handle an incoming RADIUS request */ 328 /* Handle an incoming RADIUS request */
356 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 ) 329 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 )
357 { 330 {
358 int idx; 331 int idx;
359 int got_username = 0;
360 int got_AOR = 0; 332 int got_AOR = 0;
361 int got_Dusername = 0; 333 int got_Dusername = 0;
362 int got_Drealm = 0; 334 int got_Drealm = 0;
363 int got_Duri = 0; 335 int got_Duri = 0;
364 int got_Dmethod = 0; 336 int got_Dmethod = 0;
366 int got_Dnonce_count = 0; 338 int got_Dnonce_count = 0;
367 int got_Dnonce = 0; 339 int got_Dnonce = 0;
368 int got_Dcnonce = 0; 340 int got_Dcnonce = 0;
369 int got_Dresponse = 0; 341 int got_Dresponse = 0;
370 int got_Dalgorithm = 0; 342 int got_Dalgorithm = 0;
371 343 char * sid = NULL;
344 char * un=NULL;
345 size_t un_len;
372 uint32_t status_type; 346 uint32_t status_type;
373 size_t nattr_used = 0; 347 size_t nattr_used = 0;
374 struct avp *auth_data=NULL, *auth=NULL, *avp = NULL; 348 struct avp *auth_data=NULL, *auth=NULL, *avp = NULL;
375 union avp_value value; 349 union avp_value value;
376 350
377 TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli); 351 TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
378 352
379 CHECK_PARAMS(rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCESS_REQUEST) && rad_ans && diam_fw && *diam_fw); 353 CHECK_PARAMS(rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCESS_REQUEST) && rad_ans && diam_fw && *diam_fw && session);
380 354
381 //We check that session is not already filled 355 //We check that session is not already filled
382 if(*session) 356 if(*session)
383 { 357 {
384 TRACE_DEBUG(INFO,"We are not supposed to receive a session in radSIP plugin."); 358 TRACE_DEBUG(INFO,"We are not supposed to receive a session in radSIP plugin.");
395 369
396 370
397 switch (attr->type) { 371 switch (attr->type) {
398 372
399 case RADIUS_ATTR_USER_NAME: 373 case RADIUS_ATTR_USER_NAME:
400 got_username = 1; 374 if (attr->length>sizeof(struct radius_attr_hdr))
375 {
376 TRACE_DEBUG(ANNOYING, "Found a User-Name attribute: '%.*s'", attr->length- sizeof(struct radius_attr_hdr), (char *)(attr+1));
377 un = (char *)(attr + 1);
378 un_len =attr->length - sizeof(struct radius_attr_hdr);
379 }
401 break; 380 break;
402 case RADIUS_ATTR_DIGEST_USERNAME: 381 case RADIUS_ATTR_DIGEST_USERNAME:
403 got_Dusername = 1; 382 got_Dusername = 1;
404 break; 383 break;
405 case RADIUS_ATTR_DIGEST_REALM: 384 case RADIUS_ATTR_DIGEST_REALM:
417 case RADIUS_ATTR_DIGEST_NONCE_COUNT: 396 case RADIUS_ATTR_DIGEST_NONCE_COUNT:
418 got_Dnonce_count = 1; 397 got_Dnonce_count = 1;
419 break; 398 break;
420 case RADIUS_ATTR_DIGEST_NONCE: 399 case RADIUS_ATTR_DIGEST_NONCE:
421 got_Dnonce = 1; 400 got_Dnonce = 1;
401
402 size_t sidlen;
403
404 sid=nonce_get_sid((char *)(attr+1),attr->length-2,&sidlen,cs);
405 if(!sid)
406 {
407 TRACE_DEBUG(INFO,"We haven't found the session.'");
408 return EINVAL;
409 }
410 CHECK_FCT(fd_sess_fromsid (sid, sidlen, session, NULL));
411 free(sid);
412
413
422 break; 414 break;
423 case RADIUS_ATTR_DIGEST_CNONCE: 415 case RADIUS_ATTR_DIGEST_CNONCE:
424 got_Dcnonce = 1; 416 got_Dcnonce = 1;
425 break; 417 break;
426 case RADIUS_ATTR_DIGEST_RESPONSE: 418 case RADIUS_ATTR_DIGEST_RESPONSE:
432 case RADIUS_ATTR_SIP_AOR: 424 case RADIUS_ATTR_SIP_AOR:
433 got_AOR = 1; 425 got_AOR = 1;
434 break; 426 break;
435 } 427 }
436 } 428 }
437 if(!got_username) 429 if(!un)
438 { 430 {
439 TRACE_DEBUG(INFO,"No Username in request"); 431 TRACE_DEBUG(INFO,"No Username in request");
440 return 1; 432 return EINVAL;
441 } 433 }
442 if(!got_Dnonce) 434
443 { 435 /* Create the session if it is not already done */
444 /* Add the Session-Id AVP as first AVP */ 436 if (!*session) {
445 CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) ); 437
446 438 char * fqdn;
447 char *sid=NULL; 439 char * realm;
448 fd_sess_getsid (session, &sid ); 440
449 memset(&value, 0, sizeof(value)); 441
450 value.os.data = (unsigned char *)sid; 442
451 value.os.len = strlen(sid); 443
452 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); 444 /* Get information on the RADIUS client */
453 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) ); 445 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
454 } 446
447 int len;
448 /* Create a new Session-Id. The format is: {fqdn;hi32;lo32;username;diamid} */
449 CHECK_MALLOC( sid = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) );
450 len = sprintf(sid, "%.*s;%s", un_len, un, fd_g_config->cnf_diamid);
451 CHECK_FCT( fd_sess_new(session, fqdn, sid, len) );
452 free(sid);
453 }
454
455 /* Add the Destination-Realm AVP */
456 CHECK_FCT( fd_msg_avp_new ( cs->dict.Destination_Realm, 0, &avp ) );
457
458 int i = 0;
459 if (un) {
460 /* Is there an '@' in the user name? We don't care for decorated NAI here */
461 for (i = un_len - 2; i > 0; i--) {
462 if (un[i] == '@') {
463 i++;
464 break;
465 }
466 }
467 }
468 if (i == 0) {
469 /* Not found in the User-Name => we use the local domain of this gateway */
470 value.os.data = fd_g_config->cnf_diamrlm;
471 value.os.len = fd_g_config->cnf_diamrlm_len;
472 } else {
473 value.os.data = un + i;
474 value.os.len = un_len - i;
475 }
476
477 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
478 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
479
480 /* Now, add the Session-Id AVP at beginning of Diameter message */
481 CHECK_FCT( fd_sess_getsid(*session, &sid) );
482
483 TRACE_DEBUG(FULL, "[sip.rgwx] Translating new message for session '%s'...", sid);
484
485 /* Add the Session-Id AVP as first AVP */
486 CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
487 value.os.data = (unsigned char *)sid;
488 value.os.len = strlen(sid);
489 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
490 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
491
455 /* 492 /*
456 If the RADIUS Access-Request message does not 493 If the RADIUS Access-Request message does not
457 contain any Digest-* attribute, then the RADIUS client does not want 494 contain any Digest-* attribute, then the RADIUS client does not want
458 to apply HTTP Digest authentication, in which case, actions at the 495 to apply HTTP Digest authentication, in which case, actions at the
459 gateway are outside the scope of this document. 496 gateway are outside the scope of this document.
638 case RADIUS_ATTR_DIGEST_CNONCE: 675 case RADIUS_ATTR_DIGEST_CNONCE:
639 CONV2DIAM_STR_AUTH( Digest_CNonce ); 676 CONV2DIAM_STR_AUTH( Digest_CNonce );
640 break; 677 break;
641 case RADIUS_ATTR_DIGEST_NONCE: 678 case RADIUS_ATTR_DIGEST_NONCE:
642 CONV2DIAM_STR_AUTH( Digest_Nonce ); 679 CONV2DIAM_STR_AUTH( Digest_Nonce );
643
644
645 int new=0;
646 int sidlen=0;
647 struct session * temp;
648 char *nonce=malloc(attr->length-1);
649 char *sid=malloc(sidlen+1);
650
651 strncpy(nonce,(char *)(attr+1), attr->length-2);
652 nonce[attr->length-2]='\0';
653
654 //**Start mutex
655 pthread_mutex_lock(&state->nonce_mutex);
656 sidlen=strlen(nonce_check_element(nonce));
657 strcpy(sid,nonce_check_element(nonce));
658 sid[sidlen+1]='\0';
659 nonce_del_element(nonce);
660 free(nonce); //TODO: free nonce inside delete
661 pthread_mutex_unlock(&state->nonce_mutex);
662 //**Stop mutex
663
664 CHECK_FCT(fd_sess_fromsid ( (char *)sid, (size_t)sidlen, &temp, &new));
665 //free(sid);
666
667 if(new==0)
668 {
669 session=temp;
670 /* Add the Session-Id AVP as first AVP */
671 CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
672 //memset(&value, 0, sizeof(value));
673 value.os.data = (unsigned char *)sid;
674 value.os.len = sidlen;
675 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
676 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
677
678 }
679 else
680 {
681 TRACE_DEBUG(INFO,"Can't find previously established session, message droped!");
682 return 1;
683 }
684 //free(sid);
685 free(nonce);
686 //fd_sess_dump(FULL,session);
687
688
689
690 break; 680 break;
691 case RADIUS_ATTR_DIGEST_NONCE_COUNT: 681 case RADIUS_ATTR_DIGEST_NONCE_COUNT:
692 CONV2DIAM_STR_AUTH( Digest_Nonce_Count ); 682 CONV2DIAM_STR_AUTH( Digest_Nonce_Count );
693 break; 683 break;
694 case RADIUS_ATTR_DIGEST_RESPONSE: 684 case RADIUS_ATTR_DIGEST_RESPONSE:
735 //fd_msg_dump_walk(1,*diam_fw); 725 //fd_msg_dump_walk(1,*diam_fw);
736 726
737 /* Store the request identifier in the session (if provided) */ 727 /* Store the request identifier in the session (if provided) */
738 728
739 729
740 if (session) { 730 if (*session) {
741 unsigned char * req_sip; 731 unsigned char * req_sip;
742 CHECK_MALLOC(req_sip = malloc(16)); 732 CHECK_MALLOC(req_sip = malloc(16));
743 memcpy(req_sip, &rad_req->hdr->authenticator[0], 16); 733 memcpy(req_sip, &rad_req->hdr->authenticator[0], 16);
744 734
745 CHECK_FCT( fd_sess_state_store( cs->sess_hdl, session, &req_sip ) ); 735 CHECK_FCT( fd_sess_state_store( cs->sess_hdl, *session, &req_sip ) );
746 } 736 }
747 737
748 738
749 return 0; 739 return 0;
750 } 740 }
752 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 ) 742 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 )
753 { 743 {
754 744
755 struct msg_hdr * hdr; 745 struct msg_hdr * hdr;
756 struct avp *avp, *next, *asid; 746 struct avp *avp, *next, *asid;
757 struct avp_hdr *ahdr, *sid, *oh; 747 struct avp_hdr *ahdr, *sid;
758 char buf[254]; /* to store some attributes values (with final '\0') */ 748 //char buf[254]; /* to store some attributes values (with final '\0') */
759 int ta_set = 0; 749 //unsigned char * req_sip = NULL;
760 int no_str = 0; /* indicate if an STR is required for this server */
761 uint8_t tuntag = 0;
762 unsigned char * req_sip = NULL;
763 int in_success=0; 750 int in_success=0;
764 751
765 TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli); 752 TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
766 CHECK_PARAMS(cs && session && diam_ans && *diam_ans && rad_fw && *rad_fw); 753 CHECK_PARAMS(cs && session && diam_ans && *diam_ans && rad_fw && *rad_fw);
767 754
798 785
799 786
800 /* Search the different AVPs we handle here */ 787 /* Search the different AVPs we handle here */
801 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Session_Id, &asid) ); 788 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Session_Id, &asid) );
802 CHECK_FCT( fd_msg_avp_hdr ( asid, &sid ) ); 789 CHECK_FCT( fd_msg_avp_hdr ( asid, &sid ) );
803 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Host, &asid) );
804 CHECK_FCT( fd_msg_avp_hdr ( asid, &oh ) );
805 790
806 /* Check the Diameter error code */ 791 /* Check the Diameter error code */
807 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Result_Code, &avp) ); 792 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Result_Code, &avp) );
808 ASSERT( avp ); /* otherwise the message should have been discarded a lot earlier because of ABNF */ 793 ASSERT( avp ); /* otherwise the message should have been discarded a lot earlier because of ABNF */
809 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) ); 794 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
810 switch (ahdr->avp_value->u32) { 795 switch (ahdr->avp_value->u32) {
811 case ER_DIAMETER_MULTI_ROUND_AUTH: 796 case ER_DIAMETER_MULTI_ROUND_AUTH:
812 case ER_DIAMETER_SUCCESS_AUTH_SENT_SERVER_NOT_STORED: 797 case ER_DIAMETER_SUCCESS_AUTH_SENT_SERVER_NOT_STORED:
813 (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_CHALLENGE; 798 (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_CHALLENGE;
814 *statefull=1; 799 //struct timespec nowts;
815 struct timespec nowts; 800 //CHECK_SYS(clock_gettime(CLOCK_REALTIME, &nowts));
816 CHECK_SYS(clock_gettime(CLOCK_REALTIME, &nowts)); 801 //nowts.tv_sec+=600;
817 nowts.tv_sec+=600; 802 //CHECK_FCT(fd_sess_settimeout(session, &nowts ));
818 CHECK_FCT(fd_sess_settimeout(session, &nowts ));
819 break; 803 break;
820 case ER_DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED: 804 case ER_DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED:
821 case ER_DIAMETER_SUCCESS: 805 case ER_DIAMETER_SUCCESS:
822 (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_ACCEPT; 806 (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_ACCEPT;
823 in_success=1; 807 in_success=1;
824 break; 808 break;
825 809
826 default: 810 default:
827 (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_REJECT; 811 (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_REJECT;
828 fd_log_debug("[authSIP.rgwx] Received Diameter answer with error code '%d' from server '%.*s', session %.*s, translating into Access-Reject\n", 812 fd_log_debug("[sip.rgwx] Received Diameter answer with error code '%d', session %.*s, translating into Access-Reject\n",
829 ahdr->avp_value->u32, 813 ahdr->avp_value->u32,
830 oh->avp_value->os.len, oh->avp_value->os.data,
831 sid->avp_value->os.len, sid->avp_value->os.data); 814 sid->avp_value->os.len, sid->avp_value->os.data);
832 return 0; 815 return 0;
833 } 816 }
834 /* Remove this Result-Code avp */ 817 /* Remove this Result-Code avp */
835 CHECK_FCT( fd_msg_free( avp ) ); 818 CHECK_FCT( fd_msg_free( avp ) );
836
837 /* Creation of the State or Class attribute with session information */
838 CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Realm, &avp) );
839 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
840
841
842 /* Now, save the session-id and eventually server info in a STATE or CLASS attribute */
843 if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE) {
844 if (sizeof(buf) < snprintf(buf, sizeof(buf), "Diameter/%.*s/%.*s/%.*s",
845 oh->avp_value->os.len, oh->avp_value->os.data,
846 ahdr->avp_value->os.len, ahdr->avp_value->os.data,
847 sid->avp_value->os.len, sid->avp_value->os.data)) {
848 TRACE_DEBUG(INFO, "Data truncated in State attribute: %s", buf);
849 }
850 CONV2RAD_STR(RADIUS_ATTR_STATE, buf, strlen(buf), 0);
851
852 }
853
854 if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
855 /* Add the Session-Id */
856 if (sizeof(buf) < snprintf(buf, sizeof(buf), "Diameter/%.*s",
857 sid->avp_value->os.len, sid->avp_value->os.data)) {
858 TRACE_DEBUG(INFO, "Data truncated in Class attribute: %s", buf);
859 }
860 CONV2RAD_STR(RADIUS_ATTR_CLASS, buf, strlen(buf), 0);
861 }
862
863 /* Unlink the Origin-Realm now; the others are unlinked at the end of this function */
864 CHECK_FCT( fd_msg_free( avp ) );
865
866
867 819
868 /* Now loop in the list of AVPs and convert those that we know how */ 820 /* Now loop in the list of AVPs and convert those that we know how */
869 CHECK_FCT( fd_msg_browse(*diam_ans, MSG_BRW_FIRST_CHILD, &next, NULL) ); 821 CHECK_FCT( fd_msg_browse(*diam_ans, MSG_BRW_FIRST_CHILD, &next, NULL) );
870 822
871 while (next) { 823 while (next) {
876 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) ); 828 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
877 829
878 if (!(ahdr->avp_flags & AVP_FLAG_VENDOR)) { 830 if (!(ahdr->avp_flags & AVP_FLAG_VENDOR)) {
879 switch (ahdr->avp_code) { 831 switch (ahdr->avp_code) {
880 832
881 case DIAM_ATTR_AUTH_SESSION_STATE: 833
882 if ((!ta_set) && (ahdr->avp_value->u32 == ACV_ASS_STATE_MAINTAINED)) {
883 CONV2RAD_32B( RADIUS_ATTR_TERMINATION_ACTION, RADIUS_TERMINATION_ACTION_RADIUS_REQUEST );
884 }
885
886 if (ahdr->avp_value->u32 == ACV_ASS_NO_STATE_MAINTAINED) {
887 no_str = 1;
888 }
889 break;
890 case DIAM_ATTR_DIGEST_NONCE: 834 case DIAM_ATTR_DIGEST_NONCE:
891 CONV2RAD_STR(DIAM_ATTR_DIGEST_NONCE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0); 835 CONV2RAD_STR(DIAM_ATTR_DIGEST_NONCE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
892 /* Retrieve the request identified which was stored in the session */ 836 /* Retrieve the request identified which was stored in the session */
893 if (session) { 837 if (session) {
894 char *sid=NULL; 838 char *sid=NULL;
839 size_t sidlen;
840 fd_sess_getsid (session, &sid );
841 sidlen=strlen(sid);
895 842
896 fd_sess_getsid (session, &sid ); 843 nonce_add_element(ahdr->avp_value->os.data,ahdr->avp_value->os.len, sid,sidlen, cs);
897
898 //***Start mutex
899 CHECK_POSIX(pthread_mutex_lock(&state->nonce_mutex));
900 nonce_add_element(ahdr->avp_value->os.data, sid, state);
901 CHECK_POSIX(pthread_mutex_unlock(&state->nonce_mutex));
902 //***Stop mutex
903 } 844 }
904 break; 845 break;
905 case DIAM_ATTR_DIGEST_REALM: 846 case DIAM_ATTR_DIGEST_REALM:
906 CONV2RAD_STR(DIAM_ATTR_DIGEST_REALM, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1); 847 CONV2RAD_STR(DIAM_ATTR_DIGEST_REALM, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
907 break; 848 break;
923 864
924 default: /* unknown vendor */ 865 default: /* unknown vendor */
925 handled = 0; 866 handled = 0;
926 } 867 }
927 } 868 }
928 869 }
929 870
930 if (session) 871 if (session)
931 { 872 {
932 CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, session, &req_sip ) ); 873 //TODO: authenticator & message-authenticator
933 } 874 CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, session, &req_sip ) );
934 } 875 }
935 876 free(req_sip);
936 req_sip=NULL; 877
937 878
938 return 0; 879 return 0;
939 } 880 }
940 881
941 /* The exported symbol */ 882 /* The exported symbol */
943 .rgwp_name = "sip", 884 .rgwp_name = "sip",
944 .rgwp_conf_parse = sip_conf_parse, 885 .rgwp_conf_parse = sip_conf_parse,
945 .rgwp_conf_free = sip_conf_free, 886 .rgwp_conf_free = sip_conf_free,
946 .rgwp_rad_req = sip_rad_req, 887 .rgwp_rad_req = sip_rad_req,
947 .rgwp_diam_ans = sip_diam_ans 888 .rgwp_diam_ans = sip_diam_ans
948
949 }; 889 };
950 /*} 890
951 /* Add FAKE Digest_Realm AVP
952 {
953 //We give a fake realm because it will be provided in the second access request.
954 CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Realm, 0, &avp ) );
955
956 u8 *realm="example.com";
957
958 value.os.data=(unsigned char *)realm;
959 value.os.len=strlen(realm);
960 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
961 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );
962
963 }
964 else
965 {
966 TRACE_DEBUG(FULL,"\nAnswer to challenge!\n");
967 //We need a client nonce, count nonce, digest realm, username and response to handle authentication
968 if (got_Dnonce_count && got_Dcnonce && got_Dresponse && got_Drealm && got_Dusername)
969 {
970 /* Add SIP_Authorization AVP
971 {
972 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Authorization, 0, &auth ) );
973 CHECK_FCT( fd_msg_avp_add ( auth_data, MSG_BRW_LAST_CHILD, auth) );
974 }
975 for (idx = 0; idx < rad_req->attr_used; idx++)
976 {
977 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
978 char * temp;
979
980 switch (attr->type) {
981
982
983 default:
984
985 if(!got_Dalgorithm)
986 {
987 //[Note 3] If Digest-Algorithm is missing, 'MD5' is assumed.
988
989 CHECK_PARAMS( attr->length >= 2 );
990 CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Algorithm, 0, &avp ) );
991 value.os.len = attr->length - 2;
992 value.os.data = (unsigned char *)(attr + 1);
993 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
994 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );
995 }
996
997 }
998
999 }
1000 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, auth_data) );
1001
1002 }
1003 else
1004 {
1005 TRACE_DEBUG(INFO,"Missing Digest attributes in request, we drop it...");
1006 return 1;
1007 }
1008 }*/
1009
"Welcome to our mercurial repository"