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