Navigation


source: freeDiameter/extensions/app_radgw/rgwx_auth.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: 77.4 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2011, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36/* RADIUS Access-Request messages translation plugin */
37
38#include "rgw_common.h"
39
40/* Attributes missing from radius.h */
41#define RADIUS_ATTR_CHAP_PASSWORD       3
42#define RADIUS_ATTR_ARAP_PASSWORD       70
43
44/* Other constants we use */
45#define AI_NASREQ               1       /* Diameter NASREQ */
46#define AI_EAP                  5       /* Diameter EAP application */
47#define CC_AA                   265     /* AAR */
48#define CC_DIAMETER_EAP         268     /* DER */
49#define ACV_ART_AUTHORIZE_AUTHENTICATE  3       /* AUTHORIZE_AUTHENTICATE */
50#define ACV_OAP_RADIUS                  1       /* RADIUS */
51#define ACV_ASS_STATE_MAINTAINED        0       /* STATE_MAINTAINED */
52#define ACV_ASS_NO_STATE_MAINTAINED     1       /* NO_STATE_MAINTAINED */
53
54/* The state we keep for this plugin */
55struct rgwp_config {
56        struct {
57                struct dict_object * ARAP_Password;             /* ARAP-Password */
58                struct dict_object * ARAP_Security;             /* ARAP-Security */
59                struct dict_object * ARAP_Security_Data;        /* ARAP-Security-Data */
60                struct dict_object * Auth_Application_Id;       /* Auth-Application-Id */
61                struct dict_object * Auth_Request_Type;         /* Auth-Request-Type */
62                struct dict_object * Authorization_Lifetime;    /* Authorization-Lifetime */
63                struct dict_object * Callback_Number;           /* Callback-Number */
64                struct dict_object * Called_Station_Id;         /* Called-Station-Id */
65                struct dict_object * Calling_Station_Id;        /* Calling-Station-Id */
66                struct dict_object * CHAP_Algorithm;            /* CHAP-Algorithm */
67                struct dict_object * CHAP_Auth;                 /* CHAP-Auth */
68                struct dict_object * CHAP_Challenge;            /* CHAP-Challenge */
69                struct dict_object * CHAP_Ident;                /* CHAP-Ident */
70                struct dict_object * CHAP_Response;             /* CHAP-Response */
71                struct dict_object * Destination_Host;          /* Destination-Host */
72                struct dict_object * Destination_Realm;         /* Destination-Realm */
73                struct dict_object * Connect_Info;              /* Connect-Info */
74                struct dict_object * EAP_Payload;               /* EAP-Payload */
75                struct dict_object * Error_Message;             /* Error-Message */
76                struct dict_object * Error_Reporting_Host;      /* Error-Reporting-Host */
77                struct dict_object * Failed_AVP;                /* Failed-AVP */
78                struct dict_object * Framed_Compression;        /* Framed-Compression */
79                struct dict_object * Framed_IP_Address;         /* Framed-IP-Address */
80                struct dict_object * Framed_IP_Netmask;         /* Framed-IP-Netmask */
81                struct dict_object * Framed_Interface_Id;       /* Framed-Interface-Id */
82                struct dict_object * Framed_IPv6_Prefix;        /* Framed-IPv6-Prefix */
83                struct dict_object * Framed_MTU;                /* Framed-MTU */
84                struct dict_object * Framed_Protocol;           /* Framed-Protocol */
85                struct dict_object * Login_IP_Host;             /* Login-IP-Host */
86                struct dict_object * Login_IPv6_Host;           /* Login-IPv6-Host */
87                struct dict_object * Login_LAT_Group;           /* Login-LAT-Group */
88                struct dict_object * Login_LAT_Node;            /* Login-LAT-Node */
89                struct dict_object * Login_LAT_Port;            /* Login-LAT-Port */
90                struct dict_object * Login_LAT_Service;         /* Login-LAT-Service */
91                struct dict_object * NAS_Identifier;            /* NAS-Identifier */
92                struct dict_object * NAS_IP_Address;            /* NAS-IP-Address */
93                struct dict_object * NAS_IPv6_Address;          /* NAS-IPv6-Address */
94                struct dict_object * NAS_Port;                  /* NAS-Port */
95                struct dict_object * NAS_Port_Id;               /* NAS-Port-Id */
96                struct dict_object * NAS_Port_Type;             /* NAS-Port-Type */
97                struct dict_object * Origin_AAA_Protocol;       /* Origin-AAA-Protocol */
98                struct dict_object * Origin_Host;               /* Origin-Host */
99                struct dict_object * Origin_Realm;              /* Origin-Realm */
100                struct dict_object * Originating_Line_Info;     /* Originating-Line-Info */
101                struct dict_object * Port_Limit;                /* Port-Limit */
102                struct dict_object * Re_Auth_Request_Type;      /* Re-Auth-Request-Type */
103                struct dict_object * Result_Code;               /* Result-Code */
104                struct dict_object * Service_Type;              /* Service-Type */
105                struct dict_object * Session_Id;                /* Session-Id */
106                struct dict_object * Session_Timeout;           /* Session-Timeout */
107                struct dict_object * State;                     /* State */
108                struct dict_object * Tunneling;                 /* Tunneling */
109                struct dict_object * Tunnel_Type;               /* Tunnel-Type */
110                struct dict_object * Tunnel_Medium_Type;        /* Tunnel-Medium-Type */
111                struct dict_object * Tunnel_Client_Endpoint;    /* Tunnel-Client-Endpoint */
112                struct dict_object * Tunnel_Server_Endpoint;    /* Tunnel-Server-Endpoint */
113                struct dict_object * Tunnel_Private_Group_Id;   /* Tunnel-Private-Group-Id */
114                struct dict_object * Tunnel_Preference;         /* Tunnel-Preference */
115                struct dict_object * Tunnel_Client_Auth_Id;     /* Tunnel-Client-Auth-Id */
116                struct dict_object * Tunnel_Server_Auth_Id;     /* Tunnel-Server-Auth-Id */
117                struct dict_object * User_Name;                 /* User-Name */
118                struct dict_object * User_Password;             /* User-Password */
119               
120        } dict; /* cache of the dictionary objects we use */
121        struct session_handler * sess_hdl; /* We store RADIUS request authenticator information in the session */
122        char * confstr;
123       
124        int ignore_nai;
125};
126
127/* Initialize the plugin */
128static int auth_conf_parse(char * confstr, struct rgwp_config ** state)
129{
130        struct rgwp_config * new;
131        struct dict_object * app;
132       
133        TRACE_ENTRY("%p %p", confstr, state);
134        CHECK_PARAMS( state );
135       
136        CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
137        memset(new, 0, sizeof(struct rgwp_config));
138       
139        CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free, NULL ) );
140        new->confstr = confstr;
141       
142        if (confstr && strstr(confstr, "nonai"))
143                new->ignore_nai = 1;
144       
145        /* Resolve all dictionary objects we use */
146        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "ARAP-Password", &new->dict.ARAP_Password, ENOENT) );
147        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "ARAP-Security", &new->dict.ARAP_Security, ENOENT) );
148        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "ARAP-Security-Data", &new->dict.ARAP_Security_Data, ENOENT) );
149        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Application-Id", &new->dict.Auth_Application_Id, ENOENT) );
150        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Request-Type", &new->dict.Auth_Request_Type, ENOENT) );
151        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Authorization-Lifetime", &new->dict.Authorization_Lifetime, ENOENT) );
152        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Callback-Number", &new->dict.Callback_Number, ENOENT) );
153        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Called-Station-Id", &new->dict.Called_Station_Id, ENOENT) );
154        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Calling-Station-Id", &new->dict.Calling_Station_Id, ENOENT) );
155        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "CHAP-Algorithm", &new->dict.CHAP_Algorithm, ENOENT) );
156        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "CHAP-Auth", &new->dict.CHAP_Auth, ENOENT) );
157        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "CHAP-Challenge", &new->dict.CHAP_Challenge, ENOENT) );
158        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "CHAP-Ident", &new->dict.CHAP_Ident, ENOENT) );
159        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "CHAP-Response", &new->dict.CHAP_Response, ENOENT) );
160        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Connect-Info", &new->dict.Connect_Info, ENOENT) );
161        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &new->dict.Destination_Host, ENOENT) );
162        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &new->dict.Destination_Realm, ENOENT) );
163        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "EAP-Payload", &new->dict.EAP_Payload, ENOENT) );
164        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &new->dict.Error_Message, ENOENT) );
165        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &new->dict.Error_Reporting_Host, ENOENT) );
166        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP", &new->dict.Failed_AVP, ENOENT) );
167        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-Compression", &new->dict.Framed_Compression, ENOENT) );
168        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-IP-Address", &new->dict.Framed_IP_Address, ENOENT) );
169        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-IP-Netmask", &new->dict.Framed_IP_Netmask, ENOENT) );
170        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-Interface-Id", &new->dict.Framed_Interface_Id, ENOENT) );
171        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-IPv6-Prefix", &new->dict.Framed_IPv6_Prefix, ENOENT) );
172        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-MTU", &new->dict.Framed_MTU, ENOENT) );
173        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-Protocol", &new->dict.Framed_Protocol, ENOENT) );
174        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-IP-Host", &new->dict.Login_IP_Host, ENOENT) );
175        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-IPv6-Host", &new->dict.Login_IPv6_Host, ENOENT) );
176        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-LAT-Group", &new->dict.Login_LAT_Group, ENOENT) );
177        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-LAT-Node", &new->dict.Login_LAT_Node, ENOENT) );
178        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-LAT-Port", &new->dict.Login_LAT_Port, ENOENT) );
179        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-LAT-Service", &new->dict.Login_LAT_Service, ENOENT) );
180        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-Identifier", &new->dict.NAS_Identifier, ENOENT) );
181        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-IP-Address", &new->dict.NAS_IP_Address, ENOENT) );
182        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-IPv6-Address", &new->dict.NAS_IPv6_Address, ENOENT) );
183        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-Port", &new->dict.NAS_Port, ENOENT) );
184        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-Port-Id", &new->dict.NAS_Port_Id, ENOENT) );
185        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-Port-Type", &new->dict.NAS_Port_Type, ENOENT) );
186        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-AAA-Protocol", &new->dict.Origin_AAA_Protocol, ENOENT) );
187        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &new->dict.Origin_Host, ENOENT) );
188        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &new->dict.Origin_Realm, ENOENT) );
189        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Originating-Line-Info", &new->dict.Originating_Line_Info, ENOENT) );
190        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Port-Limit", &new->dict.Port_Limit, ENOENT) );
191        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Re-Auth-Request-Type", &new->dict.Re_Auth_Request_Type, ENOENT) );
192        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &new->dict.Result_Code, ENOENT) );
193        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Service-Type", &new->dict.Service_Type, ENOENT) );
194        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &new->dict.Session_Id, ENOENT) );
195        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Timeout", &new->dict.Session_Timeout, ENOENT) );
196        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "State", &new->dict.State, ENOENT) );
197        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunneling", &new->dict.Tunneling, ENOENT) );
198        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Type", &new->dict.Tunnel_Type, ENOENT) );
199        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Medium-Type", &new->dict.Tunnel_Medium_Type, ENOENT) );
200        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Client-Endpoint", &new->dict.Tunnel_Client_Endpoint, ENOENT) );
201        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Server-Endpoint", &new->dict.Tunnel_Server_Endpoint, ENOENT) );
202        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Private-Group-Id", &new->dict.Tunnel_Private_Group_Id, ENOENT) );
203        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Preference", &new->dict.Tunnel_Preference, ENOENT) );
204        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Client-Auth-Id", &new->dict.Tunnel_Client_Auth_Id, ENOENT) );
205        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Server-Auth-Id", &new->dict.Tunnel_Server_Auth_Id, ENOENT) );
206        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "User-Name", &new->dict.User_Name, ENOENT) );
207        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "User-Password", &new->dict.User_Password, ENOENT) );
208       
209        /* This plugin provides the following Diameter authentication applications support: */
210        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Network Access Server Application", &app, ENOENT) );
211        CHECK_FCT( fd_disp_app_support ( app, NULL, 1, 0 ) );
212
213        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Extensible Authentication Protocol (EAP) Application", &app, ENOENT) );
214        CHECK_FCT( fd_disp_app_support ( app, NULL, 1, 0 ) );
215       
216        *state = new;
217        return 0;
218}
219
220/* deinitialize */
221static void auth_conf_free(struct rgwp_config * state)
222{
223        TRACE_ENTRY("%p", state);
224        CHECK_PARAMS_DO( state, return );
225        CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl, NULL ),  );
226        free(state);
227        return;
228}
229
230/* Handle an incoming RADIUS request */
231static int auth_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 )
232{
233        int idx;
234        int got_id = 0;
235        int got_mac = 0;
236        int got_passwd = 0;
237        int got_eap = 0;
238        int got_empty_eap = 0;
239        const char * prefix = "Diameter/";
240        size_t pref_len;
241        uint8_t * dh = NULL;
242        size_t dh_len = 0;
243        uint8_t * dr = NULL;
244        size_t dr_len = 0;
245        uint8_t * si = NULL;
246        size_t si_len = 0;
247        uint8_t * un = NULL;
248        size_t un_len = 0;
249        size_t nattr_used = 0;
250        struct avp ** avp_tun = NULL, *avp = NULL;
251        union avp_value value;
252       
253        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
254        CHECK_PARAMS(cs && session && rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCESS_REQUEST) && rad_ans && diam_fw && *diam_fw);
255       
256        pref_len = strlen(prefix);
257       
258        /*
259           Guidelines:
260             http://tools.ietf.org/html/rfc4005#section-9.1
261             http://tools.ietf.org/html/rfc4072#section-6.1
262
263           When a Translation Agent receives a RADIUS message, the following
264           steps should be taken:
265
266              -  If a Message-Authenticator attribute is present, the value MUST
267                 be checked but not included in the Diameter message.  If it is
268                 incorrect, the RADIUS message should be silently discarded.
269                 The gateway system SHOULD generate and include a Message-
270                 Authenticator in returned RADIUS responses.
271                     -> done in rgw_msg_auth_check
272
273              -  The transport address of the sender MUST be checked against the
274                 NAS identifying attributes.  See the description of NAS-
275                 Identifier and NAS-IP-Address below.
276                     -> done in rgw_clients_check_origin
277
278              -  The Translation Agent must maintain transaction state
279                 information relevant to the RADIUS request, such as the
280                 Identifier field in the RADIUS header, any existing RADIUS
281                 Proxy-State attribute, and the source IP address and port
282                 number of the UDP packet.  These may be maintained locally in a
283                 state table or saved in a Proxy-Info AVP group.  A Diameter
284                 Session-Id AVP value must be created using a session state
285                 mapping mechanism.
286                     -> Identifier, source and port are saved along with the request,
287                        and associated with the session state.
288                     -> sub_echo_drop should handle the Proxy-State attribute (conf issue)
289
290              -  The Diameter Origin-Host and Origin-Realm AVPs MUST be created
291                 and added by using the information from an FQDN corresponding
292                 to the NAS-IP-Address attribute (preferred if available),
293                 and/or to the NAS-Identifier attribute.  (Note that the RADIUS
294                 NAS-Identifier is not required to be an FQDN.)
295                     -> done in rgw_msg_create_base.
296
297              -  The response MUST have an Origin-AAA-Protocol AVP added,
298                 indicating the protocol of origin of the message.
299                     -> what "response" ??? Added to the AAR / DER in this function.
300
301              -  The Proxy-Info group SHOULD be added, with the local server's
302                 identity specified in the Proxy-Host AVP.  This should ensure
303                 that the response is returned to this system.
304                     -> We don't need this, answer is always routed here anyway.
305                     
306              For EAP:
307             
308              o  RADIUS EAP-Message attribute(s) are translated to a Diameter
309                 EAP-Payload AVP.  If multiple RADIUS EAP-Message attributes are
310                 present, they are concatenated and translated to a single Diameter
311                 EAP-Payload AVP.
312                     -> concatenation done by radius_msg_get_eap
313
314              -> the remaining is specific conversion rules
315        */
316       
317        /* Check basic information is there, and also retrieve some attribute information */
318        for (idx = 0; idx < rad_req->attr_used; idx++) {
319                struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
320                uint8_t * attr_val = (uint8_t *)(attr + 1);
321                size_t attr_len = attr->length - sizeof(struct radius_attr_hdr);
322               
323                switch (attr->type) {
324                        case RADIUS_ATTR_NAS_IP_ADDRESS:
325                        case RADIUS_ATTR_NAS_IDENTIFIER:
326                        case RADIUS_ATTR_NAS_IPV6_ADDRESS:
327                                got_id = 1;
328                                break;
329                        case RADIUS_ATTR_MESSAGE_AUTHENTICATOR:
330                                got_mac = 1;
331                                break;
332                        case RADIUS_ATTR_EAP_MESSAGE:
333                                got_eap = 1;
334                                if (attr->length == 2)
335                                        got_empty_eap = 1;
336                                break;
337                        case RADIUS_ATTR_USER_PASSWORD:
338                        case RADIUS_ATTR_CHAP_PASSWORD:
339                        case RADIUS_ATTR_ARAP_PASSWORD:
340                                got_passwd += 1;
341                                break;
342                               
343                        /* Is there a State attribute with prefix "Diameter/" in the message? (in that case: Diameter/Destination-Host/Destination-Realm/Session-Id) */
344                        /* NOTE: RFC4005 says "Origin-Host" here, but it's not coherent with the rules for answers. Destination-Host makes more sense */
345                        case RADIUS_ATTR_STATE:
346                                if ((attr_len > pref_len + 5 /* for the '/'s and non empty strings */ ) 
347                                        && ! memcmp(attr_val, prefix, pref_len)) {
348                                        int i, start;
349
350                                        TRACE_DEBUG(ANNOYING, "Found a State attribute with '%s' prefix (attr #%d).", prefix, idx);
351
352                                        /* Now parse the value and check its content is valid. Unfortunately we cannot use strchr here since strings are not \0-terminated */
353
354                                        i = start = pref_len;
355                                        dh = attr_val + i;
356                                        for (; (i < attr_len - 2) && (attr_val[i] != '/'); i++) /* loop */;
357                                        if ( i >= attr_len - 2 ) continue; /* the attribute format is not good */
358                                        dh_len = i - start;
359
360                                        start = ++i;
361                                        dr = attr_val + i;
362                                        for (; (i < attr_len - 1) && (attr_val[i] != '/'); i++) /* loop */;
363                                        if ( i >= attr_len - 1 ) continue; /* the attribute format is not good */
364                                        dr_len = i - start;
365
366                                        i++;
367                                        si = attr_val + i;
368                                        si_len = attr_len - i;
369
370                                        TRACE_DEBUG(ANNOYING, "Attribute parsed successfully: DH:'%.*s' DR:'%.*s' SI:'%.*s'.", dh_len, dh, dr_len, dr, si_len, si);
371                                        /* Remove from the message */
372                                        for (i = idx + 1; i < rad_req->attr_used; i++)
373                                                rad_req->attr_pos[i - 1] = rad_req->attr_pos[i];
374                                        rad_req->attr_used -= 1;
375                                        idx--;
376                                }
377                                break;
378               
379                        case RADIUS_ATTR_USER_NAME:
380                                TRACE_DEBUG(ANNOYING, "Found a User-Name attribute: '%.*s'", attr_len, attr_len ? (char *)attr_val : "");
381                                un = attr_val;
382                                un_len = attr_len;
383                                break;
384                       
385                }
386        }
387        if (!got_id) {
388                TRACE_DEBUG(INFO, "RADIUS Access-Request did not contain a NAS IP or Identifier attribute, reject.");
389                return EINVAL;
390        }
391        /* [Note 1] An Access-Request that contains either a User-Password or
392           CHAP-Password or ARAP-Password or one or more EAP-Message attributes
393           MUST NOT contain more than one type of those four attributes.  If it
394           does not contain any of those four attributes, it SHOULD contain a
395           Message-Authenticator.  If any packet type contains an EAP-Message
396           attribute it MUST also contain a Message-Authenticator.  A RADIUS
397           server receiving an Access-Request not containing any of those four
398           attributes and also not containing a Message-Authenticator attribute
399           SHOULD silently discard it.  */
400        if (((got_eap + got_passwd) > 1) || (got_eap && !got_mac) || (!got_eap && !got_passwd && !got_mac)) {
401                TRACE_DEBUG(INFO, "RADIUS Access-Request not conform to RFC3579 sec 3.3 note 1, discard.");
402                return EINVAL;
403        }
404       
405       
406       
407        /*
408              -  If the RADIUS request contained a State attribute and the
409                 prefix of the data is "Diameter/", the data following the
410                 prefix contains the Diameter Origin-Host/Origin-Realm/Session-
411                 Id.  If no such attributes are present and the RADIUS command
412                 is an Access-Request, a new Session-Id is created.  The
413                 Session-Id is included in the Session-Id AVP.
414        */
415       
416        /* Add the Destination-Realm AVP */
417        CHECK_FCT( fd_msg_avp_new ( cs->dict.Destination_Realm, 0, &avp ) );
418        if (dr) {
419                value.os.data = (unsigned char *)dr;
420                value.os.len = dr_len;
421        } else {
422                int i = 0;
423                if (un && ! cs->ignore_nai) {
424                        /* Is there an '@' in the user name? We don't care for decorated NAI here */
425                        for (i = un_len - 2; i > 0; i--) {
426                                if (un[i] == '@') {
427                                        i++;
428                                        break;
429                                }
430                        }
431                }
432                if (i <= 0) {
433                        /* Not found in the User-Name => we use the local domain of this gateway */
434                        value.os.data = (uint8_t *)fd_g_config->cnf_diamrlm;
435                        value.os.len  = fd_g_config->cnf_diamrlm_len;
436                } else {
437                        value.os.data = un + i;
438                        value.os.len  = un_len - i;
439                }
440        }
441        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
442        CHECK_FCT( fd_msg_avp_add ( *diam_fw, *session ? MSG_BRW_LAST_CHILD : MSG_BRW_FIRST_CHILD, avp) );
443       
444        /* Add the Destination-Host if found */
445        if (dh) {
446                CHECK_FCT( fd_msg_avp_new ( cs->dict.Destination_Host, 0, &avp ) );
447                value.os.data = (unsigned char *)dh;
448                value.os.len = dh_len;
449                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
450                CHECK_FCT( fd_msg_avp_add ( *diam_fw, *session ? MSG_BRW_LAST_CHILD : MSG_BRW_FIRST_CHILD, avp) );
451        }
452       
453        /* Create the session if it is not already done */
454        if (*session == NULL) {
455                char * sess_str = NULL;
456               
457                if (si_len) {
458                        /* We already have the Session-Id, just use it */
459                        CHECK_FCT( fd_sess_fromsid ( (char *) /* this cast will be removed later */ si, si_len, session, NULL) );
460                } else {
461                        /* Create a new Session-Id string */
462                       
463                        char * fqdn;
464                        char * realm;
465                       
466                        /* Get information on the RADIUS client */
467                        CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
468                       
469                        /* If we have a user name, create the new session with it */
470                        if (un) {
471                                int len;
472                                /* If not found, create a new Session-Id. The format is: {fqdn;hi32;lo32;username;diamid} */
473                                CHECK_MALLOC( sess_str = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) );
474                                len = sprintf(sess_str, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid);
475                                CHECK_FCT( fd_sess_new(session, fqdn, sess_str, len) );
476                                free(sess_str);
477                        } else {
478                                /* We don't have enough information to create the Session-Id, the RADIUS message is probably invalid */
479                                TRACE_DEBUG(INFO, "RADIUS Access-Request does not contain a User-Name attribute, rejecting.");
480                                return EINVAL;
481                        }       
482                }
483               
484                /* Now, add the Session-Id AVP at beginning of Diameter message */
485                CHECK_FCT( fd_sess_getsid(*session, &sess_str) );
486               
487                TRACE_DEBUG(FULL, "[auth.rgwx] Translating new message for session '%s'...", sess_str);
488               
489                /* Add the Session-Id AVP as first AVP */
490                CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
491                value.os.data = (unsigned char *)sess_str;
492                value.os.len = strlen(sess_str);
493                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
494                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
495        }
496       
497       
498        /* Add the appropriate command code & Auth-Application-Id */
499        {
500                struct msg_hdr * header = NULL;
501                CHECK_FCT( fd_msg_hdr ( *diam_fw, &header ) );
502                header->msg_flags = CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE;
503                if (got_eap) {
504                        header->msg_code = CC_DIAMETER_EAP;
505                        header->msg_appl = AI_EAP;
506                } else {
507                        header->msg_code = CC_AA;
508                        header->msg_appl = AI_NASREQ;
509                }
510               
511                /* Add the Auth-Application-Id */
512                {
513                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Auth_Application_Id, 0, &avp ) );
514                        value.i32 = header->msg_appl;
515                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
516                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
517                }
518        }
519       
520        /*      The type of request is identified through the Auth-Request-Type AVP
521                [BASE].  The recommended value for most RADIUS interoperabily
522                situations is AUTHORIZE_AUTHENTICATE. */
523       
524        /* Add Auth-Request-Type AVP */
525        {
526                CHECK_FCT( fd_msg_avp_new ( cs->dict.Auth_Request_Type, 0, &avp ) );
527                value.i32 = ACV_ART_AUTHORIZE_AUTHENTICATE;
528                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
529                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
530        }
531       
532        /* Add Origin-AAA-Protocol AVP */
533        {
534                CHECK_FCT( fd_msg_avp_new ( cs->dict.Origin_AAA_Protocol, 0, &avp ) );
535                value.i32 = ACV_OAP_RADIUS;
536                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
537                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
538        }
539       
540        /* Convert the EAP payload (concat RADIUS attributes) */
541        if (got_eap) {
542                CHECK_FCT( fd_msg_avp_new ( cs->dict.EAP_Payload, 0, &avp ) );
543               
544                /*    o  An empty RADIUS EAP-Message attribute (with length 2) signifies
545                         EAP-Start, and it is translated to an empty EAP-Payload AVP. */
546                if (got_empty_eap) {
547                        value.os.len = 0;
548                        value.os.data = (uint8_t *)"";
549                } else {
550                        CHECK_MALLOC( value.os.data = radius_msg_get_eap(rad_req, &value.os.len) );
551                }
552               
553                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
554                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
555        }
556       
557        /* Tunnel AVPs need some preparation */
558        /* Convert the attributes one by one */
559        for (idx = 0; idx < rad_req->attr_used; idx++) {
560                struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
561
562                switch (attr->type) {
563                       
564                        /* This macro converts a RADIUS attribute to a Diameter AVP of type OctetString */
565                        #define CONV2DIAM_STR( _dictobj_ )      \
566                                CHECK_PARAMS( attr->length >= 2 );                                              \
567                                /* Create the AVP with the specified dictionary model */                        \
568                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
569                                value.os.len = attr->length - 2;                                                \
570                                value.os.data = (unsigned char *)(attr + 1);                                    \
571                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
572                                /* Add the AVP in the Diameter message. */                                      \
573                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
574                               
575                        /* Same thing, for scalar AVPs of 32 bits */
576                        #define CONV2DIAM_32B( _dictobj_ )      \
577                                CHECK_PARAMS( attr->length == 6 );                                              \
578                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
579                                {                                                                               \
580                                        uint8_t * v = (uint8_t *)(attr + 1);                                    \
581                                        value.u32  = (v[0] << 24)                                               \
582                                                   | (v[1] << 16)                                               \
583                                                   | (v[2] <<  8)                                               \
584                                                   |  v[3] ;                                                    \
585                                }                                                                               \
586                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
587                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
588                               
589                        /* And the 64b version */
590                        #define CONV2DIAM_64B( _dictobj_ )      \
591                                CHECK_PARAMS( attr->length == 10);                                              \
592                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
593                                {                                                                               \
594                                        uint8_t * v = (uint8_t *)(attr + 1);                                    \
595                                        value.u64  = ((uint64_t)(v[0]) << 56)                                   \
596                                                   | ((uint64_t)(v[1]) << 48)                                   \
597                                                   | ((uint64_t)(v[2]) << 40)                                   \
598                                                   | ((uint64_t)(v[3]) << 32)                                   \
599                                                   | ((uint64_t)(v[4]) << 24)                                   \
600                                                   | ((uint64_t)(v[5]) << 16)                                   \
601                                                   | ((uint64_t)(v[6]) <<  8)                                   \
602                                                   |  (uint64_t)(v[7]) ;                                        \
603                                }                                                                               \
604                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
605                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
606                               
607                /* RFC 2865 */ 
608                        /*
609                              -  The Destination-Realm AVP is created from the information found
610                                 in the RADIUS User-Name attribute.
611                                        -> done in rgw_msg_create_base
612                        */
613                        case RADIUS_ATTR_USER_NAME:
614                                CONV2DIAM_STR( User_Name );
615                                break;
616                               
617                        /*
618                              -  If the RADIUS User-Password attribute is present, the password
619                                 must be unencrypted by using the link's RADIUS shared secret.
620                                 The unencrypted value must be forwarded in a User-Password AVP
621                                 using Diameter security.
622                        */
623                        case RADIUS_ATTR_USER_PASSWORD:
624                                if ((attr->length - 2) % 16) {
625                                        TRACE_DEBUG(INFO, "Invalid length of User-Password attribute: %hhd", attr->length);
626                                        return EINVAL;
627                                }
628                                {
629                                        /* Decipher following this logic (refers to rfc2865#section-5.2 )
630                                           b1 = MD5(S + RA)     p1 = c(1) xor b1
631                                           b2 = MD5(S + c(1))   p2 = c(2) xor b2
632                                           ...
633                                        */
634                                       
635                                        uint8_t *ciph = (uint8_t *)(attr+1);    /* c(i) */
636                                        size_t ciph_len = attr->length - 2;
637                                        uint8_t deciph[128];                    /* pi */
638                                        size_t deciph_len = 0;
639                                        uint8_t * secret;                       /* S */
640                                        size_t secret_len;
641                                        uint8_t hash[16];                       /* b(i) */
642                                        const uint8_t *addr[2];
643                                        size_t len[2];
644                                       
645                                        /* Retrieve the shared secret */
646                                        CHECK_FCT(rgw_clients_getkey(cli, &secret, &secret_len));
647                                       
648                                        /* Initial b1 = MD5(S + RA) */
649                                        addr[0] = secret;
650                                        len[0] = secret_len;
651                                        addr[1] = rad_req->hdr->authenticator;
652                                        len[1] = 16;
653                                        md5_vector(2, addr, len, hash);
654                                       
655                                        /* loop */
656                                        while (deciph_len < ciph_len) {
657                                                int i;
658                                                /* pi = c(i) xor bi */
659                                                for (i = 0; i < 16; i++)
660                                                        deciph[deciph_len + i] = ciph[deciph_len + i] ^ hash[i];
661                                                        /* do we have to remove the padding '\0's ? */
662                                               
663                                                /* b(i+1) = MD5(S + c(i) */
664                                                addr[1] = ciph + deciph_len;
665                                                md5_vector(2, addr, len, hash);
666                                               
667                                                deciph_len += 16;
668                                        }
669                                       
670                                        /* Now save this value in the AVP */
671                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.User_Password, 0, &avp ) );
672                                        value.os.data = &deciph[0];
673                                        value.os.len  = deciph_len;
674                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
675                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
676                                }
677                                break;
678                               
679
680                        /*
681                              -  If the RADIUS CHAP-Password attribute is present, the Ident and
682                                 Data portion of the attribute are used to create the CHAP-Auth
683                                 grouped AVP.
684                        */
685                        case RADIUS_ATTR_CHAP_PASSWORD:
686                                CHECK_PARAMS( attr->length == 19 /* RFC 2865 */);
687                                {
688                                        uint8_t * c = (uint8_t *)(attr + 1);
689                                        struct avp * chap_auth;
690                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.CHAP_Auth, 0, &chap_auth ) );
691                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, chap_auth) );
692
693                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.CHAP_Algorithm, 0, &avp ) );
694                                        value.u32 = 5; /* The only value defined currently... */
695                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
696                                        CHECK_FCT( fd_msg_avp_add ( chap_auth, MSG_BRW_LAST_CHILD, avp) );
697                                       
698                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.CHAP_Ident, 0, &avp ) );
699                                        value.os.data = c;
700                                        value.os.len = 1;
701                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
702                                        CHECK_FCT( fd_msg_avp_add ( chap_auth, MSG_BRW_LAST_CHILD, avp) );
703                                       
704                                        c++;
705                                       
706                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.CHAP_Response, 0, &avp ) );
707                                        value.os.data = c;
708                                        value.os.len = attr->length - 3;
709                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
710                                        CHECK_FCT( fd_msg_avp_add ( chap_auth, MSG_BRW_LAST_CHILD, avp) );
711                                }
712                                break;
713                               
714                        case RADIUS_ATTR_NAS_IP_ADDRESS:
715                                CONV2DIAM_STR( NAS_IP_Address );
716                                break;
717                               
718                        case RADIUS_ATTR_NAS_PORT:
719                                CONV2DIAM_32B( NAS_Port );
720                                break;
721                               
722                        case RADIUS_ATTR_SERVICE_TYPE:
723                                CONV2DIAM_32B( Service_Type );
724                                break;
725                               
726                        case RADIUS_ATTR_FRAMED_PROTOCOL:
727                                CONV2DIAM_32B( Framed_Protocol );
728                                break;
729                               
730                        case RADIUS_ATTR_FRAMED_IP_ADDRESS:
731                                CONV2DIAM_STR( Framed_IP_Address );
732                                break;
733                               
734                        case RADIUS_ATTR_FRAMED_IP_NETMASK:
735                                CONV2DIAM_STR( Framed_IP_Netmask );
736                                break;
737                               
738                        /* Framed-Routing never present in an Access-Request */
739                        /* Filter-Id never present in an Access-Request */
740                               
741                        case RADIUS_ATTR_FRAMED_MTU:
742                                CONV2DIAM_32B( Framed_MTU );
743                                break;
744                       
745                        case RADIUS_ATTR_FRAMED_COMPRESSION:
746                                CONV2DIAM_32B( Framed_Compression );
747                                break;
748                       
749                        case RADIUS_ATTR_LOGIN_IP_HOST:
750                                CONV2DIAM_STR( Login_IP_Host );
751                                break;
752                               
753                        /* Login-Service never present in an Access-Request */
754                        /* Login-TCP-Port never present in an Access-Request */
755                        /* Reply-Message never present in an Access-Request */
756                       
757                        case RADIUS_ATTR_CALLBACK_NUMBER:
758                                CONV2DIAM_STR( Callback_Number );
759                                break;
760                               
761                        /* Callback-Id never present in an Access-Request */
762                        /* Framed-Route never present in an Access-Request */
763                        /* Framed-IPX-Network never present in an Access-Request */
764                               
765                        case RADIUS_ATTR_STATE:
766                                CONV2DIAM_STR( State );
767                                break;
768                       
769                        /* Class never present in an Access-Request */
770                               
771                        case RADIUS_ATTR_VENDOR_SPECIFIC:
772                                /* RFC 4005, Section 9.6 :
773                                           Systems that don't have vendor format knowledge MAY discard such
774                                           attributes without knowing a suitable translation.
775                                           
776                                           [conversion rule in 9.6.2]
777                                 */
778                                if (attr->length >= 6) {
779                                        uint32_t vendor_id;
780                                        uint8_t * c = (uint8_t *)(attr + 1);
781                                       
782                                        vendor_id = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3];
783                                        c += 4;
784                                       
785                                        switch (vendor_id) {
786                                               
787                                                /* For the vendors we KNOW they follow the VSA recommended format, we convert following the rules of RFC4005 (9.6.2) */
788                                                case RADIUS_VENDOR_ID_MICROSOFT : /* RFC 2548 */
789                                                /* other vendors ? */
790                                                {
791                                                        size_t left;
792                                                        struct radius_attr_vendor *vtlv;
793                                                       
794                                                        left = attr->length - 6;
795                                                        vtlv = (struct radius_attr_vendor *)c;
796                                               
797                                                        while ((left >= 2) && (vtlv->vendor_length <= left)) {
798                                                                /* Search our dictionary for corresponding Vendor's AVP */
799                                                                struct dict_avp_request req;
800                                                                struct dict_object * avp_model = NULL;
801                                                                memset(&req, 0, sizeof(struct dict_avp_request));
802                                                                req.avp_vendor = vendor_id;
803                                                                req.avp_code = vtlv->vendor_type;
804                                                               
805                                                                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE_AND_VENDOR, &req, &avp_model, 0) );
806                                                                if (!avp_model) {
807                                                                        TRACE_DEBUG(FULL, "Unknown attribute (vendor 0x%x, code 0x%x) ignored.", req.avp_vendor, req.avp_code);
808                                                                } else {
809                                                                        CHECK_FCT( fd_msg_avp_new ( avp_model, 0, &avp ) );
810                                                                        value.os.len = vtlv->vendor_length - 2;
811                                                                        value.os.data = (unsigned char *)(vtlv + 1);
812                                                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
813                                                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
814                                                                }
815                                                                c += vtlv->vendor_length;
816                                                                left -= vtlv->vendor_length;
817                                                                vtlv = (struct radius_attr_vendor *)c;
818                                                        }
819                                                }
820                                                break;
821                                               
822                                                /* Other vendors we KNOw how to convert the attributes would be added here... */
823                                                /* case RADIUS_VENDOR_ID_CISCO :
824                                                        break; */
825                                                /* case RADIUS_VENDOR_ID_IETF : (extended RADIUS attributes)
826                                                        break; */
827                                               
828                                                /* When we don't know, just discard the attribute... VSA are optional with regards to RADIUS anyway */
829                                                default:
830                                                        /* do nothing */
831                                                        TRACE_DEBUG(FULL, "VSA attribute from vendor %d discarded", vendor_id);
832                                                       
833                                        }
834                                }
835                                break;
836                               
837                        /* Session-Timeout never present in an Access-Request */
838                        /* Idle-Timeout never present in an Access-Request */
839                        /* Termination-Action never present in an Access-Request */
840                               
841                        case RADIUS_ATTR_CALLED_STATION_ID:
842                                CONV2DIAM_STR( Called_Station_Id );
843                                break;
844                       
845                        case RADIUS_ATTR_CALLING_STATION_ID:
846                                CONV2DIAM_STR( Calling_Station_Id );
847                                break;
848                       
849                        case RADIUS_ATTR_NAS_IDENTIFIER:
850                                CONV2DIAM_STR( NAS_Identifier );
851                                break;
852                       
853                        /* Proxy-State is handled by echo_drop.rgwx plugin, we ignore it here */
854                       
855                        case RADIUS_ATTR_LOGIN_LAT_SERVICE:
856                                CONV2DIAM_STR( Login_LAT_Service );
857                                break;
858                       
859                        case RADIUS_ATTR_LOGIN_LAT_NODE:
860                                CONV2DIAM_STR( Login_LAT_Node );
861                                break;
862                       
863                        case RADIUS_ATTR_LOGIN_LAT_GROUP:
864                                CONV2DIAM_STR( Login_LAT_Group );
865                                break;
866                       
867                        /* Framed-AppleTalk-Link never present in an Access-Request */
868                        /* Framed-AppleTalk-Network never present in an Access-Request */
869                        /* Framed-AppleTalk-Zone never present in an Access-Request */
870                       
871                        case RADIUS_ATTR_CHAP_CHALLENGE:
872                                CONV2DIAM_STR( CHAP_Challenge );
873                                break;
874                       
875                        case RADIUS_ATTR_NAS_PORT_TYPE:
876                                CONV2DIAM_32B( NAS_Port_Type );
877                                break;
878                       
879                        case RADIUS_ATTR_PORT_LIMIT:
880                                CONV2DIAM_32B( Port_Limit );
881                                break;
882                       
883                        case RADIUS_ATTR_LOGIN_LAT_PORT:
884                                CONV2DIAM_STR( Login_LAT_Port );
885                                break;
886                       
887                       
888                /* RFC 3162 */ 
889                        case RADIUS_ATTR_NAS_IPV6_ADDRESS:
890                                CONV2DIAM_STR( NAS_IPv6_Address );
891                                break;
892                               
893                        case RADIUS_ATTR_FRAMED_INTERFACE_ID:
894                                CONV2DIAM_64B( Framed_Interface_Id );
895                                break;
896                               
897                        case RADIUS_ATTR_FRAMED_IPV6_PREFIX:
898                                CONV2DIAM_STR( Framed_IPv6_Prefix );
899                                break;
900                               
901                        case RADIUS_ATTR_LOGIN_IPV6_HOST:
902                                CONV2DIAM_STR( Login_IPv6_Host );
903                                break;
904                               
905                        /* Framed-IPv6-Route never present in an Access-Request */
906                        /* Framed-IPv6-Pool never present in an Access-Request */
907
908
909                /* RFC 2868 */
910                        /* Prepare the top-level Tunneling AVP for each tag values, as needed, and add to the Diameter message.
911                                This macro is called when an AVP is added inside the group, so we will not have empty grouped AVPs */
912                        #define AVP_TUN_PREPARE() {                                                                             \
913                                                if (avp_tun == NULL) {                                                          \
914                                                        CHECK_MALLOC( avp_tun = calloc(sizeof(struct avp *), 32 ) );            \
915                                                }                                                                               \
916                                                tag = *(uint8_t *)(attr + 1);                                                   \
917                                                if (tag > 0x1F) tag = 0;                                                        \
918                                                if (avp_tun[tag] == NULL) {                                                     \
919                                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Tunneling, 0, &avp_tun[tag] ) );   \
920                                                        CHECK_FCT( fd_msg_avp_add (*diam_fw, MSG_BRW_LAST_CHILD, avp_tun[tag]));\
921                                                }                                                                               \
922                                        }
923                       
924                        /* Convert an attribute to an OctetString AVP and add inside the Tunneling AVP corresponding to the tag */
925                        #define CONV2DIAM_TUN_STR( _dictobj_ ) {                                                \
926                                uint8_t tag;                                                                    \
927                                CHECK_PARAMS( attr->length >= 3);                                               \
928                                AVP_TUN_PREPARE();                                                              \
929                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
930                                value.os.len = attr->length - (tag ? 3 : 2);                                    \
931                                value.os.data = ((unsigned char *)(attr + 1)) + (tag ? 1 : 0);                  \
932                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
933                                CHECK_FCT( fd_msg_avp_add ( avp_tun[tag], MSG_BRW_LAST_CHILD, avp) );           \
934                                }
935                               
936                        /* Convert an attribute to a scalar AVP and add inside the Tunneling AVP corresponding to the tag */
937                        #define CONV2DIAM_TUN_24B( _dictobj_ ) {                                                \
938                                uint8_t tag;                                                                    \
939                                CHECK_PARAMS( attr->length == 6);                                               \
940                                AVP_TUN_PREPARE();                                                              \
941                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
942                                {                                                                               \
943                                        uint8_t * v = (uint8_t *)(attr + 1);                                    \
944                                        value.u32 = (v[1] << 16) | (v[2] <<8) | v[3] ;                          \
945                                }                                                                               \
946                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
947                                CHECK_FCT( fd_msg_avp_add ( avp_tun[tag], MSG_BRW_LAST_CHILD, avp) );           \
948                                }
949
950                        /*
951                              -  If the RADIUS message contains Tunnel information [RADTunnels],
952                                 the attributes or tagged groups should each be converted to a
953                                 Diameter Tunneling Grouped AVP set.  If the tunnel information
954                                 contains a Tunnel-Password attribute, the RADIUS encryption
955                                 must be resolved, and the password forwarded, by using Diameter
956                                 security methods.
957                                    -> If the RADIUS message does not use properly the Tag info, result is unpredictable here..
958                        */
959                        case RADIUS_ATTR_TUNNEL_TYPE:
960                                CONV2DIAM_TUN_24B( Tunnel_Type );
961                                break;
962                       
963                        case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
964                                CONV2DIAM_TUN_24B( Tunnel_Medium_Type );
965                                break;
966                       
967                        case RADIUS_ATTR_TUNNEL_CLIENT_ENDPOINT:
968                                CONV2DIAM_TUN_STR( Tunnel_Client_Endpoint );
969                                break;
970                       
971                        case RADIUS_ATTR_TUNNEL_SERVER_ENDPOINT:
972                                CONV2DIAM_TUN_STR( Tunnel_Server_Endpoint );
973                                break;
974                       
975                        /* Tunnel-Password never present in an Access-Request */
976
977                        case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
978                                CONV2DIAM_TUN_STR( Tunnel_Private_Group_Id );
979                                break;
980                       
981                        /* Tunnel-Assignment-ID never present in an Access-Request */
982                       
983                        case RADIUS_ATTR_TUNNEL_PREFERENCE:
984                                CONV2DIAM_TUN_24B( Tunnel_Preference );
985                                break;
986                       
987                        case RADIUS_ATTR_TUNNEL_CLIENT_AUTH_ID:
988                                CONV2DIAM_TUN_STR( Tunnel_Client_Auth_Id );
989                                break;
990                       
991                        case RADIUS_ATTR_TUNNEL_SERVER_AUTH_ID:
992                                CONV2DIAM_TUN_STR( Tunnel_Server_Auth_Id );
993                                break;
994                       
995                       
996                /* RFC 2869 */ 
997                        case RADIUS_ATTR_ARAP_PASSWORD:
998                                CONV2DIAM_STR( ARAP_Password );
999                                break;
1000                               
1001                        /* ARAP-Features never present in an Access-Request */
1002                        /* ARAP-Zone-Access never present in an Access-Request */
1003                       
1004                        case RADIUS_ATTR_ARAP_SECURITY:
1005                                CONV2DIAM_32B( ARAP_Security );
1006                                break;
1007                       
1008                        case RADIUS_ATTR_ARAP_SECURITY_DATA:
1009                                CONV2DIAM_STR( ARAP_Security_Data );
1010                                break;
1011                       
1012                        /* Password-Retry never present in an Access-Request */
1013                        /* Prompt never present in an Access-Request */
1014                       
1015                        case RADIUS_ATTR_CONNECT_INFO:
1016                                CONV2DIAM_STR( Connect_Info );
1017                                break;
1018                       
1019                        /* Configuration-Token never present in an Access-Request */
1020                        /* ARAP-Challenge-Response never present in an Access-Request */
1021                        /* Acct-Interim-Interval never present in an Access-Request */
1022                       
1023                        case RADIUS_ATTR_NAS_PORT_ID:
1024                                CONV2DIAM_STR( NAS_Port_Id );
1025                                break;
1026                       
1027                        /* Framed-Pool never present in an Access-Request */
1028                       
1029                               
1030                /* RFC 2869 / 3579 */   
1031                        case RADIUS_ATTR_ORIGINATING_LINE_INFO:
1032                                CONV2DIAM_STR( Originating_Line_Info );
1033                                break;
1034                               
1035                        case RADIUS_ATTR_MESSAGE_AUTHENTICATOR:
1036                        case RADIUS_ATTR_EAP_MESSAGE:
1037                                /* It was already handled, just remove the attribute */
1038                                break;
1039                               
1040                /* Default */           
1041                        default: /* unknown attribute */
1042                                /* We just keep the attribute in the RADIUS message */
1043                                rad_req->attr_pos[nattr_used++] = rad_req->attr_pos[idx];
1044                }
1045        }
1046       
1047        /* Destroy tunnel pointers (if we used it) */
1048        free(avp_tun);
1049       
1050        /* Update the radius message to remove all handled attributes */
1051        rad_req->attr_used = nattr_used;
1052
1053        /* Store the request identifier in the session (if provided) */
1054        if (*session) {
1055                unsigned char * req_auth;
1056                CHECK_MALLOC(req_auth = malloc(16));
1057                memcpy(req_auth, &rad_req->hdr->authenticator[0], 16);
1058               
1059                CHECK_FCT( fd_sess_state_store( cs->sess_hdl, *session, &req_auth ) );
1060        }
1061       
1062        return 0;
1063}
1064
1065static int auth_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli, int * stateful )
1066{
1067        struct msg_hdr * hdr;
1068        struct avp *avp, *next, *avp_x, *avp_y, *asid, *aoh;
1069        struct avp_hdr *ahdr, *sid, *oh;
1070        uint8_t buf[254]; /* to store some attributes values (with final '\0') */
1071        size_t sz;
1072        int ta_set = 0;
1073        int no_str = 0; /* indicate if an STR is required for this server */
1074        uint8_t tuntag = 0;
1075        unsigned char * req_auth = NULL;
1076        int error_cause = 0;
1077       
1078        TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
1079        CHECK_PARAMS(cs && session && diam_ans && *diam_ans && rad_fw && *rad_fw);
1080       
1081        /* Retrieve the request identified which was stored in the session */
1082        if (session) {
1083                CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, session, &req_auth ) );
1084        }
1085       
1086        /*     
1087              -  If the Diameter Command-Code is set to AA-Answer and the
1088                 Result-Code AVP is set to DIAMETER_MULTI_ROUND_AUTH, the
1089                 gateway must send a RADIUS Access-Challenge.  This must have
1090                 the Origin-Host, Origin-Realm, and Diameter Session-Id AVPs
1091                 encapsulated in the RADIUS State attribute, with the prefix
1092                 "Diameter/", concatenated in the above order separated with "/"
1093                 characters, in UTF-8 [UTF-8].  This is necessary to ensure that
1094                 the Translation Agent receiving the subsequent RADIUS Access-
1095                 Request will have access to the Session Identifier and be able
1096                 to set the Destination-Host to the correct value.
1097                        -> done here bellow
1098                 
1099              -  If the Command-Code is set to AA-Answer, the Diameter Session-
1100                 Id AVP is saved in a new RADIUS Class attribute whose format
1101                 consists of the string "Diameter/" followed by the Diameter
1102                 Session Identifier.  This will ensure that the subsequent
1103                 Accounting messages, which could be received by any Translation
1104                 Agent, would have access to the original Diameter Session
1105                 Identifier.
1106                        -> done here but only for Access-Accept messages (Result-Code = success)
1107         */
1108       
1109        /* MACROS to help in the process: convert AVP data to RADIUS attributes. */
1110        /* Control large attributes:  _trunc_ = 0 => error; _trunc_ = 1 => truncate; _trunc = 2 => create several attributes */
1111        #define CONV2RAD_STR( _attr_, _data_, _len_, _trunc_)   {                                       \
1112                size_t __l = (size_t)(_len_);                                                           \
1113                size_t __off = 0;                                                                       \
1114                TRACE_DEBUG(FULL, "Converting AVP to "#_attr_);                                         \
1115                if ((_trunc_) == 0) {                                                                   \
1116                        CHECK_PARAMS( __l <= 253 );                                                     \
1117                }                                                                                       \
1118                if ((__l > 253) && (_trunc_ == 1)) {                                                    \
1119                        TRACE_DEBUG(INFO, "[auth.rgwx] AVP truncated in "#_attr_);                      \
1120                        __l = 253;                                                                      \
1121                }                                                                                       \
1122                do {                                                                                    \
1123                        size_t __w = (__l > 253) ? 253 : __l;                                           \
1124                        CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (_data_) + __off, __w));    \
1125                        __off += __w;                                                                   \
1126                        __l   -= __w;                                                                   \
1127                } while (__l);                                                                          \
1128        }
1129
1130        #define CONV2RAD_32B( _attr_, _data_)   {                                                       \
1131                uint32_t __v = htonl((uint32_t)(_data_));                                               \
1132                TRACE_DEBUG(FULL, "Converting AVP to "#_attr_);                                         \
1133                CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (uint8_t *)&__v, sizeof(__v)));     \
1134        }
1135
1136        #define CONV2RAD_64B( _attr_, _data_)   {                                                       \
1137                uint64_t __v = htonll((uint64_t)(_data_));                                              \
1138                TRACE_DEBUG(FULL, "Converting AVP to "#_attr_);                                         \
1139                CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (uint8_t *)&__v, sizeof(__v)));     \
1140        }
1141
1142        /* Search the different AVPs we handle here */
1143        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Session_Id, &asid) );
1144        CHECK_FCT( fd_msg_avp_hdr ( asid, &sid ) );
1145        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Host, &aoh) );
1146        CHECK_FCT( fd_msg_avp_hdr ( aoh, &oh ) );
1147
1148        /* Check the Diameter error code */
1149        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Result_Code, &avp) );
1150        ASSERT( avp ); /* otherwise the message should have been discarded a lot earlier because of ABNF */
1151        CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1152        switch (ahdr->avp_value->u32) {
1153                case ER_DIAMETER_MULTI_ROUND_AUTH:
1154                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_CHALLENGE;
1155                        break;
1156                case ER_DIAMETER_SUCCESS:
1157                case ER_DIAMETER_LIMITED_SUCCESS:
1158                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_ACCEPT;
1159                        break;
1160               
1161                default:
1162                        /* Can we convert the value to a natural Error-Cause ? */
1163                        switch (ahdr->avp_value->u32) {
1164                                case ER_DIAMETER_AVP_UNSUPPORTED:
1165                                        error_cause = 401; /* Unsupported Attribute */
1166                                        break;
1167                                       
1168                                case ER_DIAMETER_MISSING_AVP:
1169                                        error_cause = 402; /* Missing Attribute */
1170                                        break;
1171                                       
1172                                case ER_DIAMETER_UNABLE_TO_COMPLY:
1173                                        error_cause = 404; /* Invalid Request */
1174                                        break;
1175                                       
1176                                case ER_DIAMETER_APPLICATION_UNSUPPORTED:
1177                                        error_cause = 405; /* Unsupported Service */
1178                                        break;
1179                                       
1180                                case ER_DIAMETER_COMMAND_UNSUPPORTED:
1181                                        error_cause = 406; /* Unsupported Extension */
1182                                        break;
1183                                       
1184                                case ER_DIAMETER_INVALID_AVP_VALUE:
1185                                        error_cause = 407; /* Invalid Attribute Value */
1186                                        break;
1187                                       
1188                                case ER_DIAMETER_AVP_NOT_ALLOWED:
1189                                        error_cause = 501; /* Administratively Prohibited */
1190                                        break;
1191                                       
1192                                case ER_DIAMETER_REALM_NOT_SERVED:
1193                                case ER_DIAMETER_LOOP_DETECTED:
1194                                case ER_DIAMETER_UNKNOWN_PEER:
1195                                case ER_DIAMETER_UNABLE_TO_DELIVER:
1196                                        error_cause = 502; /* Request Not Routable (Proxy) */
1197                                        break;
1198                                       
1199                                case ER_DIAMETER_UNKNOWN_SESSION_ID:
1200                                        error_cause = 503; /* Session Context Not Found */
1201                                        break;
1202                                       
1203                                case ER_DIAMETER_TOO_BUSY:
1204                                case ER_DIAMETER_OUT_OF_SPACE:
1205                                        error_cause = 506; /* Resources Unavailable */
1206                                        break;
1207                                       
1208#if 0
1209                        /* remaining Diameter Result-Code & RADIUS Error-Cause */
1210                                case ER_DIAMETER_REDIRECT_INDICATION:
1211                                case ER_DIAMETER_INVALID_HDR_BITS:
1212                                case ER_DIAMETER_INVALID_AVP_BITS:
1213                                case ER_DIAMETER_AUTHENTICATION_REJECTED:
1214                                case ER_ELECTION_LOST:
1215                                case ER_DIAMETER_AUTHORIZATION_REJECTED:
1216                                case ER_DIAMETER_RESOURCES_EXCEEDED:
1217                                case ER_DIAMETER_CONTRADICTING_AVPS:
1218                                case ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES
1219                                case ER_DIAMETER_NO_COMMON_APPLICATION:
1220                                case ER_DIAMETER_UNSUPPORTED_VERSION:
1221                                case ER_DIAMETER_INVALID_BIT_IN_HEADER:
1222                                case ER_DIAMETER_INVALID_AVP_LENGTH:
1223                                case ER_DIAMETER_INVALID_MESSAGE_LENGTH:
1224                                case ER_DIAMETER_INVALID_AVP_BIT_COMBO:
1225                                case ER_DIAMETER_NO_COMMON_SECURITY:
1226                                        error_cause = 403; /* NAS Identification Mismatch */
1227                                        error_cause = 504; /* Session Context Not Removable */
1228                                        error_cause = 505; /* Other Proxy Processing Error */
1229                                        error_cause = 507; /* Request Initiated */
1230                                        error_cause = 508; /* Multiple Session Selection Unsupported */
1231#endif /* 0 */
1232                        }
1233                        /* In any case, the following is processed: */
1234                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_REJECT;
1235                        fd_log_debug("[auth.rgwx] Received Diameter answer with error code '%d' from server '%.*s', session %.*s, translating into Access-Reject\n",
1236                                        ahdr->avp_value->u32, 
1237                                        oh->avp_value->os.len, oh->avp_value->os.data,
1238                                        sid->avp_value->os.len, sid->avp_value->os.data);
1239                        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Error_Message, &avp_x) );
1240                        if (avp_x) {
1241                                CHECK_FCT( fd_msg_avp_hdr ( avp_x, &ahdr ) );
1242                                fd_log_debug("[auth.rgwx]   Error-Message content: '%.*s'\n",
1243                                                ahdr->avp_value->os.len, ahdr->avp_value->os.data);
1244                        }
1245                        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Error_Reporting_Host, &avp_x) );
1246                        if (avp_x) {
1247                                CHECK_FCT( fd_msg_avp_hdr ( avp_x, &ahdr ) );
1248                                fd_log_debug("[auth.rgwx]   Error-Reporting-Host: '%.*s'\n",
1249                                                ahdr->avp_value->os.len, ahdr->avp_value->os.data);
1250                        }
1251                        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Failed_AVP, &avp_x) );
1252                        if (avp_x) {
1253                                fd_log_debug("[auth.rgwx]   Failed-AVP was included in the message.\n");
1254                                /* Dump its content ? */
1255                        }
1256        }
1257        /* Remove this Result-Code avp */
1258        CHECK_FCT( fd_msg_free( avp ) );
1259       
1260        /* Creation of the State or Class attribute with session information */
1261        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Realm, &avp) );
1262        CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1263       
1264        /* Now, save the session-id and eventually server info in a STATE or CLASS attribute */
1265        if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE) {
1266                if (sizeof(buf) < (sz = snprintf((char *)buf, sizeof(buf), "Diameter/%.*s/%.*s/%.*s", 
1267                                (int)oh->avp_value->os.len,  (char *)oh->avp_value->os.data,
1268                                (int)ahdr->avp_value->os.len,  (char *)ahdr->avp_value->os.data,
1269                                (int)sid->avp_value->os.len, (char *)sid->avp_value->os.data))) {
1270                        TRACE_DEBUG(INFO, "Data truncated in State attribute: %s", buf);
1271                }
1272                CONV2RAD_STR(RADIUS_ATTR_STATE, buf, sz, 0);
1273        }
1274
1275        if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
1276                /* Add the Session-Id */
1277                if (sizeof(buf) < (sz = snprintf((char *)buf, sizeof(buf), "Diameter/%.*s", 
1278                                (int)sid->avp_value->os.len, sid->avp_value->os.data))) {
1279                        TRACE_DEBUG(INFO, "Data truncated in Class attribute: %s", buf);
1280                }
1281                CONV2RAD_STR(RADIUS_ATTR_CLASS, buf, sz, 0);
1282        }
1283       
1284        /* Unlink the Origin-Realm now; the others are unlinked at the end of this function */
1285        CHECK_FCT( fd_msg_free( avp ) );
1286       
1287        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Session_Timeout, &avp) );
1288        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Authorization_Lifetime, &avp_x) );
1289        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Re_Auth_Request_Type, &avp_y) );
1290        /*     
1291           When translating a Diameter AA-Answer (with successful result code)
1292           to RADIUS Access-Accept that contains a Session-Timeout or
1293           Authorization-Lifetime AVP, take the following steps:
1294           
1295              -  If the Diameter message contains a Session-Timeout AVP but no
1296                 Authorization-Lifetime AVP, translate it to a Session-Timeout
1297                 attribute (not a Termination-Action).
1298        */
1299        if ((avp != NULL) && (avp_x == NULL)) {
1300                CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1301                CONV2RAD_32B( RADIUS_ATTR_SESSION_TIMEOUT, ahdr->avp_value->u32 );
1302        }
1303       
1304        /*     
1305              -  If the Diameter message contains an Authorization-Lifetime AVP
1306                 but no Session-Timeout AVP, translate it to a Session-Timeout
1307                 attribute and a Termination-Action set to AA-REQUEST.  (Remove
1308                 Authorization-Lifetime and Re-Auth-Request-Type.)
1309        */
1310        if ((avp == NULL) && (avp_x != NULL)) {
1311                CHECK_FCT( fd_msg_avp_hdr ( avp_x, &ahdr ) );
1312                CONV2RAD_32B( RADIUS_ATTR_SESSION_TIMEOUT, ahdr->avp_value->u32 );
1313                CONV2RAD_32B( RADIUS_ATTR_TERMINATION_ACTION, RADIUS_TERMINATION_ACTION_RADIUS_REQUEST );
1314                ta_set = 1;
1315        }
1316       
1317        /*     
1318              -  If the Diameter message has both, the Session-Timeout must be
1319                 greater than or equal to the Authorization-Lifetime (required
1320                 by [BASE]).  Translate it to a Session-Timeout value (with
1321                 value from Authorization-Lifetime AVP, the smaller one) and
1322                 with the Termination-Action set to AA-REQUEST.  (Remove the
1323                 Authorization-Lifetime and Re-Auth-Request-Type.)
1324        */
1325        if ((avp != NULL) && (avp_x != NULL)) {
1326                CHECK_FCT( fd_msg_avp_hdr ( avp_x, &ahdr ) );
1327                CONV2RAD_32B( RADIUS_ATTR_SESSION_TIMEOUT, ahdr->avp_value->u32 );
1328                CONV2RAD_32B( RADIUS_ATTR_TERMINATION_ACTION, RADIUS_TERMINATION_ACTION_RADIUS_REQUEST );
1329                ta_set = 1;
1330        }
1331       
1332        /*  -> Not too sure about Auth-Grace-Period... we'll just discard it for now */
1333       
1334        if (avp) {
1335                CHECK_FCT( fd_msg_free( avp ) );
1336        }
1337        if (avp_x) {
1338                CHECK_FCT( fd_msg_free( avp_x ) );
1339        }
1340        if (avp_y) {
1341                CHECK_FCT( fd_msg_free( avp_y ) );
1342        }
1343       
1344       
1345        /*
1346              -  If a Proxy-State attribute was present in the RADIUS request,
1347                 the same attribute is added in the response.  This information
1348                 may be found in the Proxy-Info AVP group, or in a local state
1349                 table.
1350                        -> handled by sub_echo_drop
1351
1352              -  If state information regarding the RADIUS request was saved in
1353                 a Proxy-Info AVP or local state table, the RADIUS Identifier
1354                 and UDP IP Address and port number are extracted and used in
1355                 issuing the RADIUS reply.
1356                        -> was saved with the full request
1357        */
1358       
1359       
1360        /* Now loop in the list of AVPs and convert those that we know how */
1361        CHECK_FCT( fd_msg_browse(*diam_ans, MSG_BRW_FIRST_CHILD, &next, NULL) );
1362       
1363        while (next) {
1364                int handled = 1;
1365                avp = next;
1366                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &next, NULL) );
1367               
1368                CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1369               
1370                if (!(ahdr->avp_flags & AVP_FLAG_VENDOR)) {
1371                        switch (ahdr->avp_code) {
1372                /* In case of Diameter error, include the Reply-Message attribute */
1373                                case DIAM_ATTR_ERROR_MESSAGE:
1374                                        CONV2RAD_STR(RADIUS_ATTR_REPLY_MESSAGE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1375                                        break;
1376                                       
1377                                case DIAM_ATTR_ERROR_REPORTING_HOST:
1378                                        {
1379                                                char buf[254];
1380                                                int bsz = snprintf(buf, sizeof(buf), "Error-Reporting-Host: %*s", (int)(ahdr->avp_value->os.len), ahdr->avp_value->os.data);
1381                                                CONV2RAD_STR(RADIUS_ATTR_REPLY_MESSAGE, (uint8_t *)buf, bsz, 2);
1382                                        }
1383                                        break;
1384                               
1385                                case DIAM_ATTR_FAILED_AVP:
1386                                        {
1387                                                struct avp * favp;
1388                                                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &favp, NULL) );
1389                                                if (favp) {
1390                                                        char buf[254];
1391                                                        int bsz;
1392                                                        struct dict_object * favp_model;
1393                                                       
1394                                                        CHECK_FCT( fd_msg_model(favp, &favp_model) );
1395                                                        if (favp_model) {
1396                                                                struct dict_avp_data fadata;
1397                                                                CHECK_FCT( fd_dict_getval(favp_model, &fadata) );
1398                                                                bsz = snprintf(buf, sizeof(buf), "Failed-AVP: %s", fadata.avp_name);
1399                                                        } else {
1400                                                                struct avp_hdr * favp_hdr;
1401                                                                CHECK_FCT( fd_msg_avp_hdr ( favp, &favp_hdr ) );
1402                                                                bsz = snprintf(buf, sizeof(buf), "Failed-AVP: code %u, vendor %u", favp_hdr->avp_code, favp_hdr->avp_vendor);
1403                                                        }
1404                                                        CONV2RAD_STR(RADIUS_ATTR_REPLY_MESSAGE, (uint8_t *)buf, bsz, 2);
1405                                                }
1406                                        }
1407                                        break;
1408                                       
1409                /* RFC 4005 (AVP in the order of the AA-Request/Answer AVP Table) */
1410                                case DIAM_ATTR_ACCT_INTERIM_INTERVAL:
1411                                        CONV2RAD_32B(RADIUS_ATTR_ACCT_INTERIM_INTERVAL, ahdr->avp_value->u32);
1412                                        break;
1413                                       
1414                                case DIAM_ATTR_ARAP_CHALLENGE_RESPONSE:
1415                                        CONV2RAD_STR(RADIUS_ATTR_ARAP_CHALLENGE_RESPONSE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1416                                        break;
1417                                       
1418                                case DIAM_ATTR_ARAP_FEATURES:
1419                                        CONV2RAD_STR(RADIUS_ATTR_ARAP_FEATURES, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1420                                        break;
1421                                       
1422                                /* ARAP-Password is not present in answers */
1423                                       
1424                                case DIAM_ATTR_ARAP_SECURITY:
1425                                        CONV2RAD_32B(RADIUS_ATTR_ARAP_SECURITY, ahdr->avp_value->u32);
1426                                        break;
1427                                       
1428                                case DIAM_ATTR_ARAP_SECURITY_DATA:
1429                                        CONV2RAD_STR(RADIUS_ATTR_ARAP_SECURITY_DATA, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1430                                        break;
1431                                       
1432                                case DIAM_ATTR_ARAP_ZONE_ACCESS:
1433                                        CONV2RAD_32B(RADIUS_ATTR_ARAP_ZONE_ACCESS, ahdr->avp_value->u32);
1434                                        break;
1435                                       
1436                                case DIAM_ATTR_AUTH_APPLICATION_ID:
1437                                        /* We just remove this AVP */
1438                                        break;
1439                                       
1440                                case DIAM_ATTR_AUTH_GRACE_PERIOD:
1441                                        /* We just remove this AVP (?) */
1442                                        break;
1443                               
1444                                case DIAM_ATTR_AUTH_REQUEST_TYPE:
1445                                        /* We only check the value */
1446                                        if (ahdr->avp_value->u32 != 3) {
1447                                                fd_log_debug("[auth.rgwx] Received Diameter answer with Auth-Request-Type set to %d (%s) from server %.*s, session %.*s.\n"
1448                                                                "  This may cause interoperability problems with RADIUS.\n",
1449                                                                ahdr->avp_value->u32,
1450                                                                (ahdr->avp_value->u32 == 1) ? "AUTHENTICATE_ONLY" :
1451                                                                        ((ahdr->avp_value->u32 == 2) ? "AUTHORIZE_ONLY" : "???"),
1452                                                                oh->avp_value->os.len, oh->avp_value->os.data, 
1453                                                                sid->avp_value->os.len, sid->avp_value->os.len);
1454                                        }
1455                                        break;
1456                               
1457                                case DIAM_ATTR_AUTH_SESSION_STATE:
1458                                        if ((!ta_set) && (ahdr->avp_value->u32 == ACV_ASS_STATE_MAINTAINED)) {
1459                                                CONV2RAD_32B( RADIUS_ATTR_TERMINATION_ACTION, RADIUS_TERMINATION_ACTION_RADIUS_REQUEST );
1460                                        }
1461                                       
1462                                        if (ahdr->avp_value->u32 == ACV_ASS_NO_STATE_MAINTAINED) {
1463                                                no_str = 1;
1464                                        }
1465                                        break;
1466                                       
1467                                /* Authorization-Lifetime already handled */
1468                               
1469                                case DIAM_ATTR_CALLBACK_ID:
1470                                        CONV2RAD_STR(RADIUS_ATTR_CALLBACK_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1471                                        break;
1472                               
1473                                case DIAM_ATTR_CALLBACK_NUMBER:
1474                                        CONV2RAD_STR(RADIUS_ATTR_CALLBACK_NUMBER, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1475                                        break;
1476                               
1477                                /* Called-Station-Id is not present in answers */
1478                                /* Calling-Station-Id is not present in answers */
1479                                /* CHAP-Auth is not present in answers */
1480                                /* CHAP-Challenge is not present in answers */
1481                                       
1482                                case DIAM_ATTR_CLASS:
1483                                        CONV2RAD_STR(RADIUS_ATTR_CLASS, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1484                                        break;
1485                               
1486                                case DIAM_ATTR_CONFIGURATION_TOKEN:
1487                                        /* We might as well remove it since it's not supposed to be sent to the NAS... */
1488                                        CONV2RAD_STR(RADIUS_ATTR_CONFIGURATION_TOKEN, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1489                                        break;
1490                               
1491                                /* Connect-Info is not present in answers */
1492                               
1493                                case DIAM_ATTR_FILTER_ID:
1494                                        CONV2RAD_STR(RADIUS_ATTR_FILTER_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1495                                        break;
1496                                       
1497                                case DIAM_ATTR_FRAMED_APPLETALK_LINK:
1498                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_APPLETALK_LINK, ahdr->avp_value->u32);
1499                                        break;
1500                                       
1501                                case DIAM_ATTR_FRAMED_APPLETALK_NETWORK:
1502                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_APPLETALK_NETWORK, ahdr->avp_value->u32);
1503                                        break;
1504                                       
1505                                case DIAM_ATTR_FRAMED_APPLETALK_ZONE:
1506                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_APPLETALK_ZONE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1507                                        break;
1508                                       
1509                                case DIAM_ATTR_FRAMED_COMPRESSION:
1510                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_COMPRESSION,  ahdr->avp_value->u32);
1511                                        break;
1512                                       
1513                                case DIAM_ATTR_FRAMED_INTERFACE_ID:
1514                                        CONV2RAD_64B(RADIUS_ATTR_FRAMED_INTERFACE_ID,  ahdr->avp_value->u64);
1515                                        break;
1516                                       
1517                                case DIAM_ATTR_FRAMED_IP_ADDRESS:
1518                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IP_ADDRESS,  ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1519                                        break;
1520                                       
1521                                case DIAM_ATTR_FRAMED_IP_NETMASK:
1522                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IP_NETMASK, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1523                                        break;
1524                                       
1525                                case DIAM_ATTR_FRAMED_IPV6_PREFIX:
1526                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IPV6_PREFIX, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1527                                        break;
1528                                       
1529                                case DIAM_ATTR_FRAMED_IPV6_POOL:
1530                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IPV6_POOL, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1531                                        break;
1532                                       
1533                                case DIAM_ATTR_FRAMED_IPV6_ROUTE:
1534                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IPV6_ROUTE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1535                                        break;
1536                                       
1537                                case DIAM_ATTR_FRAMED_IPX_NETWORK:
1538                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_IPX_NETWORK, ahdr->avp_value->u32);
1539                                        break;
1540                                       
1541                                case DIAM_ATTR_FRAMED_MTU:
1542                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_MTU, ahdr->avp_value->u32);
1543                                        break;
1544                                       
1545                                case DIAM_ATTR_FRAMED_POOL:
1546                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_POOL, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1547                                        break;
1548                                       
1549                                case DIAM_ATTR_FRAMED_PROTOCOL:
1550                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_PROTOCOL, ahdr->avp_value->u32);
1551                                        break;
1552                                       
1553                                case DIAM_ATTR_FRAMED_ROUTE:
1554                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_ROUTE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1555                                        break;
1556                                       
1557                                case DIAM_ATTR_FRAMED_ROUTING:
1558                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_ROUTING, ahdr->avp_value->u32);
1559                                        break;
1560                                       
1561                                case DIAM_ATTR_IDLE_TIMEOUT:
1562                                        CONV2RAD_32B(RADIUS_ATTR_IDLE_TIMEOUT, ahdr->avp_value->u32);
1563                                        break;
1564                                       
1565                                case DIAM_ATTR_LOGIN_IP_HOST:
1566                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_IP_HOST, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1567                                        break;
1568                                       
1569                                case DIAM_ATTR_LOGIN_IPV6_HOST:
1570                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_IPV6_HOST, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1571                                        break;
1572                                       
1573                                case DIAM_ATTR_LOGIN_LAT_GROUP:
1574                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_LAT_GROUP, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1575                                        break;
1576                                       
1577                                case DIAM_ATTR_LOGIN_LAT_NODE:
1578                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_LAT_NODE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1579                                        break;
1580                                       
1581                                case DIAM_ATTR_LOGIN_LAT_PORT:
1582                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_LAT_PORT, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1583                                        break;
1584                                       
1585                                case DIAM_ATTR_LOGIN_LAT_SERVICE:
1586                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_LAT_SERVICE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1587                                        break;
1588                                       
1589                                case DIAM_ATTR_LOGIN_SERVICE:
1590                                        CONV2RAD_32B(RADIUS_ATTR_LOGIN_SERVICE, ahdr->avp_value->u32);
1591                                        break;
1592                                       
1593                                case DIAM_ATTR_LOGIN_TCP_PORT:
1594                                        CONV2RAD_32B(RADIUS_ATTR_LOGIN_TCP_PORT, ahdr->avp_value->u32);
1595                                        break;
1596                                       
1597                        /*
1598                              -                                                         If the
1599                                 Multi-Round-Time-Out AVP is present, the value of the AVP MUST
1600                                 be inserted in the RADIUS Session-Timeout AVP.
1601
1602                              o  As described in [NASREQ], if the Result-Code AVP set to
1603                                 DIAMETER_MULTI_ROUND_AUTH and the Multi-Round-Time-Out AVP is
1604                                 present, it is translated to the RADIUS Session-Timeout attribute.
1605                        */
1606                                case DIAM_ATTR_MULTI_ROUND_TIMEOUT:
1607                                        CONV2RAD_32B(RADIUS_ATTR_SESSION_TIMEOUT, ahdr->avp_value->u32);
1608                                        break;
1609                                       
1610                                case DIAM_ATTR_NAS_FILTER_RULE:
1611                                        /* This is not translatable to RADIUS */
1612                                        fd_log_debug("[auth.rgwx] Received Diameter answer with non-translatable NAS-Filter-Rule AVP from '%.*s' (session: '%.*s'), ignoring.\n",
1613                                                        oh->avp_value->os.len, oh->avp_value->os.data,
1614                                                        sid->avp_value->os.len, sid->avp_value->os.data);
1615                                        handled = 0;
1616                                        break;
1617                                       
1618                                /* NAS-Identifier is not present in answers */
1619                                /* NAS-IP-Address is not present in answers */
1620                                /* NAS-IPv6-Address is not present in answers */
1621                                /* NAS-Port is not present in answers */
1622                                /* NAS-Port-Id is not present in answers */
1623                                /* NAS-Port-Type is not present in answers */
1624                               
1625                                case DIAM_ATTR_ORIGIN_AAA_PROTOCOL:
1626                                        /* We just remove this AVP */
1627                                        break;
1628                                       
1629                                /* Originating-Line-Info is not present in answers */
1630                               
1631                                case DIAM_ATTR_PASSWORD_RETRY:
1632                                        CONV2RAD_32B(RADIUS_ATTR_PASSWORD_RETRY, ahdr->avp_value->u32);
1633                                        break;
1634                               
1635                                case DIAM_ATTR_PORT_LIMIT:
1636                                        CONV2RAD_32B(RADIUS_ATTR_PORT_LIMIT, ahdr->avp_value->u32);
1637                                        break;
1638                               
1639                                case DIAM_ATTR_PROMPT:
1640                                        CONV2RAD_32B(RADIUS_ATTR_PROMPT, ahdr->avp_value->u32);
1641                                        break;
1642                                       
1643                                case DIAM_ATTR_QOS_FILTER_RULE:
1644                                        /* This is not translatable to RADIUS */
1645                                        fd_log_debug("[auth.rgwx] Received Diameter answer with non-translatable QoS-Filter-Rule AVP from '%.*s' (session: '%.*s'), ignoring.\n",
1646                                                        oh->avp_value->os.len, oh->avp_value->os.data,
1647                                                        sid->avp_value->os.len, sid->avp_value->os.data);
1648                                        handled = 0;
1649                                        break;
1650                                       
1651                                /* Re-Auth-Request-Type already handled */
1652                               
1653                                case DIAM_ATTR_REPLY_MESSAGE:
1654                                        CONV2RAD_STR(RADIUS_ATTR_REPLY_MESSAGE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1655                                        break;
1656                                       
1657                                case DIAM_ATTR_SERVICE_TYPE:
1658                                        CONV2RAD_32B(RADIUS_ATTR_SERVICE_TYPE, ahdr->avp_value->u32);
1659                                        break;
1660                               
1661                                case DIAM_ATTR_STATE:
1662                                        CONV2RAD_STR(RADIUS_ATTR_STATE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1663                                        break;
1664                                       
1665                                case DIAM_ATTR_TUNNELING:
1666                                        {
1667#define CONV2RAD_TUN_STR( _attr_, _data_, _len_, _trunc_)       {                               \
1668        size_t __l = (size_t)(_len_);                                                           \
1669        size_t __w = (__l > 252) ? 252 : __l;                                                   \
1670        size_t __off = 0;                                                                       \
1671        if ((_trunc_) == 0) {                                                                   \
1672                CHECK_PARAMS( __l <= 252 );                                                     \
1673        }                                                                                       \
1674        if ((__l > 252) && (_trunc_ == 1)) {                                                    \
1675                TRACE_DEBUG(FULL, "Attribute truncated!");                                      \
1676                __l = 252;                                                                      \
1677        }                                                                                       \
1678        buf[0] = tuntag;                                                                        \
1679        memcpy(&buf[1], (_data_), __w);                                                         \
1680        CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), &buf[0], __w + 1));                 \
1681        while (__l -= __w) {                                                                    \
1682                __off += __w;                                                                   \
1683                __w = (__l > 253) ? 253 : __l;                                                  \
1684                CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (_data_) + __off, __w));    \
1685        }                                                                                       \
1686}
1687
1688#define CONV2RAD_TUN_32B( _attr_, _data_)       {                                               \
1689        uint32_t __v = htonl((uint32_t)(_data_) | (tuntag << 24));                              \
1690        CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (uint8_t *)&__v, sizeof(__v)));     \
1691}
1692                                                struct avp *inavp, *innext;
1693                                                tuntag++;
1694                                                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &innext, NULL) );
1695                                                while (innext) {
1696                                                        inavp = innext;
1697                                                        CHECK_FCT( fd_msg_browse(inavp, MSG_BRW_NEXT, &innext, NULL) );
1698                                                        CHECK_FCT( fd_msg_avp_hdr ( inavp, &ahdr ) );
1699                                                       
1700                                                        if ( ! (ahdr->avp_flags & AVP_FLAG_VENDOR)) {
1701                                                                switch (ahdr->avp_code) {
1702                                                                        case DIAM_ATTR_TUNNEL_TYPE:
1703                                                                                CONV2RAD_TUN_32B( RADIUS_ATTR_TUNNEL_TYPE, ahdr->avp_value->u32);
1704                                                                                break;
1705                                                                               
1706                                                                        case DIAM_ATTR_TUNNEL_MEDIUM_TYPE:
1707                                                                                CONV2RAD_TUN_32B( RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, ahdr->avp_value->u32);
1708                                                                                break;
1709                                                                               
1710                                                                        case DIAM_ATTR_TUNNEL_CLIENT_ENDPOINT:
1711                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_CLIENT_ENDPOINT, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1712                                                                                break;
1713                                                                               
1714                                                                        case DIAM_ATTR_TUNNEL_SERVER_ENDPOINT:
1715                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_SERVER_ENDPOINT, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1716                                                                                break;
1717                                                                               
1718                                                                        case DIAM_ATTR_TUNNEL_PREFERENCE:
1719                                                                                CONV2RAD_TUN_32B( RADIUS_ATTR_TUNNEL_PREFERENCE, ahdr->avp_value->u32);
1720                                                                                break;
1721                                                                               
1722                                                                        case DIAM_ATTR_TUNNEL_CLIENT_AUTH_ID:
1723                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_CLIENT_AUTH_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1724                                                                                break;
1725                                                                               
1726                                                                        case DIAM_ATTR_TUNNEL_SERVER_AUTH_ID:
1727                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_SERVER_AUTH_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1728                                                                                break;
1729                                                                               
1730                                                                        case DIAM_ATTR_TUNNEL_ASSIGNMENT_ID:
1731                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_ASSIGNMENT_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1732                                                                                break;
1733                                                                               
1734                                                                        case DIAM_ATTR_TUNNEL_PASSWORD:
1735                                                                                {
1736                                                                                        /* This AVP must be encoded for RADIUS (similar to radius_msg_add_attr_user_password)
1737                                                                                            0                   1                   2                   3
1738                                                                                            0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1739                                                                                           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1740                                                                                           |     Type      |    Length     |     Tag       |   Salt
1741                                                                                           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1742                                                                                              Salt (cont)  |   String ...
1743                                                                                           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1744                                                                                        */
1745                                                                                        size_t pos;
1746                                                                                        int i;
1747                                                                                        uint8_t * secret;       /* S */
1748                                                                                        size_t secret_len;
1749                                                                                        uint8_t hash[16];       /* b(i) */
1750                                                                                        const uint8_t *addr[3];
1751                                                                                        size_t len[3];
1752                                                                                       
1753                                                                                        /* We need the request authenticator */
1754                                                                                        CHECK_PARAMS(req_auth);
1755
1756                                                                                        /* Retrieve the shared secret */
1757                                                                                        CHECK_FCT(rgw_clients_getkey(cli, &secret, &secret_len));
1758                                                                                       
1759                                                                                        /* Beginning of the buffer */
1760                                                                                        buf[0] = tuntag;
1761                                                                                        buf[1] = (uint8_t)(lrand48()); /* A (hi bits) */
1762                                                                                        buf[2] = (uint8_t)(lrand48()); /* A (low bits) */
1763                                                                                       
1764                                                                                        /* The plain text string P */
1765                                                                                        CHECK_PARAMS(ahdr->avp_value->os.len < 240);
1766                                                                                        buf[3] = ahdr->avp_value->os.len;
1767                                                                                        memcpy(&buf[4], ahdr->avp_value->os.data, ahdr->avp_value->os.len);
1768                                                                                        memset(&buf[4 + ahdr->avp_value->os.len], 0, sizeof(buf) - 4 - ahdr->avp_value->os.len);
1769                                                                                       
1770                                                                                        /* Initial b1 = MD5(S + R + A) */
1771                                                                                        addr[0] = secret;
1772                                                                                        len[0] = secret_len;
1773                                                                                        addr[1] = req_auth;
1774                                                                                        len[1] = 16;
1775                                                                                        addr[2] = &buf[1];
1776                                                                                        len[2] = 2;
1777                                                                                        md5_vector(3, addr, len, hash);
1778                                                                                       
1779                                                                                        /* Initial c(1) = p(1) xor b(1) */
1780                                                                                        for (i = 0; i < 16; i++) {
1781                                                                                                buf[i + 3] ^= hash[i];
1782                                                                                        }
1783                                                                                        pos = 16;
1784                                                                                       
1785                                                                                        /* loop */
1786                                                                                        while (pos < ahdr->avp_value->os.len + 1) {
1787                                                                                                addr[0] = secret;
1788                                                                                                len[0] = secret_len;
1789                                                                                                addr[1] = &buf[pos - 13];
1790                                                                                                len[1] = 16;
1791                                                                                                /* b(i) = MD5( S + c(i-1) */
1792                                                                                                md5_vector(2, addr, len, hash);
1793                                                                                               
1794                                                                                                /* c(i) = p(i) xor b(i) */
1795                                                                                                for (i = 0; i < 16; i++)
1796                                                                                                        buf[pos + i + 3] ^= hash[i];
1797
1798                                                                                                pos += 16;
1799                                                                                        }
1800                                                                                       
1801                                                                                        CONV2RAD_STR(RADIUS_ATTR_TUNNEL_PASSWORD, &buf[0], pos + 3, 0);
1802                                                                                }
1803                                                                                break;
1804                                                                               
1805                                                                        case DIAM_ATTR_TUNNEL_PRIVATE_GROUP_ID:
1806                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1807                                                                                break;
1808                                                                       
1809                                                                        default:
1810                                                                                TRACE_DEBUG(FULL, "Ignored unknown AVP inside Tunneling AVP (%d)", ahdr->avp_code);
1811                                                                }
1812                                                        } else {
1813                                                                TRACE_DEBUG(FULL, "Ignored unknown Vendor AVP inside Tunneling AVP (%d, %d)", ahdr->avp_vendor, ahdr->avp_code);
1814                                                        }
1815                                                }
1816                                        }
1817                                        break;
1818                                       
1819                                case DIAM_ATTR_USER_NAME:
1820                                        CONV2RAD_STR(RADIUS_ATTR_USER_NAME, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1821                                        break;
1822                               
1823                                /* User-Password never present in answers */
1824                                       
1825                /* RFC 4072 (AVP in the order of the EAP Command AVP Table) */
1826                        /*
1827                              o  Diameter Accounting-EAP-Auth-Method AVPs, if present, are
1828                                 discarded.
1829                        */
1830                                case DIAM_ATTR_ACCOUNTING_EAP_AUTH_METHOD:
1831                                        break;
1832                                       
1833                        /*
1834                              o  Diameter EAP-Master-Session-Key AVP can be translated to the
1835                                 vendor-specific RADIUS MS-MPPE-Recv-Key and MS-MPPE-Send-Key
1836                                 attributes [RFC2548].  The first up to 32 octets of the key is
1837                                 stored into MS-MPPE-Recv-Key, and the next up to 32 octets (if
1838                                 present) are stored into MS-MPPE-Send-Key.  The encryption of this
1839                                 attribute is described in [RFC2548].
1840                        */
1841                                case DIAM_ATTR_EAP_MASTER_SESSION_KEY:
1842                                        {
1843                                                uint8_t * secret;       /* S */
1844                                                size_t secret_len;
1845                                                size_t recv_len, send_len;
1846
1847                                                /* We need the request authenticator */
1848                                                CHECK_PARAMS(req_auth);
1849
1850                                                /* Retrieve the shared secret */
1851                                                CHECK_FCT(rgw_clients_getkey(cli, &secret, &secret_len));
1852                                               
1853                                                if (ahdr->avp_value->os.len != 64) {
1854                                                        TRACE_DEBUG(INFO, "Received EAP-Master-Session-Key attribute with length %d != 64.\n", ahdr->avp_value->os.len)
1855                                                }
1856                                               
1857                                                CHECK_PARAMS(ahdr->avp_value->os.len <= 64);
1858                                                recv_len = ahdr->avp_value->os.len >= 32 ? 32 : ahdr->avp_value->os.len;
1859                                                send_len = ahdr->avp_value->os.len - recv_len;
1860                                               
1861                                                if ( ! radius_msg_add_mppe_keys(*rad_fw, req_auth, secret, secret_len, 
1862                                                                ahdr->avp_value->os.data + recv_len, send_len,
1863                                                                ahdr->avp_value->os.data, recv_len) ) {
1864                                                        TRACE_DEBUG(INFO, "Error while converting EAP-Master-Session-Key to RADIUS message");
1865                                                        return ENOMEM;
1866                                                }
1867                                        }
1868                                        break;
1869                               
1870                                case DIAM_ATTR_EAP_KEY_NAME:
1871                                        CONV2RAD_STR(RADIUS_ATTR_EAP_KEY_NAME, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1872                                        break;
1873                               
1874                        /*
1875                              o  Diameter EAP-Payload AVP is translated to RADIUS EAP-Message
1876                                 attribute(s).  If necessary, the value is split into multiple
1877                                 RADIUS EAP-Message attributes.
1878                        */
1879                                case DIAM_ATTR_EAP_PAYLOAD:
1880                                        if ( ! radius_msg_add_eap(*rad_fw, ahdr->avp_value->os.data, ahdr->avp_value->os.len) ) {
1881                                                TRACE_DEBUG(INFO, "Error while converting EAP payload to RADIUS message");
1882                                                return ENOMEM;
1883                                        }
1884                                        break;
1885                                       
1886                        /*
1887                              o  Diameter EAP-Reissued-Payload AVP is translated to a message that
1888                                 contains RADIUS EAP-Message attribute(s), and a RADIUS Error-Cause
1889                                 attribute [RFC3576] with value 202 (decimal), "Invalid EAP Packet
1890                                 (Ignored)" [RFC3579].
1891                        */
1892                                case DIAM_ATTR_EAP_REISSUED_PAYLOAD:
1893                                        if ( ! radius_msg_add_eap(*rad_fw, ahdr->avp_value->os.data, ahdr->avp_value->os.len) ) {
1894                                                TRACE_DEBUG(INFO, "Error while converting EAP reissued payload to RADIUS message");
1895                                                return ENOMEM;
1896                                        }
1897                                       
1898                                        error_cause = 202; /* Invalid EAP Packet */
1899                                        break;
1900                       
1901                                default:
1902                                        /* Leave the AVP in the message for further treatment */
1903                                        handled = 0;
1904                        }
1905                } else {
1906                        /* Vendor-specific AVPs */
1907                        switch (ahdr->avp_vendor) {
1908                               
1909                                default: /* unknown vendor */
1910                                        handled = 0;
1911                        }
1912                }
1913               
1914                if (handled) {
1915                        CHECK_FCT( fd_msg_free( avp ) );
1916                }
1917        }
1918       
1919        CHECK_FCT( fd_msg_free( asid ) );
1920        CHECK_FCT( fd_msg_free( aoh ) );
1921        free(req_auth);
1922       
1923        if (error_cause) {
1924                if ( ! radius_msg_add_attr_int32(*rad_fw, RADIUS_ATTR_ERROR_CAUSE, error_cause) ) {
1925                        TRACE_DEBUG(INFO, "Error while adding Error-Cause attribute in RADIUS message");
1926                        return ENOMEM;
1927                }
1928        }               
1929
1930        if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
1931                /* Add the auth-application-id required for STR, or 0 if no STR is required */
1932                CHECK_FCT( fd_msg_hdr( *diam_ans, &hdr ) );
1933                if (sizeof(buf) < (sz = snprintf((char *)buf, sizeof(buf), CLASS_AAI_PREFIX "%u", 
1934                                no_str ? 0 : hdr->msg_appl))) {
1935                        TRACE_DEBUG(INFO, "Data truncated in Class attribute: %s", buf);
1936                }
1937                CONV2RAD_STR(RADIUS_ATTR_CLASS, buf, sz, 0);
1938        }
1939       
1940        return 0;
1941}
1942
1943/* The exported symbol */
1944struct rgw_api rgwp_descriptor = {
1945        .rgwp_name       = "auth",
1946        .rgwp_conf_parse = auth_conf_parse,
1947        .rgwp_conf_free  = auth_conf_free,
1948        .rgwp_rad_req    = auth_rad_req,
1949        .rgwp_diam_ans   = auth_diam_ans
1950};     
Note: See TracBrowser for help on using the repository browser.