Navigation


source: freeDiameter/extensions/app_radgw/rgwx_sip.c @ 706:4ffbc9f1e922

Last change on this file since 706:4ffbc9f1e922 was 706:4ffbc9f1e922, checked in by Sebastien Decugis <sdecugis@nict.go.jp>, 11 years ago

Large UNTESTED commit with the following changes:

  • Improved DiameterIdentity? handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7)
  • Cleanup in the session module to free only unreferenced sessions (#16)
  • Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
  • Improved peer state machine algorithm to counter SCTP multistream race condition.
File size: 29.9 KB
Line 
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 */
98struct 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
143typedef struct noncechain noncechain;
144struct 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
154static 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/*
176static 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
198static 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
228static 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 */
247static 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 */
308static 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 */
324static 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
738static 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 */
883struct 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
Note: See TracBrowser for help on using the repository browser.