Navigation


source: freeDiameter/extensions/app_radgw/rgwx_sip.c @ 705:f0cb8f465763

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

Added standard Result-Code values in header.
Added Error-Cause attribute conversion in app_radgw.

File size: 29.7 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 >= 2 );                                              \
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 - 2;                                                \
64        value.os.data = (unsigned char *)(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 >= 2 );                                              \
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 - 2;                                                \
74        value.os.data = (unsigned char *)(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 == 6 );                                              \
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    char * sid;
148    size_t sidlen;
149    char * nonce;
150    size_t noncelen;
151   
152};
153
154static int nonce_add_element(char * nonce, size_t noncelen,char * 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=malloc(noncelen));
162        memcpy(newelt->nonce,nonce,noncelen);
163        newelt->noncelen=noncelen;
164       
165        CHECK_MALLOC(newelt->sid=malloc(sidlen));
166        memcpy(newelt->sid,sid,sidlen);
167        newelt->sidlen=sidlen;
168       
169        fd_list_init(&newelt->chain,NULL);
170       
171        CHECK_POSIX(pthread_mutex_lock(&state->nonce_mutex));
172        fd_list_insert_before(&state->listnonce,&newelt->chain);
173        CHECK_POSIX(pthread_mutex_unlock(&state->nonce_mutex));
174       
175        return 0;
176}
177/*
178static void nonce_del_element(char * nonce, struct rgwp_config *state)
179{
180        struct fd_list * li;
181       
182        CHECK_PARAMS_DO(nonce && state, return);
183       
184        for(li=state->listnonce.next;li!=&state->listnonce;li=li->next)
185        {
186                noncechain *temp=(noncechain *)li;
187               
188                if(strcmp(temp->nonce,nonce)==0)
189                {
190                        fd_list_unlink (li);
191                        free(temp->sid);
192                        free(temp->nonce);
193                        free(temp);
194                        break;
195                }
196        }
197}
198*/
199//Retrieve sid from nonce
200static char * nonce_get_sid(char * nonce, size_t noncelen, size_t * sidlen, struct rgwp_config *state)
201{
202        struct fd_list * li;
203        char *sid=NULL;
204       
205        CHECK_PARAMS_DO(nonce && state && noncelen && sidlen, return NULL);
206        *sidlen=0;
207       
208        //**Start mutex
209        CHECK_POSIX_DO(pthread_mutex_lock(&state->nonce_mutex),); 
210        for(li=state->listnonce.next;li!=&state->listnonce;li=li->next)
211        {
212                noncechain *temp=(noncechain *)li;
213               
214                if(temp->noncelen==noncelen && strncmp(temp->nonce,nonce, noncelen)==0)
215                {
216                        fd_list_unlink (li);
217                        sid=temp->sid;
218                        *sidlen=temp->sidlen;
219                        free(temp->nonce);
220                        free(temp);
221                        break;
222                }
223               
224        }
225        CHECK_POSIX_DO(pthread_mutex_unlock(&state->nonce_mutex),); 
226        //***Stop mutex
227        return sid;
228}
229
230static void nonce_deletelistnonce(struct rgwp_config *state)
231{
232        //**Start mutex
233        CHECK_POSIX_DO(pthread_mutex_lock(&state->nonce_mutex),); 
234        while(!(FD_IS_LIST_EMPTY(&state->listnonce)) )
235        {
236                noncechain *temp=(noncechain *)state->listnonce.next;
237               
238                fd_list_unlink (&temp->chain);
239                free(temp->sid);
240                free(temp->nonce);
241                free(temp);
242               
243        }
244        CHECK_POSIX_DO(pthread_mutex_unlock(&state->nonce_mutex),); 
245        //***Stop mutex
246}
247
248/* Initialize the plugin */
249static int sip_conf_parse(char * conffile, struct rgwp_config ** state)
250{
251        struct rgwp_config * new;
252        struct dict_object * app;
253       
254       
255        TRACE_ENTRY("%p %p", conffile, state);
256        CHECK_PARAMS( state );
257       
258        CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
259        memset(new, 0, sizeof(struct rgwp_config));
260       
261        CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free, NULL ) );
262        new->confstr = conffile;
263       
264        /* Resolve all dictionary objects we use */
265        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &new->dict.Session_Id, ENOENT) );
266        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Application-Id", &new->dict.Auth_Application_Id, ENOENT) );
267        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Session-State", &new->dict.Auth_Session_State, ENOENT) );
268        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &new->dict.Origin_Host, ENOENT) );
269        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &new->dict.Origin_Realm, ENOENT) );
270        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &new->dict.Destination_Realm, ENOENT) );
271        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-AOR", &new->dict.SIP_AOR, ENOENT) );
272        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Method", &new->dict.SIP_Method, ENOENT) );
273        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &new->dict.Destination_Host, ENOENT) );
274        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "User-Name", &new->dict.User_Name, ENOENT) );
275        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Server-URI", &new->dict.SIP_Server_URI, ENOENT) );
276        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) );
277        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Authorization", &new->dict.SIP_Authorization, ENOENT) );
278        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) );
279        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Authentication-Scheme", &new->dict.SIP_Authentication_Scheme, ENOENT) );
280        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "SIP-Authentication-Info", &new->dict.SIP_Authentication_Info, ENOENT) );
281        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Info", &new->dict.Proxy_Info, ENOENT) );
282        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &new->dict.Route_Record, ENOENT) );
283        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &new->dict.Result_Code, ENOENT) );
284        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-URI", &new->dict.Digest_URI, ENOENT) );
285        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Nonce", &new->dict.Digest_Nonce, ENOENT) );
286        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Method", &new->dict.Digest_Method, ENOENT) );
287        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-CNonce", &new->dict.Digest_CNonce, ENOENT) );
288        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Nonce-Count", &new->dict.Digest_Nonce_Count, ENOENT) );
289        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Realm", &new->dict.Digest_Realm, ENOENT) );
290        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Response", &new->dict.Digest_Response, ENOENT) );
291        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Response-Auth", &new->dict.Digest_Response_Auth, ENOENT) );
292        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Username", &new->dict.Digest_Username, ENOENT) );
293        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-Algorithm", &new->dict.Digest_Algorithm, ENOENT) );
294        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Digest-QoP", &new->dict.Digest_QOP, ENOENT) );
295
296
297       
298        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Session Initiation Protocol (SIP) Application", &app, ENOENT) );
299        CHECK_FCT( fd_disp_app_support ( app, NULL, 1, 0 ) );
300       
301        //chained list
302        fd_list_init(&new->listnonce,NULL);
303        CHECK_POSIX(pthread_mutex_init(&new->nonce_mutex,NULL));
304       
305        *state = new;
306        return 0;
307}
308
309/* deinitialize */
310static void sip_conf_free(struct rgwp_config * state)
311{
312        TRACE_ENTRY("%p", state);
313        CHECK_PARAMS_DO( state, return );
314       
315        CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl, NULL ),  );
316       
317        nonce_deletelistnonce(state);
318        CHECK_POSIX_DO(pthread_mutex_destroy(&state->nonce_mutex), /*continue*/);
319       
320        free(state);
321        return;
322}
323
324
325/* Handle an incoming RADIUS request */
326static 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 )
327{
328        int idx;
329        int got_AOR = 0;
330        int got_Dusername = 0;
331        int got_Drealm = 0;
332        int got_Duri = 0;
333        int got_Dmethod = 0;
334        int got_Dqop = 0;
335        int got_Dnonce_count = 0;
336        int got_Dnonce = 0;
337        int got_Dcnonce = 0;
338        int got_Dresponse = 0;
339        int got_Dalgorithm = 0;
340        char * sid = NULL;
341        char * un=NULL;
342        size_t  un_len;
343        size_t nattr_used = 0;
344        struct avp *auth_data=NULL, *auth=NULL, *avp = NULL;
345        union avp_value value;
346       
347        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
348       
349        CHECK_PARAMS(rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCESS_REQUEST) && rad_ans && diam_fw && *diam_fw && session);
350       
351        //We check that session is not already filled
352        if(*session)
353        {
354                TRACE_DEBUG(INFO,"We are not supposed to receive a session in radSIP plugin.");
355                return EINVAL;
356        }
357       
358        /*
359           RFC5090 RADIUS Extension Digest Application
360        */
361       
362        /* Check basic information is there */
363        for (idx = 0; idx < rad_req->attr_used; idx++) {
364                struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
365               
366               
367                switch (attr->type) {
368                       
369                        case RADIUS_ATTR_USER_NAME:
370                                if (attr->length>sizeof(struct radius_attr_hdr)) 
371                                {
372                                        TRACE_DEBUG(ANNOYING, "Found a User-Name attribute: '%.*s'", attr->length- sizeof(struct radius_attr_hdr), (char *)(attr+1));
373                                        un = (char *)(attr + 1);
374                                        un_len =attr->length - sizeof(struct radius_attr_hdr);
375                                }
376                        break;
377                        case RADIUS_ATTR_DIGEST_USERNAME:
378                                got_Dusername = 1;
379                        break;
380                        case RADIUS_ATTR_DIGEST_REALM:
381                                got_Drealm = 1;
382                        break;
383                        case RADIUS_ATTR_DIGEST_URI:
384                                got_Duri = 1;
385                        break;
386                        case RADIUS_ATTR_DIGEST_METHOD:
387                                got_Dmethod = 1;
388                        break;
389                        case RADIUS_ATTR_DIGEST_QOP:
390                                got_Dqop = 1;
391                        break;
392                        case RADIUS_ATTR_DIGEST_NONCE_COUNT:
393                                got_Dnonce_count = 1;
394                        break;
395                        case RADIUS_ATTR_DIGEST_NONCE:
396                                got_Dnonce = 1;
397                               
398                                size_t sidlen;
399                               
400                                sid=nonce_get_sid((char *)(attr+1),attr->length-2,&sidlen,cs);
401                                if(!sid)
402                                {
403                                        TRACE_DEBUG(INFO,"We haven't found the session.'");
404                                        return EINVAL;
405                                }
406                                CHECK_FCT(fd_sess_fromsid (sid, sidlen, session, NULL));
407                                free(sid);
408                                                               
409                               
410                        break;
411                        case RADIUS_ATTR_DIGEST_CNONCE:
412                                got_Dcnonce = 1;
413                        break;
414                        case RADIUS_ATTR_DIGEST_RESPONSE:
415                                got_Dresponse = 1;
416                        break;                 
417                        case RADIUS_ATTR_DIGEST_ALGORITHM:
418                                got_Dalgorithm = 1;
419                        break;
420                        case RADIUS_ATTR_SIP_AOR:
421                                got_AOR = 1;
422                        break;
423                }
424        }
425        if(!un)
426        {
427                TRACE_DEBUG(INFO,"No Username in request");
428                return EINVAL;
429        }
430
431        /* Create the session if it is not already done */
432        if (!*session) {
433               
434                char * fqdn;
435                char * realm;
436               
437               
438               
439               
440                /* Get information on the RADIUS client */
441                CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
442               
443                int len;
444                /* Create a new Session-Id. The format is: {fqdn;hi32;lo32;username;diamid} */
445                CHECK_MALLOC( sid = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) );
446                len = sprintf(sid, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid);
447                CHECK_FCT( fd_sess_new(session, fqdn, sid, len) );
448                free(sid);
449        }
450               
451        /* Add the Destination-Realm AVP */
452        CHECK_FCT( fd_msg_avp_new ( cs->dict.Destination_Realm, 0, &avp ) );
453       
454        int i = 0;
455        if (un) {
456                /* Is there an '@' in the user name? We don't care for decorated NAI here */
457                for (i = un_len - 2; i > 0; i--) {
458                        if (un[i] == '@') {
459                                i++;
460                                break;
461                        }
462                }
463        }
464        if (i == 0) {
465                /* Not found in the User-Name => we use the local domain of this gateway */
466                value.os.data = (unsigned char *)fd_g_config->cnf_diamrlm;
467                value.os.len  = fd_g_config->cnf_diamrlm_len;
468        } else {
469                value.os.data = (unsigned char *)(un + i);
470                value.os.len  = un_len - i;
471        }
472       
473        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
474        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
475       
476        /* Now, add the Session-Id AVP at beginning of Diameter message */
477        CHECK_FCT( fd_sess_getsid(*session, &sid) );
478       
479        TRACE_DEBUG(FULL, "[sip.rgwx] Translating new message for session '%s'...", sid);
480       
481        /* Add the Session-Id AVP as first AVP */
482        CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
483        value.os.data = (unsigned char *)sid;
484        value.os.len = strlen(sid);
485        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
486        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
487       
488        /*
489        If the RADIUS Access-Request message does not
490        contain any Digest-* attribute, then the RADIUS client does not want
491        to apply HTTP Digest authentication, in which case, actions at the
492        gateway are outside the scope of this document.
493        */
494       
495        if(!(got_Dmethod && got_Duri))
496        {
497                TRACE_DEBUG(INFO,"No Digest attributes in request, we drop it...");
498                return 1;
499        }
500
501        /* Add the appropriate command code & Auth-Application-Id */
502        {
503                struct msg_hdr * header = NULL;
504                CHECK_FCT( fd_msg_hdr ( *diam_fw, &header ) );
505                header->msg_flags = CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE;
506                header->msg_code = CC_MULTIMEDIA_AUTH_REQUEST;
507                header->msg_appl = AI_SIP;
508       
509       
510                /* Add the Auth-Application-Id */
511                {
512                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Auth_Application_Id, 0, &avp ) );
513                        value.i32 = header->msg_appl;
514                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
515                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
516                }
517        }
518        /*Add Auth_Session_State  AVP */
519        {
520                CHECK_FCT( fd_msg_avp_new ( cs->dict.Auth_Session_State, 0, &avp ) );
521                value.i32 = ACV_ASS_NO_STATE_MAINTAINED;
522                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
523                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
524        }
525
526       
527        /*Add SIP_Number_Auth_Items  AVP */
528        {
529                CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Number_Auth_Items, 0, &avp ) );
530                value.i32 = 1; //We just treat one auth per request in gateway
531                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
532                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
533        }
534
535        /* Add SIP_Auth_Data_Item AVP */
536        {
537                CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Auth_Data_Item, 0, &auth_data ) );
538        }
539        /* Add SIP_Authentication_Scheme AVP */
540        {
541                CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Authentication_Scheme, 0, &avp ) );
542                value.i32=0; //There is only Digest Auth in RFC for now
543                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
544                CHECK_FCT( fd_msg_avp_add ( auth_data, MSG_BRW_LAST_CHILD, avp) );
545       
546        }
547
548       
549        /* Add SIP_Authorization AVP */
550        {
551                CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Authorization, 0, &auth ) );
552                CHECK_FCT( fd_msg_avp_add ( auth_data, MSG_BRW_LAST_CHILD, auth) );
553        }
554        char * temp=NULL,*sipuri=NULL;
555
556        for (idx = 0; idx < rad_req->attr_used; idx++) 
557        {
558                struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
559               
560                switch (attr->type) {
561
562                        case RADIUS_ATTR_USER_NAME:
563                        CONV2DIAM_STR( User_Name );
564                       
565                        if(!got_Dusername)
566                        {
567                                CONV2DIAM_STR_AUTH(Digest_Username);
568                                got_Dusername=1;
569                        }
570                       
571                        break;
572
573                        case RADIUS_ATTR_DIGEST_URI:
574                       
575                        CONV2DIAM_STR_AUTH(Digest_URI);
576                       
577                        //All of these attributes are required by Diameter but not defined in RFC5090 so we provide FAKE values (only in first exchange)
578                        if(!got_AOR)
579                        {
580                                CONV2DIAM_STR( SIP_AOR );
581                                got_AOR=1;
582                        }
583                        /*
584                        We must provide a fake nonce because of RFC4740 problem
585                        TODO: remove when RFC is updated
586                        ==START of FAKE
587                        */
588                        if(!got_Dresponse)
589                        {
590                                CONV2DIAM_STR_AUTH(Digest_Response);
591                                got_Dresponse=1;
592                        }
593                        /*
594                        ==END of FAKE
595                        */
596                        if(!got_Drealm)
597                        {
598                                //We extract Realm from Digest_URI
599                                char *realm=NULL;
600                       
601                                CHECK_MALLOC(temp=malloc(attr->length -1));
602                                strncpy(temp, (char *)(attr + 1), attr->length -2);
603                                temp[attr->length-2] = '\0';
604                       
605                                realm = strtok( (char *)(temp), "@" );
606                                realm = strtok( NULL, "@" );
607                                free(temp);
608                                temp=NULL;
609                                if(realm!=NULL)
610                                {
611                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Realm, 0, &avp ) );
612                                        value.os.data=(unsigned char *)realm;
613                                        value.os.len=strlen(realm);
614                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
615                                        CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );
616                                       
617                                        //We add SIP-Server-URI AVP because SIP server is registrar (through gateway)
618                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Server_URI, 0, &avp ) );
619                                        value.os.data=(unsigned char *)realm;
620                                        value.os.len=strlen(realm);
621                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
622                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
623                                       
624                                }
625                                else
626                                {
627                                        TRACE_DEBUG(INFO, "Can't extract domain from URI, droping request...");
628                                        return 1;
629                                }       
630                                got_Drealm=1;
631                        }
632                        break;
633
634                        case RADIUS_ATTR_DIGEST_METHOD:
635                        CONV2DIAM_STR(SIP_Method);
636                        CONV2DIAM_STR_AUTH(Digest_Method);
637                        break;
638                        case RADIUS_ATTR_DIGEST_REALM:
639                        CONV2DIAM_STR_AUTH(Digest_Realm);
640                       
641                        //We add SIP-Server-URI AVP because SIP server is registrar (through gateway)
642                        CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Server_URI, 0, &avp ) );
643                       
644                       
645                        CHECK_MALLOC(temp=malloc(attr->length -1));
646                        strncpy(temp, (char *)(attr + 1), attr->length -2);
647                       
648                       
649                        CHECK_MALLOC(sipuri=malloc(attr->length +3));
650                        strcpy(sipuri,"sip:");
651                        strcat(sipuri,(const char *)temp);
652                        value.os.data=(unsigned char *)sipuri;
653                        value.os.len=attr->length +2;
654                       
655                        free(temp);
656                        temp=NULL;
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                                                                               
692                                CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Algorithm, 0, &avp ) );                     
693                                                                               
694                                value.os.data = (unsigned char *)"MD5";
695                                value.os.len = strlen((const char *)value.os.data);
696                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                                       
697                                CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );   
698                                got_Dalgorithm=1;       
699                        }
700                       
701                        if(!got_Dnonce)
702                        {
703                                //We give a fake nonce because it will be calculated at the server.
704                                CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Nonce, 0, &avp ) );
705                                value.os.data=(unsigned char *)"nonce";
706                                value.os.len=strlen((const char *)value.os.data);
707                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
708                                CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );   
709                                got_Dnonce=1;
710                        }
711                        break;
712       
713                }
714        }
715
716       
717        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, auth_data) );
718       
719        /* Update the radius message to remove all handled attributes */
720        rad_req->attr_used = nattr_used;
721
722        //fd_msg_dump_walk(1,*diam_fw);
723       
724        /* Store the request identifier in the session (if provided) */
725        if (*session) {
726                unsigned char * req_sip;
727                CHECK_MALLOC(req_sip = malloc(16));
728                memcpy(req_sip, &rad_req->hdr->authenticator[0], 16);
729               
730                CHECK_FCT( fd_sess_state_store( cs->sess_hdl, *session, &req_sip ) );
731        }
732       
733       
734        return 0;
735}
736
737static 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 )
738{
739       
740       
741        struct avp *avp, *next, *asid;
742        struct avp_hdr *ahdr, *sid;
743        //char buf[254]; /* to store some attributes values (with final '\0') */
744        unsigned char * req_sip = NULL;
745        int in_success=0;
746       
747        TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
748        CHECK_PARAMS(cs && session && diam_ans && *diam_ans && rad_fw && *rad_fw);
749       
750       
751       
752       
753       
754        /* MACROS to help in the process: convert AVP data to RADIUS attributes. */
755        /* Control large attributes:  _trunc_ = 0 => error; _trunc_ = 1 => truncate; _trunc = 2 => create several attributes */
756        #define CONV2RAD_STR( _attr_, _data_, _len_, _trunc_)   {                                       \
757                size_t __l = (size_t)(_len_);                                                           \
758                size_t __off = 0;                                                                       \
759                TRACE_DEBUG(FULL, "Converting AVP to "#_attr_);                                         \
760                if ((_trunc_) == 0) {                                                                   \
761                        CHECK_PARAMS( __l <= 253 );                                                     \
762                }                                                                                       \
763                if ((__l > 253) && (_trunc_ == 1)) {                                                    \
764                        TRACE_DEBUG(INFO, "[authSIP.rgwx] AVP truncated in "#_attr_);                   \
765                        __l = 253;                                                                      \
766                }                                                                                       \
767                do {                                                                                    \
768                        size_t __w = (__l > 253) ? 253 : __l;                                           \
769                        CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (_data_) + __off, __w));    \
770                        __off += __w;                                                                   \
771                        __l   -= __w;                                                                   \
772                } while (__l);                                                                          \
773        }
774
775        #define CONV2RAD_32B( _attr_, _data_)   {                                                       \
776                uint32_t __v = htonl((uint32_t)(_data_));                                               \
777                TRACE_DEBUG(FULL, "Converting AVP to "#_attr_);                                         \
778                CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (uint8_t *)&__v, sizeof(__v)));     \
779        }
780
781
782        /* Search the different AVPs we handle here */
783        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Session_Id, &asid) );
784        CHECK_FCT( fd_msg_avp_hdr ( asid, &sid ) );
785
786        /* Check the Diameter error code */
787        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Result_Code, &avp) );
788        ASSERT( avp ); /* otherwise the message should have been discarded a lot earlier because of ABNF */
789        CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
790        switch (ahdr->avp_value->u32) {
791                case ER_DIAMETER_MULTI_ROUND_AUTH:
792                case ER_DIAMETER_SUCCESS_AUTH_SENT_SERVER_NOT_STORED:           
793                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_CHALLENGE;
794                        //struct timespec nowts;
795                        //CHECK_SYS(clock_gettime(CLOCK_REALTIME, &nowts));
796                        //nowts.tv_sec+=600;
797                        //CHECK_FCT(fd_sess_settimeout(session, &nowts ));
798                        break;
799                case ER_DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED:
800                case ER_DIAMETER_SUCCESS:
801                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_ACCEPT;
802                        in_success=1;
803                        break;
804               
805                default:
806                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_REJECT;
807                        fd_log_debug("[sip.rgwx] Received Diameter answer with error code '%d', session %.*s, translating into Access-Reject\n",
808                                        ahdr->avp_value->u32, 
809                                        sid->avp_value->os.len, sid->avp_value->os.data);
810                        return 0;
811        }
812        /* Remove this Result-Code avp */
813        CHECK_FCT( fd_msg_free( avp ) );
814       
815        /* Now loop in the list of AVPs and convert those that we know how */
816        CHECK_FCT( fd_msg_browse(*diam_ans, MSG_BRW_FIRST_CHILD, &next, NULL) );
817       
818        while (next) {
819                int handled = 1;
820                avp = next;
821                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_WALK, &next, NULL) );
822               
823                CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
824               
825                if (!(ahdr->avp_flags & AVP_FLAG_VENDOR)) {
826                        switch (ahdr->avp_code) {
827                               
828                               
829                                case DIAM_ATTR_DIGEST_NONCE:
830                                        CONV2RAD_STR(DIAM_ATTR_DIGEST_NONCE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
831                                        /* Retrieve the request identified which was stored in the session */
832                                        if (session) {
833                                                char *sid=NULL;
834                                                size_t sidlen;
835                                                fd_sess_getsid (session, &sid );
836                                                sidlen=strlen(sid);
837                                               
838                                                nonce_add_element((char *)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.