Mercurial > hg > freeDiameter
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 |