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