Navigation


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

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

Large UNTESTED commit with the following changes:

  • Improved DiameterIdentity? handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7)
  • Cleanup in the session module to free only unreferenced sessions (#16)
  • Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
  • Improved peer state machine algorithm to counter SCTP multistream race condition.
File size: 77.5 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        os0_t dh = NULL;
242        size_t dh_len = 0;
243        os0_t dr = NULL;
244        size_t dr_len = 0;
245        os0_t si = NULL;
246        size_t si_len = 0;
247        os0_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_clients_create_origin.
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                os0_t sess_str = NULL;
456                size_t sess_strlen;
457               
458                if (si_len) {
459                        /* We already have the Session-Id, just use it */
460                        CHECK_FCT( fd_sess_fromsid ( si, si_len, session, NULL) );
461                } else {
462                        /* Create a new Session-Id string */
463                       
464                        DiamId_t fqdn;
465                        size_t fqdnlen;
466                        DiamId_t realm;
467                        size_t realmlen;
468                       
469                        /* Get information on the RADIUS client */
470                        CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &fqdnlen, &realm, &realmlen) );
471                       
472                        /* If we have a user name, create the new session with it */
473                        if (un) {
474                                int len;
475                                /* If not found, create a new Session-Id. Our format is: {fqdn;hi32;lo32;username;diamid} */
476                                CHECK_MALLOC( sess_str = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) );
477                                len = sprintf((char *)sess_str, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid);
478                                CHECK_FCT( fd_sess_new(session, fqdn, fqdnlen, sess_str, len) );
479                                free(sess_str);
480                        } else {
481                                /* We don't have enough information to create the Session-Id, the RADIUS message is probably invalid */
482                                TRACE_DEBUG(INFO, "RADIUS Access-Request does not contain a User-Name attribute, rejecting.");
483                                return EINVAL;
484                        }       
485                }
486               
487                /* Now, add the Session-Id AVP at beginning of Diameter message */
488                CHECK_FCT( fd_sess_getsid(*session, &sess_str, &sess_strlen) );
489               
490                TRACE_DEBUG(FULL, "[auth.rgwx] Translating new message for session '%s'...", sess_str);
491               
492                /* Add the Session-Id AVP as first AVP */
493                CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
494                value.os.data = sess_str;
495                value.os.len = sess_strlen;
496                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
497                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
498        }
499       
500       
501        /* Add the appropriate command code & Auth-Application-Id */
502        {
503                struct msg_hdr * header = NULL;
504                CHECK_FCT( fd_msg_hdr ( *diam_fw, &header ) );
505                header->msg_flags = CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE;
506                if (got_eap) {
507                        header->msg_code = CC_DIAMETER_EAP;
508                        header->msg_appl = AI_EAP;
509                } else {
510                        header->msg_code = CC_AA;
511                        header->msg_appl = AI_NASREQ;
512                }
513               
514                /* Add the Auth-Application-Id */
515                {
516                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Auth_Application_Id, 0, &avp ) );
517                        value.i32 = header->msg_appl;
518                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
519                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
520                }
521        }
522       
523        /*      The type of request is identified through the Auth-Request-Type AVP
524                [BASE].  The recommended value for most RADIUS interoperabily
525                situations is AUTHORIZE_AUTHENTICATE. */
526       
527        /* Add Auth-Request-Type AVP */
528        {
529                CHECK_FCT( fd_msg_avp_new ( cs->dict.Auth_Request_Type, 0, &avp ) );
530                value.i32 = ACV_ART_AUTHORIZE_AUTHENTICATE;
531                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
532                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
533        }
534       
535        /* Add Origin-AAA-Protocol AVP */
536        {
537                CHECK_FCT( fd_msg_avp_new ( cs->dict.Origin_AAA_Protocol, 0, &avp ) );
538                value.i32 = ACV_OAP_RADIUS;
539                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
540                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
541        }
542       
543        /* Convert the EAP payload (concat RADIUS attributes) */
544        if (got_eap) {
545                CHECK_FCT( fd_msg_avp_new ( cs->dict.EAP_Payload, 0, &avp ) );
546               
547                /*    o  An empty RADIUS EAP-Message attribute (with length 2) signifies
548                         EAP-Start, and it is translated to an empty EAP-Payload AVP. */
549                if (got_empty_eap) {
550                        value.os.len = 0;
551                        value.os.data = (uint8_t *)"";
552                } else {
553                        CHECK_MALLOC( value.os.data = radius_msg_get_eap(rad_req, &value.os.len) );
554                }
555               
556                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
557                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
558        }
559       
560        /* Tunnel AVPs need some preparation */
561        /* Convert the attributes one by one */
562        for (idx = 0; idx < rad_req->attr_used; idx++) {
563                struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
564
565                switch (attr->type) {
566                       
567                        /* This macro converts a RADIUS attribute to a Diameter AVP of type OctetString */
568                        #define CONV2DIAM_STR( _dictobj_ )      \
569                                CHECK_PARAMS( attr->length >= sizeof(struct radius_attr_hdr) );                 \
570                                /* Create the AVP with the specified dictionary model */                        \
571                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
572                                value.os.len = attr->length - sizeof(struct radius_attr_hdr);                   \
573                                value.os.data = (os0_t)(attr + 1);                                              \
574                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
575                                /* Add the AVP in the Diameter message. */                                      \
576                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
577                               
578                        /* Same thing, for scalar AVPs of 32 bits */
579                        #define CONV2DIAM_32B( _dictobj_ )      \
580                                CHECK_PARAMS( attr->length == sizeof(struct radius_attr_hdr)+sizeof(uint32_t) );\
581                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
582                                {                                                                               \
583                                        uint8_t * v = (uint8_t *)(attr + 1);                                    \
584                                        value.u32  = (v[0] << 24)                                               \
585                                                   | (v[1] << 16)                                               \
586                                                   | (v[2] <<  8)                                               \
587                                                   |  v[3] ;                                                    \
588                                }                                                                               \
589                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
590                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
591                               
592                        /* And the 64b version */
593                        #define CONV2DIAM_64B( _dictobj_ )      \
594                                CHECK_PARAMS( attr->length == sizeof(struct radius_attr_hdr)+sizeof(uint64_t) );\
595                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
596                                {                                                                               \
597                                        uint8_t * v = (uint8_t *)(attr + 1);                                    \
598                                        value.u64  = ((uint64_t)(v[0]) << 56)                                   \
599                                                   | ((uint64_t)(v[1]) << 48)                                   \
600                                                   | ((uint64_t)(v[2]) << 40)                                   \
601                                                   | ((uint64_t)(v[3]) << 32)                                   \
602                                                   | ((uint64_t)(v[4]) << 24)                                   \
603                                                   | ((uint64_t)(v[5]) << 16)                                   \
604                                                   | ((uint64_t)(v[6]) <<  8)                                   \
605                                                   |  (uint64_t)(v[7]) ;                                        \
606                                }                                                                               \
607                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
608                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
609                               
610                /* RFC 2865 */ 
611                        /*
612                              -  The Destination-Realm AVP is created from the information found
613                                 in the RADIUS User-Name attribute.
614                                        -> done in rgw_clients_create_origin
615                        */
616                        case RADIUS_ATTR_USER_NAME:
617                                CONV2DIAM_STR( User_Name );
618                                break;
619                               
620                        /*
621                              -  If the RADIUS User-Password attribute is present, the password
622                                 must be unencrypted by using the link's RADIUS shared secret.
623                                 The unencrypted value must be forwarded in a User-Password AVP
624                                 using Diameter security.
625                        */
626                        case RADIUS_ATTR_USER_PASSWORD:
627                                if ((attr->length - 2) % 16) {
628                                        TRACE_DEBUG(INFO, "Invalid length of User-Password attribute: %hhd", attr->length);
629                                        return EINVAL;
630                                }
631                                {
632                                        /* Decipher following this logic (refers to rfc2865#section-5.2 )
633                                           b1 = MD5(S + RA)     p1 = c(1) xor b1
634                                           b2 = MD5(S + c(1))   p2 = c(2) xor b2
635                                           ...
636                                        */
637                                       
638                                        uint8_t *ciph = (uint8_t *)(attr+1);    /* c(i) */
639                                        size_t ciph_len = attr->length - 2;
640                                        uint8_t deciph[128];                    /* pi */
641                                        size_t deciph_len = 0;
642                                        uint8_t * secret;                       /* S */
643                                        size_t secret_len;
644                                        uint8_t hash[16];                       /* b(i) */
645                                        const uint8_t *addr[2];
646                                        size_t len[2];
647                                       
648                                        /* Retrieve the shared secret */
649                                        CHECK_FCT(rgw_clients_getkey(cli, &secret, &secret_len));
650                                       
651                                        /* Initial b1 = MD5(S + RA) */
652                                        addr[0] = secret;
653                                        len[0] = secret_len;
654                                        addr[1] = rad_req->hdr->authenticator;
655                                        len[1] = 16;
656                                        md5_vector(2, addr, len, hash);
657                                       
658                                        /* loop */
659                                        while (deciph_len < ciph_len) {
660                                                int i;
661                                                /* pi = c(i) xor bi */
662                                                for (i = 0; i < 16; i++)
663                                                        deciph[deciph_len + i] = ciph[deciph_len + i] ^ hash[i];
664                                                        /* do we have to remove the padding '\0's ? */
665                                               
666                                                /* b(i+1) = MD5(S + c(i) */
667                                                addr[1] = ciph + deciph_len;
668                                                md5_vector(2, addr, len, hash);
669                                               
670                                                deciph_len += 16;
671                                        }
672                                       
673                                        /* Now save this value in the AVP */
674                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.User_Password, 0, &avp ) );
675                                        value.os.data = &deciph[0];
676                                        value.os.len  = deciph_len;
677                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
678                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
679                                }
680                                break;
681                               
682
683                        /*
684                              -  If the RADIUS CHAP-Password attribute is present, the Ident and
685                                 Data portion of the attribute are used to create the CHAP-Auth
686                                 grouped AVP.
687                        */
688                        case RADIUS_ATTR_CHAP_PASSWORD:
689                                CHECK_PARAMS( attr->length == 19 /* RFC 2865 */);
690                                {
691                                        uint8_t * c = (uint8_t *)(attr + 1);
692                                        struct avp * chap_auth;
693                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.CHAP_Auth, 0, &chap_auth ) );
694                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, chap_auth) );
695
696                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.CHAP_Algorithm, 0, &avp ) );
697                                        value.u32 = 5; /* The only value defined currently... */
698                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
699                                        CHECK_FCT( fd_msg_avp_add ( chap_auth, MSG_BRW_LAST_CHILD, avp) );
700                                       
701                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.CHAP_Ident, 0, &avp ) );
702                                        value.os.data = c;
703                                        value.os.len = 1;
704                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
705                                        CHECK_FCT( fd_msg_avp_add ( chap_auth, MSG_BRW_LAST_CHILD, avp) );
706                                       
707                                        c++;
708                                       
709                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.CHAP_Response, 0, &avp ) );
710                                        value.os.data = c;
711                                        value.os.len = attr->length - 3;
712                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
713                                        CHECK_FCT( fd_msg_avp_add ( chap_auth, MSG_BRW_LAST_CHILD, avp) );
714                                }
715                                break;
716                               
717                        case RADIUS_ATTR_NAS_IP_ADDRESS:
718                                CONV2DIAM_STR( NAS_IP_Address );
719                                break;
720                               
721                        case RADIUS_ATTR_NAS_PORT:
722                                CONV2DIAM_32B( NAS_Port );
723                                break;
724                               
725                        case RADIUS_ATTR_SERVICE_TYPE:
726                                CONV2DIAM_32B( Service_Type );
727                                break;
728                               
729                        case RADIUS_ATTR_FRAMED_PROTOCOL:
730                                CONV2DIAM_32B( Framed_Protocol );
731                                break;
732                               
733                        case RADIUS_ATTR_FRAMED_IP_ADDRESS:
734                                CONV2DIAM_STR( Framed_IP_Address );
735                                break;
736                               
737                        case RADIUS_ATTR_FRAMED_IP_NETMASK:
738                                CONV2DIAM_STR( Framed_IP_Netmask );
739                                break;
740                               
741                        /* Framed-Routing never present in an Access-Request */
742                        /* Filter-Id never present in an Access-Request */
743                               
744                        case RADIUS_ATTR_FRAMED_MTU:
745                                CONV2DIAM_32B( Framed_MTU );
746                                break;
747                       
748                        case RADIUS_ATTR_FRAMED_COMPRESSION:
749                                CONV2DIAM_32B( Framed_Compression );
750                                break;
751                       
752                        case RADIUS_ATTR_LOGIN_IP_HOST:
753                                CONV2DIAM_STR( Login_IP_Host );
754                                break;
755                               
756                        /* Login-Service never present in an Access-Request */
757                        /* Login-TCP-Port never present in an Access-Request */
758                        /* Reply-Message never present in an Access-Request */
759                       
760                        case RADIUS_ATTR_CALLBACK_NUMBER:
761                                CONV2DIAM_STR( Callback_Number );
762                                break;
763                               
764                        /* Callback-Id never present in an Access-Request */
765                        /* Framed-Route never present in an Access-Request */
766                        /* Framed-IPX-Network never present in an Access-Request */
767                               
768                        case RADIUS_ATTR_STATE:
769                                CONV2DIAM_STR( State );
770                                break;
771                       
772                        /* Class never present in an Access-Request */
773                               
774                        case RADIUS_ATTR_VENDOR_SPECIFIC:
775                                /* RFC 4005, Section 9.6 :
776                                           Systems that don't have vendor format knowledge MAY discard such
777                                           attributes without knowing a suitable translation.
778                                           
779                                           [conversion rule in 9.6.2]
780                                 */
781                                if (attr->length >= 6) {
782                                        uint32_t vendor_id;
783                                        uint8_t * c = (uint8_t *)(attr + 1);
784                                       
785                                        vendor_id = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3];
786                                        c += 4;
787                                       
788                                        switch (vendor_id) {
789                                               
790                                                /* For the vendors we KNOW they follow the VSA recommended format, we convert following the rules of RFC4005 (9.6.2) */
791                                                case RADIUS_VENDOR_ID_MICROSOFT : /* RFC 2548 */
792                                                /* other vendors ? */
793                                                {
794                                                        size_t left;
795                                                        struct radius_attr_vendor *vtlv;
796                                                       
797                                                        left = attr->length - 6;
798                                                        vtlv = (struct radius_attr_vendor *)c;
799                                               
800                                                        while ((left >= 2) && (vtlv->vendor_length <= left)) {
801                                                                /* Search our dictionary for corresponding Vendor's AVP */
802                                                                struct dict_avp_request req;
803                                                                struct dict_object * avp_model = NULL;
804                                                                memset(&req, 0, sizeof(struct dict_avp_request));
805                                                                req.avp_vendor = vendor_id;
806                                                                req.avp_code = vtlv->vendor_type;
807                                                               
808                                                                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE_AND_VENDOR, &req, &avp_model, 0) );
809                                                                if (!avp_model) {
810                                                                        TRACE_DEBUG(FULL, "Unknown attribute (vendor 0x%x, code 0x%x) ignored.", req.avp_vendor, req.avp_code);
811                                                                } else {
812                                                                        CHECK_FCT( fd_msg_avp_new ( avp_model, 0, &avp ) );
813                                                                        value.os.len = vtlv->vendor_length - 2;
814                                                                        value.os.data = (unsigned char *)(vtlv + 1);
815                                                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
816                                                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
817                                                                }
818                                                                c += vtlv->vendor_length;
819                                                                left -= vtlv->vendor_length;
820                                                                vtlv = (struct radius_attr_vendor *)c;
821                                                        }
822                                                }
823                                                break;
824                                               
825                                                /* Other vendors we KNOw how to convert the attributes would be added here... */
826                                                /* case RADIUS_VENDOR_ID_CISCO :
827                                                        break; */
828                                                /* case RADIUS_VENDOR_ID_IETF : (extended RADIUS attributes)
829                                                        break; */
830                                               
831                                                /* When we don't know, just discard the attribute... VSA are optional with regards to RADIUS anyway */
832                                                default:
833                                                        /* do nothing */
834                                                        TRACE_DEBUG(FULL, "VSA attribute from vendor %d discarded", vendor_id);
835                                                       
836                                        }
837                                }
838                                break;
839                               
840                        /* Session-Timeout never present in an Access-Request */
841                        /* Idle-Timeout never present in an Access-Request */
842                        /* Termination-Action never present in an Access-Request */
843                               
844                        case RADIUS_ATTR_CALLED_STATION_ID:
845                                CONV2DIAM_STR( Called_Station_Id );
846                                break;
847                       
848                        case RADIUS_ATTR_CALLING_STATION_ID:
849                                CONV2DIAM_STR( Calling_Station_Id );
850                                break;
851                       
852                        case RADIUS_ATTR_NAS_IDENTIFIER:
853                                CONV2DIAM_STR( NAS_Identifier );
854                                break;
855                       
856                        /* Proxy-State is handled by echo_drop.rgwx plugin, we ignore it here */
857                       
858                        case RADIUS_ATTR_LOGIN_LAT_SERVICE:
859                                CONV2DIAM_STR( Login_LAT_Service );
860                                break;
861                       
862                        case RADIUS_ATTR_LOGIN_LAT_NODE:
863                                CONV2DIAM_STR( Login_LAT_Node );
864                                break;
865                       
866                        case RADIUS_ATTR_LOGIN_LAT_GROUP:
867                                CONV2DIAM_STR( Login_LAT_Group );
868                                break;
869                       
870                        /* Framed-AppleTalk-Link never present in an Access-Request */
871                        /* Framed-AppleTalk-Network never present in an Access-Request */
872                        /* Framed-AppleTalk-Zone never present in an Access-Request */
873                       
874                        case RADIUS_ATTR_CHAP_CHALLENGE:
875                                CONV2DIAM_STR( CHAP_Challenge );
876                                break;
877                       
878                        case RADIUS_ATTR_NAS_PORT_TYPE:
879                                CONV2DIAM_32B( NAS_Port_Type );
880                                break;
881                       
882                        case RADIUS_ATTR_PORT_LIMIT:
883                                CONV2DIAM_32B( Port_Limit );
884                                break;
885                       
886                        case RADIUS_ATTR_LOGIN_LAT_PORT:
887                                CONV2DIAM_STR( Login_LAT_Port );
888                                break;
889                       
890                       
891                /* RFC 3162 */ 
892                        case RADIUS_ATTR_NAS_IPV6_ADDRESS:
893                                CONV2DIAM_STR( NAS_IPv6_Address );
894                                break;
895                               
896                        case RADIUS_ATTR_FRAMED_INTERFACE_ID:
897                                CONV2DIAM_64B( Framed_Interface_Id );
898                                break;
899                               
900                        case RADIUS_ATTR_FRAMED_IPV6_PREFIX:
901                                CONV2DIAM_STR( Framed_IPv6_Prefix );
902                                break;
903                               
904                        case RADIUS_ATTR_LOGIN_IPV6_HOST:
905                                CONV2DIAM_STR( Login_IPv6_Host );
906                                break;
907                               
908                        /* Framed-IPv6-Route never present in an Access-Request */
909                        /* Framed-IPv6-Pool never present in an Access-Request */
910
911
912                /* RFC 2868 */
913                        /* Prepare the top-level Tunneling AVP for each tag values, as needed, and add to the Diameter message.
914                                This macro is called when an AVP is added inside the group, so we will not have empty grouped AVPs */
915                        #define AVP_TUN_PREPARE() {                                                                             \
916                                                if (avp_tun == NULL) {                                                          \
917                                                        CHECK_MALLOC( avp_tun = calloc(sizeof(struct avp *), 32 ) );            \
918                                                }                                                                               \
919                                                tag = *(uint8_t *)(attr + 1);                                                   \
920                                                if (tag > 0x1F) tag = 0;                                                        \
921                                                if (avp_tun[tag] == NULL) {                                                     \
922                                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Tunneling, 0, &avp_tun[tag] ) );   \
923                                                        CHECK_FCT( fd_msg_avp_add (*diam_fw, MSG_BRW_LAST_CHILD, avp_tun[tag]));\
924                                                }                                                                               \
925                                        }
926                       
927                        /* Convert an attribute to an OctetString AVP and add inside the Tunneling AVP corresponding to the tag */
928                        #define CONV2DIAM_TUN_STR( _dictobj_ ) {                                                \
929                                uint8_t tag;                                                                    \
930                                CHECK_PARAMS( attr->length >= 3);                                               \
931                                AVP_TUN_PREPARE();                                                              \
932                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
933                                value.os.len = attr->length - (tag ? 3 : 2);                                    \
934                                value.os.data = ((unsigned char *)(attr + 1)) + (tag ? 1 : 0);                  \
935                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
936                                CHECK_FCT( fd_msg_avp_add ( avp_tun[tag], MSG_BRW_LAST_CHILD, avp) );           \
937                                }
938                               
939                        /* Convert an attribute to a scalar AVP and add inside the Tunneling AVP corresponding to the tag */
940                        #define CONV2DIAM_TUN_24B( _dictobj_ ) {                                                \
941                                uint8_t tag;                                                                    \
942                                CHECK_PARAMS( attr->length == 6);                                               \
943                                AVP_TUN_PREPARE();                                                              \
944                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
945                                {                                                                               \
946                                        uint8_t * v = (uint8_t *)(attr + 1);                                    \
947                                        value.u32 = (v[1] << 16) | (v[2] <<8) | v[3] ;                          \
948                                }                                                                               \
949                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
950                                CHECK_FCT( fd_msg_avp_add ( avp_tun[tag], MSG_BRW_LAST_CHILD, avp) );           \
951                                }
952
953                        /*
954                              -  If the RADIUS message contains Tunnel information [RADTunnels],
955                                 the attributes or tagged groups should each be converted to a
956                                 Diameter Tunneling Grouped AVP set.  If the tunnel information
957                                 contains a Tunnel-Password attribute, the RADIUS encryption
958                                 must be resolved, and the password forwarded, by using Diameter
959                                 security methods.
960                                    -> If the RADIUS message does not use properly the Tag info, result is unpredictable here..
961                        */
962                        case RADIUS_ATTR_TUNNEL_TYPE:
963                                CONV2DIAM_TUN_24B( Tunnel_Type );
964                                break;
965                       
966                        case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
967                                CONV2DIAM_TUN_24B( Tunnel_Medium_Type );
968                                break;
969                       
970                        case RADIUS_ATTR_TUNNEL_CLIENT_ENDPOINT:
971                                CONV2DIAM_TUN_STR( Tunnel_Client_Endpoint );
972                                break;
973                       
974                        case RADIUS_ATTR_TUNNEL_SERVER_ENDPOINT:
975                                CONV2DIAM_TUN_STR( Tunnel_Server_Endpoint );
976                                break;
977                       
978                        /* Tunnel-Password never present in an Access-Request */
979
980                        case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
981                                CONV2DIAM_TUN_STR( Tunnel_Private_Group_Id );
982                                break;
983                       
984                        /* Tunnel-Assignment-ID never present in an Access-Request */
985                       
986                        case RADIUS_ATTR_TUNNEL_PREFERENCE:
987                                CONV2DIAM_TUN_24B( Tunnel_Preference );
988                                break;
989                       
990                        case RADIUS_ATTR_TUNNEL_CLIENT_AUTH_ID:
991                                CONV2DIAM_TUN_STR( Tunnel_Client_Auth_Id );
992                                break;
993                       
994                        case RADIUS_ATTR_TUNNEL_SERVER_AUTH_ID:
995                                CONV2DIAM_TUN_STR( Tunnel_Server_Auth_Id );
996                                break;
997                       
998                       
999                /* RFC 2869 */ 
1000                        case RADIUS_ATTR_ARAP_PASSWORD:
1001                                CONV2DIAM_STR( ARAP_Password );
1002                                break;
1003                               
1004                        /* ARAP-Features never present in an Access-Request */
1005                        /* ARAP-Zone-Access never present in an Access-Request */
1006                       
1007                        case RADIUS_ATTR_ARAP_SECURITY:
1008                                CONV2DIAM_32B( ARAP_Security );
1009                                break;
1010                       
1011                        case RADIUS_ATTR_ARAP_SECURITY_DATA:
1012                                CONV2DIAM_STR( ARAP_Security_Data );
1013                                break;
1014                       
1015                        /* Password-Retry never present in an Access-Request */
1016                        /* Prompt never present in an Access-Request */
1017                       
1018                        case RADIUS_ATTR_CONNECT_INFO:
1019                                CONV2DIAM_STR( Connect_Info );
1020                                break;
1021                       
1022                        /* Configuration-Token never present in an Access-Request */
1023                        /* ARAP-Challenge-Response never present in an Access-Request */
1024                        /* Acct-Interim-Interval never present in an Access-Request */
1025                       
1026                        case RADIUS_ATTR_NAS_PORT_ID:
1027                                CONV2DIAM_STR( NAS_Port_Id );
1028                                break;
1029                       
1030                        /* Framed-Pool never present in an Access-Request */
1031                       
1032                               
1033                /* RFC 2869 / 3579 */   
1034                        case RADIUS_ATTR_ORIGINATING_LINE_INFO:
1035                                CONV2DIAM_STR( Originating_Line_Info );
1036                                break;
1037                               
1038                        case RADIUS_ATTR_MESSAGE_AUTHENTICATOR:
1039                        case RADIUS_ATTR_EAP_MESSAGE:
1040                                /* It was already handled, just remove the attribute */
1041                                break;
1042                               
1043                /* Default */           
1044                        default: /* unknown attribute */
1045                                /* We just keep the attribute in the RADIUS message */
1046                                rad_req->attr_pos[nattr_used++] = rad_req->attr_pos[idx];
1047                }
1048        }
1049       
1050        /* Destroy tunnel pointers (if we used it) */
1051        free(avp_tun);
1052       
1053        /* Update the radius message to remove all handled attributes */
1054        rad_req->attr_used = nattr_used;
1055
1056        /* Store the request identifier in the session (if provided) */
1057        if (*session) {
1058                unsigned char * req_auth;
1059                CHECK_MALLOC(req_auth = malloc(16));
1060                memcpy(req_auth, &rad_req->hdr->authenticator[0], 16);
1061               
1062                CHECK_FCT( fd_sess_state_store( cs->sess_hdl, *session, &req_auth ) );
1063        }
1064       
1065        return 0;
1066}
1067
1068static 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 )
1069{
1070        struct msg_hdr * hdr;
1071        struct avp *avp, *next, *avp_x, *avp_y, *asid, *aoh;
1072        struct avp_hdr *ahdr, *sid, *oh;
1073        uint8_t buf[254]; /* to store some attributes values (with final '\0') */
1074        size_t sz;
1075        int ta_set = 0;
1076        int no_str = 0; /* indicate if an STR is required for this server */
1077        uint8_t tuntag = 0;
1078        unsigned char * req_auth = NULL;
1079        int error_cause = 0;
1080       
1081        TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
1082        CHECK_PARAMS(cs && session && diam_ans && *diam_ans && rad_fw && *rad_fw);
1083       
1084        /* Retrieve the request identified which was stored in the session */
1085        if (session) {
1086                CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, session, &req_auth ) );
1087        }
1088       
1089        /*     
1090              -  If the Diameter Command-Code is set to AA-Answer and the
1091                 Result-Code AVP is set to DIAMETER_MULTI_ROUND_AUTH, the
1092                 gateway must send a RADIUS Access-Challenge.  This must have
1093                 the Origin-Host, Origin-Realm, and Diameter Session-Id AVPs
1094                 encapsulated in the RADIUS State attribute, with the prefix
1095                 "Diameter/", concatenated in the above order separated with "/"
1096                 characters, in UTF-8 [UTF-8].  This is necessary to ensure that
1097                 the Translation Agent receiving the subsequent RADIUS Access-
1098                 Request will have access to the Session Identifier and be able
1099                 to set the Destination-Host to the correct value.
1100                        -> done here bellow
1101                 
1102              -  If the Command-Code is set to AA-Answer, the Diameter Session-
1103                 Id AVP is saved in a new RADIUS Class attribute whose format
1104                 consists of the string "Diameter/" followed by the Diameter
1105                 Session Identifier.  This will ensure that the subsequent
1106                 Accounting messages, which could be received by any Translation
1107                 Agent, would have access to the original Diameter Session
1108                 Identifier.
1109                        -> done here but only for Access-Accept messages (Result-Code = success)
1110         */
1111       
1112        /* MACROS to help in the process: convert AVP data to RADIUS attributes. */
1113        /* Control large attributes:  _trunc_ = 0 => error; _trunc_ = 1 => truncate; _trunc = 2 => create several attributes */
1114        #define CONV2RAD_STR( _attr_, _data_, _len_, _trunc_)   {                                       \
1115                size_t __l = (size_t)(_len_);                                                           \
1116                size_t __off = 0;                                                                       \
1117                TRACE_DEBUG(FULL, "Converting AVP to "#_attr_);                                         \
1118                if ((_trunc_) == 0) {                                                                   \
1119                        CHECK_PARAMS( __l <= 253 );                                                     \
1120                }                                                                                       \
1121                if ((__l > 253) && (_trunc_ == 1)) {                                                    \
1122                        TRACE_DEBUG(INFO, "[auth.rgwx] AVP truncated in "#_attr_);                      \
1123                        __l = 253;                                                                      \
1124                }                                                                                       \
1125                do {                                                                                    \
1126                        size_t __w = (__l > 253) ? 253 : __l;                                           \
1127                        CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (_data_) + __off, __w));    \
1128                        __off += __w;                                                                   \
1129                        __l   -= __w;                                                                   \
1130                } while (__l);                                                                          \
1131        }
1132
1133        #define CONV2RAD_32B( _attr_, _data_)   {                                                       \
1134                uint32_t __v = htonl((uint32_t)(_data_));                                               \
1135                TRACE_DEBUG(FULL, "Converting AVP to "#_attr_);                                         \
1136                CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (uint8_t *)&__v, sizeof(__v)));     \
1137        }
1138
1139        #define CONV2RAD_64B( _attr_, _data_)   {                                                       \
1140                uint64_t __v = htonll((uint64_t)(_data_));                                              \
1141                TRACE_DEBUG(FULL, "Converting AVP to "#_attr_);                                         \
1142                CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (uint8_t *)&__v, sizeof(__v)));     \
1143        }
1144
1145        /* Search the different AVPs we handle here */
1146        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Session_Id, &asid) );
1147        CHECK_FCT( fd_msg_avp_hdr ( asid, &sid ) );
1148        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Host, &aoh) );
1149        CHECK_FCT( fd_msg_avp_hdr ( aoh, &oh ) );
1150
1151        /* Check the Diameter error code */
1152        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Result_Code, &avp) );
1153        ASSERT( avp ); /* otherwise the message should have been discarded a lot earlier because of ABNF */
1154        CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1155        switch (ahdr->avp_value->u32) {
1156                case ER_DIAMETER_MULTI_ROUND_AUTH:
1157                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_CHALLENGE;
1158                        break;
1159                case ER_DIAMETER_SUCCESS:
1160                case ER_DIAMETER_LIMITED_SUCCESS:
1161                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_ACCEPT;
1162                        break;
1163               
1164                default:
1165                        /* Can we convert the value to a natural Error-Cause ? */
1166                        switch (ahdr->avp_value->u32) {
1167                                case ER_DIAMETER_AVP_UNSUPPORTED:
1168                                        error_cause = 401; /* Unsupported Attribute */
1169                                        break;
1170                                       
1171                                case ER_DIAMETER_MISSING_AVP:
1172                                        error_cause = 402; /* Missing Attribute */
1173                                        break;
1174                                       
1175                                case ER_DIAMETER_UNABLE_TO_COMPLY:
1176                                        error_cause = 404; /* Invalid Request */
1177                                        break;
1178                                       
1179                                case ER_DIAMETER_APPLICATION_UNSUPPORTED:
1180                                        error_cause = 405; /* Unsupported Service */
1181                                        break;
1182                                       
1183                                case ER_DIAMETER_COMMAND_UNSUPPORTED:
1184                                        error_cause = 406; /* Unsupported Extension */
1185                                        break;
1186                                       
1187                                case ER_DIAMETER_INVALID_AVP_VALUE:
1188                                        error_cause = 407; /* Invalid Attribute Value */
1189                                        break;
1190                                       
1191                                case ER_DIAMETER_AVP_NOT_ALLOWED:
1192                                        error_cause = 501; /* Administratively Prohibited */
1193                                        break;
1194                                       
1195                                case ER_DIAMETER_REALM_NOT_SERVED:
1196                                case ER_DIAMETER_LOOP_DETECTED:
1197                                case ER_DIAMETER_UNKNOWN_PEER:
1198                                case ER_DIAMETER_UNABLE_TO_DELIVER:
1199                                        error_cause = 502; /* Request Not Routable (Proxy) */
1200                                        break;
1201                                       
1202                                case ER_DIAMETER_UNKNOWN_SESSION_ID:
1203                                        error_cause = 503; /* Session Context Not Found */
1204                                        break;
1205                                       
1206                                case ER_DIAMETER_TOO_BUSY:
1207                                case ER_DIAMETER_OUT_OF_SPACE:
1208                                        error_cause = 506; /* Resources Unavailable */
1209                                        break;
1210                                       
1211#if 0
1212                        /* remaining Diameter Result-Code & RADIUS Error-Cause */
1213                                case ER_DIAMETER_REDIRECT_INDICATION:
1214                                case ER_DIAMETER_INVALID_HDR_BITS:
1215                                case ER_DIAMETER_INVALID_AVP_BITS:
1216                                case ER_DIAMETER_AUTHENTICATION_REJECTED:
1217                                case ER_ELECTION_LOST:
1218                                case ER_DIAMETER_AUTHORIZATION_REJECTED:
1219                                case ER_DIAMETER_RESOURCES_EXCEEDED:
1220                                case ER_DIAMETER_CONTRADICTING_AVPS:
1221                                case ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES
1222                                case ER_DIAMETER_NO_COMMON_APPLICATION:
1223                                case ER_DIAMETER_UNSUPPORTED_VERSION:
1224                                case ER_DIAMETER_INVALID_BIT_IN_HEADER:
1225                                case ER_DIAMETER_INVALID_AVP_LENGTH:
1226                                case ER_DIAMETER_INVALID_MESSAGE_LENGTH:
1227                                case ER_DIAMETER_INVALID_AVP_BIT_COMBO:
1228                                case ER_DIAMETER_NO_COMMON_SECURITY:
1229                                        error_cause = 403; /* NAS Identification Mismatch */
1230                                        error_cause = 504; /* Session Context Not Removable */
1231                                        error_cause = 505; /* Other Proxy Processing Error */
1232                                        error_cause = 507; /* Request Initiated */
1233                                        error_cause = 508; /* Multiple Session Selection Unsupported */
1234#endif /* 0 */
1235                        }
1236                        /* In any case, the following is processed: */
1237                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCESS_REJECT;
1238                        fd_log_debug("[auth.rgwx] Received Diameter answer with error code '%d' from server '%.*s', session %.*s, translating into Access-Reject\n",
1239                                        ahdr->avp_value->u32, 
1240                                        oh->avp_value->os.len, oh->avp_value->os.data,
1241                                        sid->avp_value->os.len, sid->avp_value->os.data);
1242                        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Error_Message, &avp_x) );
1243                        if (avp_x) {
1244                                CHECK_FCT( fd_msg_avp_hdr ( avp_x, &ahdr ) );
1245                                fd_log_debug("[auth.rgwx]   Error-Message content: '%.*s'\n",
1246                                                ahdr->avp_value->os.len, ahdr->avp_value->os.data);
1247                        }
1248                        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Error_Reporting_Host, &avp_x) );
1249                        if (avp_x) {
1250                                CHECK_FCT( fd_msg_avp_hdr ( avp_x, &ahdr ) );
1251                                fd_log_debug("[auth.rgwx]   Error-Reporting-Host: '%.*s'\n",
1252                                                ahdr->avp_value->os.len, ahdr->avp_value->os.data);
1253                        }
1254                        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Failed_AVP, &avp_x) );
1255                        if (avp_x) {
1256                                fd_log_debug("[auth.rgwx]   Failed-AVP was included in the message.\n");
1257                                /* Dump its content ? */
1258                        }
1259        }
1260        /* Remove this Result-Code avp */
1261        CHECK_FCT( fd_msg_free( avp ) );
1262       
1263        /* Creation of the State or Class attribute with session information */
1264        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Realm, &avp) );
1265        CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1266       
1267        /* Now, save the session-id and eventually server info in a STATE or CLASS attribute */
1268        if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE) {
1269                if (sizeof(buf) < (sz = snprintf((char *)buf, sizeof(buf), "Diameter/%.*s/%.*s/%.*s", 
1270                                (int)oh->avp_value->os.len,  (char *)oh->avp_value->os.data,
1271                                (int)ahdr->avp_value->os.len,  (char *)ahdr->avp_value->os.data,
1272                                (int)sid->avp_value->os.len, (char *)sid->avp_value->os.data))) {
1273                        TRACE_DEBUG(INFO, "Data truncated in State attribute: %s", buf);
1274                }
1275                CONV2RAD_STR(RADIUS_ATTR_STATE, buf, sz, 0);
1276        }
1277
1278        if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
1279                /* Add the Session-Id */
1280                if (sizeof(buf) < (sz = snprintf((char *)buf, sizeof(buf), "Diameter/%.*s", 
1281                                (int)sid->avp_value->os.len, sid->avp_value->os.data))) {
1282                        TRACE_DEBUG(INFO, "Data truncated in Class attribute: %s", buf);
1283                }
1284                CONV2RAD_STR(RADIUS_ATTR_CLASS, buf, sz, 0);
1285        }
1286       
1287        /* Unlink the Origin-Realm now; the others are unlinked at the end of this function */
1288        CHECK_FCT( fd_msg_free( avp ) );
1289       
1290        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Session_Timeout, &avp) );
1291        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Authorization_Lifetime, &avp_x) );
1292        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Re_Auth_Request_Type, &avp_y) );
1293        /*     
1294           When translating a Diameter AA-Answer (with successful result code)
1295           to RADIUS Access-Accept that contains a Session-Timeout or
1296           Authorization-Lifetime AVP, take the following steps:
1297           
1298              -  If the Diameter message contains a Session-Timeout AVP but no
1299                 Authorization-Lifetime AVP, translate it to a Session-Timeout
1300                 attribute (not a Termination-Action).
1301        */
1302        if ((avp != NULL) && (avp_x == NULL)) {
1303                CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1304                CONV2RAD_32B( RADIUS_ATTR_SESSION_TIMEOUT, ahdr->avp_value->u32 );
1305        }
1306       
1307        /*     
1308              -  If the Diameter message contains an Authorization-Lifetime AVP
1309                 but no Session-Timeout AVP, translate it to a Session-Timeout
1310                 attribute and a Termination-Action set to AA-REQUEST.  (Remove
1311                 Authorization-Lifetime and Re-Auth-Request-Type.)
1312        */
1313        if ((avp == NULL) && (avp_x != NULL)) {
1314                CHECK_FCT( fd_msg_avp_hdr ( avp_x, &ahdr ) );
1315                CONV2RAD_32B( RADIUS_ATTR_SESSION_TIMEOUT, ahdr->avp_value->u32 );
1316                CONV2RAD_32B( RADIUS_ATTR_TERMINATION_ACTION, RADIUS_TERMINATION_ACTION_RADIUS_REQUEST );
1317                ta_set = 1;
1318        }
1319       
1320        /*     
1321              -  If the Diameter message has both, the Session-Timeout must be
1322                 greater than or equal to the Authorization-Lifetime (required
1323                 by [BASE]).  Translate it to a Session-Timeout value (with
1324                 value from Authorization-Lifetime AVP, the smaller one) and
1325                 with the Termination-Action set to AA-REQUEST.  (Remove the
1326                 Authorization-Lifetime and Re-Auth-Request-Type.)
1327        */
1328        if ((avp != NULL) && (avp_x != NULL)) {
1329                CHECK_FCT( fd_msg_avp_hdr ( avp_x, &ahdr ) );
1330                CONV2RAD_32B( RADIUS_ATTR_SESSION_TIMEOUT, ahdr->avp_value->u32 );
1331                CONV2RAD_32B( RADIUS_ATTR_TERMINATION_ACTION, RADIUS_TERMINATION_ACTION_RADIUS_REQUEST );
1332                ta_set = 1;
1333        }
1334       
1335        /*  -> Not too sure about Auth-Grace-Period... we'll just discard it for now */
1336       
1337        if (avp) {
1338                CHECK_FCT( fd_msg_free( avp ) );
1339        }
1340        if (avp_x) {
1341                CHECK_FCT( fd_msg_free( avp_x ) );
1342        }
1343        if (avp_y) {
1344                CHECK_FCT( fd_msg_free( avp_y ) );
1345        }
1346       
1347       
1348        /*
1349              -  If a Proxy-State attribute was present in the RADIUS request,
1350                 the same attribute is added in the response.  This information
1351                 may be found in the Proxy-Info AVP group, or in a local state
1352                 table.
1353                        -> handled by sub_echo_drop
1354
1355              -  If state information regarding the RADIUS request was saved in
1356                 a Proxy-Info AVP or local state table, the RADIUS Identifier
1357                 and UDP IP Address and port number are extracted and used in
1358                 issuing the RADIUS reply.
1359                        -> was saved with the full request
1360        */
1361       
1362       
1363        /* Now loop in the list of AVPs and convert those that we know how */
1364        CHECK_FCT( fd_msg_browse(*diam_ans, MSG_BRW_FIRST_CHILD, &next, NULL) );
1365       
1366        while (next) {
1367                int handled = 1;
1368                avp = next;
1369                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &next, NULL) );
1370               
1371                CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1372               
1373                if (!(ahdr->avp_flags & AVP_FLAG_VENDOR)) {
1374                        switch (ahdr->avp_code) {
1375                /* In case of Diameter error, include the Reply-Message attribute */
1376                                case DIAM_ATTR_ERROR_MESSAGE:
1377                                        CONV2RAD_STR(RADIUS_ATTR_REPLY_MESSAGE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1378                                        break;
1379                                       
1380                                case DIAM_ATTR_ERROR_REPORTING_HOST:
1381                                        {
1382                                                char buf[254];
1383                                                int bsz = snprintf(buf, sizeof(buf), "Error-Reporting-Host: %*s", (int)(ahdr->avp_value->os.len), ahdr->avp_value->os.data);
1384                                                CONV2RAD_STR(RADIUS_ATTR_REPLY_MESSAGE, (uint8_t *)buf, bsz, 2);
1385                                        }
1386                                        break;
1387                               
1388                                case DIAM_ATTR_FAILED_AVP:
1389                                        {
1390                                                struct avp * favp;
1391                                                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &favp, NULL) );
1392                                                if (favp) {
1393                                                        char buf[254];
1394                                                        int bsz;
1395                                                        struct dict_object * favp_model;
1396                                                       
1397                                                        CHECK_FCT( fd_msg_model(favp, &favp_model) );
1398                                                        if (favp_model) {
1399                                                                struct dict_avp_data fadata;
1400                                                                CHECK_FCT( fd_dict_getval(favp_model, &fadata) );
1401                                                                bsz = snprintf(buf, sizeof(buf), "Failed-AVP: %s", fadata.avp_name);
1402                                                        } else {
1403                                                                struct avp_hdr * favp_hdr;
1404                                                                CHECK_FCT( fd_msg_avp_hdr ( favp, &favp_hdr ) );
1405                                                                bsz = snprintf(buf, sizeof(buf), "Failed-AVP: code %u, vendor %u", favp_hdr->avp_code, favp_hdr->avp_vendor);
1406                                                        }
1407                                                        CONV2RAD_STR(RADIUS_ATTR_REPLY_MESSAGE, (uint8_t *)buf, bsz, 2);
1408                                                }
1409                                        }
1410                                        break;
1411                                       
1412                /* RFC 4005 (AVP in the order of the AA-Request/Answer AVP Table) */
1413                                case DIAM_ATTR_ACCT_INTERIM_INTERVAL:
1414                                        CONV2RAD_32B(RADIUS_ATTR_ACCT_INTERIM_INTERVAL, ahdr->avp_value->u32);
1415                                        break;
1416                                       
1417                                case DIAM_ATTR_ARAP_CHALLENGE_RESPONSE:
1418                                        CONV2RAD_STR(RADIUS_ATTR_ARAP_CHALLENGE_RESPONSE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1419                                        break;
1420                                       
1421                                case DIAM_ATTR_ARAP_FEATURES:
1422                                        CONV2RAD_STR(RADIUS_ATTR_ARAP_FEATURES, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1423                                        break;
1424                                       
1425                                /* ARAP-Password is not present in answers */
1426                                       
1427                                case DIAM_ATTR_ARAP_SECURITY:
1428                                        CONV2RAD_32B(RADIUS_ATTR_ARAP_SECURITY, ahdr->avp_value->u32);
1429                                        break;
1430                                       
1431                                case DIAM_ATTR_ARAP_SECURITY_DATA:
1432                                        CONV2RAD_STR(RADIUS_ATTR_ARAP_SECURITY_DATA, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1433                                        break;
1434                                       
1435                                case DIAM_ATTR_ARAP_ZONE_ACCESS:
1436                                        CONV2RAD_32B(RADIUS_ATTR_ARAP_ZONE_ACCESS, ahdr->avp_value->u32);
1437                                        break;
1438                                       
1439                                case DIAM_ATTR_AUTH_APPLICATION_ID:
1440                                        /* We just remove this AVP */
1441                                        break;
1442                                       
1443                                case DIAM_ATTR_AUTH_GRACE_PERIOD:
1444                                        /* We just remove this AVP (?) */
1445                                        break;
1446                               
1447                                case DIAM_ATTR_AUTH_REQUEST_TYPE:
1448                                        /* We only check the value */
1449                                        if (ahdr->avp_value->u32 != 3) {
1450                                                fd_log_debug("[auth.rgwx] Received Diameter answer with Auth-Request-Type set to %d (%s) from server %.*s, session %.*s.\n"
1451                                                                "  This may cause interoperability problems with RADIUS.\n",
1452                                                                ahdr->avp_value->u32,
1453                                                                (ahdr->avp_value->u32 == 1) ? "AUTHENTICATE_ONLY" :
1454                                                                        ((ahdr->avp_value->u32 == 2) ? "AUTHORIZE_ONLY" : "???"),
1455                                                                oh->avp_value->os.len, oh->avp_value->os.data, 
1456                                                                sid->avp_value->os.len, sid->avp_value->os.len);
1457                                        }
1458                                        break;
1459                               
1460                                case DIAM_ATTR_AUTH_SESSION_STATE:
1461                                        if ((!ta_set) && (ahdr->avp_value->u32 == ACV_ASS_STATE_MAINTAINED)) {
1462                                                CONV2RAD_32B( RADIUS_ATTR_TERMINATION_ACTION, RADIUS_TERMINATION_ACTION_RADIUS_REQUEST );
1463                                        }
1464                                       
1465                                        if (ahdr->avp_value->u32 == ACV_ASS_NO_STATE_MAINTAINED) {
1466                                                no_str = 1;
1467                                        }
1468                                        break;
1469                                       
1470                                /* Authorization-Lifetime already handled */
1471                               
1472                                case DIAM_ATTR_CALLBACK_ID:
1473                                        CONV2RAD_STR(RADIUS_ATTR_CALLBACK_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1474                                        break;
1475                               
1476                                case DIAM_ATTR_CALLBACK_NUMBER:
1477                                        CONV2RAD_STR(RADIUS_ATTR_CALLBACK_NUMBER, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1478                                        break;
1479                               
1480                                /* Called-Station-Id is not present in answers */
1481                                /* Calling-Station-Id is not present in answers */
1482                                /* CHAP-Auth is not present in answers */
1483                                /* CHAP-Challenge is not present in answers */
1484                                       
1485                                case DIAM_ATTR_CLASS:
1486                                        CONV2RAD_STR(RADIUS_ATTR_CLASS, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1487                                        break;
1488                               
1489                                case DIAM_ATTR_CONFIGURATION_TOKEN:
1490                                        /* We might as well remove it since it's not supposed to be sent to the NAS... */
1491                                        CONV2RAD_STR(RADIUS_ATTR_CONFIGURATION_TOKEN, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1492                                        break;
1493                               
1494                                /* Connect-Info is not present in answers */
1495                               
1496                                case DIAM_ATTR_FILTER_ID:
1497                                        CONV2RAD_STR(RADIUS_ATTR_FILTER_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1498                                        break;
1499                                       
1500                                case DIAM_ATTR_FRAMED_APPLETALK_LINK:
1501                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_APPLETALK_LINK, ahdr->avp_value->u32);
1502                                        break;
1503                                       
1504                                case DIAM_ATTR_FRAMED_APPLETALK_NETWORK:
1505                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_APPLETALK_NETWORK, ahdr->avp_value->u32);
1506                                        break;
1507                                       
1508                                case DIAM_ATTR_FRAMED_APPLETALK_ZONE:
1509                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_APPLETALK_ZONE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1510                                        break;
1511                                       
1512                                case DIAM_ATTR_FRAMED_COMPRESSION:
1513                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_COMPRESSION,  ahdr->avp_value->u32);
1514                                        break;
1515                                       
1516                                case DIAM_ATTR_FRAMED_INTERFACE_ID:
1517                                        CONV2RAD_64B(RADIUS_ATTR_FRAMED_INTERFACE_ID,  ahdr->avp_value->u64);
1518                                        break;
1519                                       
1520                                case DIAM_ATTR_FRAMED_IP_ADDRESS:
1521                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IP_ADDRESS,  ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1522                                        break;
1523                                       
1524                                case DIAM_ATTR_FRAMED_IP_NETMASK:
1525                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IP_NETMASK, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1526                                        break;
1527                                       
1528                                case DIAM_ATTR_FRAMED_IPV6_PREFIX:
1529                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IPV6_PREFIX, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1530                                        break;
1531                                       
1532                                case DIAM_ATTR_FRAMED_IPV6_POOL:
1533                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IPV6_POOL, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1534                                        break;
1535                                       
1536                                case DIAM_ATTR_FRAMED_IPV6_ROUTE:
1537                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_IPV6_ROUTE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1538                                        break;
1539                                       
1540                                case DIAM_ATTR_FRAMED_IPX_NETWORK:
1541                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_IPX_NETWORK, ahdr->avp_value->u32);
1542                                        break;
1543                                       
1544                                case DIAM_ATTR_FRAMED_MTU:
1545                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_MTU, ahdr->avp_value->u32);
1546                                        break;
1547                                       
1548                                case DIAM_ATTR_FRAMED_POOL:
1549                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_POOL, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1550                                        break;
1551                                       
1552                                case DIAM_ATTR_FRAMED_PROTOCOL:
1553                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_PROTOCOL, ahdr->avp_value->u32);
1554                                        break;
1555                                       
1556                                case DIAM_ATTR_FRAMED_ROUTE:
1557                                        CONV2RAD_STR(RADIUS_ATTR_FRAMED_ROUTE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1558                                        break;
1559                                       
1560                                case DIAM_ATTR_FRAMED_ROUTING:
1561                                        CONV2RAD_32B(RADIUS_ATTR_FRAMED_ROUTING, ahdr->avp_value->u32);
1562                                        break;
1563                                       
1564                                case DIAM_ATTR_IDLE_TIMEOUT:
1565                                        CONV2RAD_32B(RADIUS_ATTR_IDLE_TIMEOUT, ahdr->avp_value->u32);
1566                                        break;
1567                                       
1568                                case DIAM_ATTR_LOGIN_IP_HOST:
1569                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_IP_HOST, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1570                                        break;
1571                                       
1572                                case DIAM_ATTR_LOGIN_IPV6_HOST:
1573                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_IPV6_HOST, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0);
1574                                        break;
1575                                       
1576                                case DIAM_ATTR_LOGIN_LAT_GROUP:
1577                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_LAT_GROUP, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1578                                        break;
1579                                       
1580                                case DIAM_ATTR_LOGIN_LAT_NODE:
1581                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_LAT_NODE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1582                                        break;
1583                                       
1584                                case DIAM_ATTR_LOGIN_LAT_PORT:
1585                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_LAT_PORT, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1586                                        break;
1587                                       
1588                                case DIAM_ATTR_LOGIN_LAT_SERVICE:
1589                                        CONV2RAD_STR(RADIUS_ATTR_LOGIN_LAT_SERVICE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1590                                        break;
1591                                       
1592                                case DIAM_ATTR_LOGIN_SERVICE:
1593                                        CONV2RAD_32B(RADIUS_ATTR_LOGIN_SERVICE, ahdr->avp_value->u32);
1594                                        break;
1595                                       
1596                                case DIAM_ATTR_LOGIN_TCP_PORT:
1597                                        CONV2RAD_32B(RADIUS_ATTR_LOGIN_TCP_PORT, ahdr->avp_value->u32);
1598                                        break;
1599                                       
1600                        /*
1601                              -                                                         If the
1602                                 Multi-Round-Time-Out AVP is present, the value of the AVP MUST
1603                                 be inserted in the RADIUS Session-Timeout AVP.
1604
1605                              o  As described in [NASREQ], if the Result-Code AVP set to
1606                                 DIAMETER_MULTI_ROUND_AUTH and the Multi-Round-Time-Out AVP is
1607                                 present, it is translated to the RADIUS Session-Timeout attribute.
1608                        */
1609                                case DIAM_ATTR_MULTI_ROUND_TIMEOUT:
1610                                        CONV2RAD_32B(RADIUS_ATTR_SESSION_TIMEOUT, ahdr->avp_value->u32);
1611                                        break;
1612                                       
1613                                case DIAM_ATTR_NAS_FILTER_RULE:
1614                                        /* This is not translatable to RADIUS */
1615                                        fd_log_debug("[auth.rgwx] Received Diameter answer with non-translatable NAS-Filter-Rule AVP from '%.*s' (session: '%.*s'), ignoring.\n",
1616                                                        oh->avp_value->os.len, oh->avp_value->os.data,
1617                                                        sid->avp_value->os.len, sid->avp_value->os.data);
1618                                        handled = 0;
1619                                        break;
1620                                       
1621                                /* NAS-Identifier is not present in answers */
1622                                /* NAS-IP-Address is not present in answers */
1623                                /* NAS-IPv6-Address is not present in answers */
1624                                /* NAS-Port is not present in answers */
1625                                /* NAS-Port-Id is not present in answers */
1626                                /* NAS-Port-Type is not present in answers */
1627                               
1628                                case DIAM_ATTR_ORIGIN_AAA_PROTOCOL:
1629                                        /* We just remove this AVP */
1630                                        break;
1631                                       
1632                                /* Originating-Line-Info is not present in answers */
1633                               
1634                                case DIAM_ATTR_PASSWORD_RETRY:
1635                                        CONV2RAD_32B(RADIUS_ATTR_PASSWORD_RETRY, ahdr->avp_value->u32);
1636                                        break;
1637                               
1638                                case DIAM_ATTR_PORT_LIMIT:
1639                                        CONV2RAD_32B(RADIUS_ATTR_PORT_LIMIT, ahdr->avp_value->u32);
1640                                        break;
1641                               
1642                                case DIAM_ATTR_PROMPT:
1643                                        CONV2RAD_32B(RADIUS_ATTR_PROMPT, ahdr->avp_value->u32);
1644                                        break;
1645                                       
1646                                case DIAM_ATTR_QOS_FILTER_RULE:
1647                                        /* This is not translatable to RADIUS */
1648                                        fd_log_debug("[auth.rgwx] Received Diameter answer with non-translatable QoS-Filter-Rule AVP from '%.*s' (session: '%.*s'), ignoring.\n",
1649                                                        oh->avp_value->os.len, oh->avp_value->os.data,
1650                                                        sid->avp_value->os.len, sid->avp_value->os.data);
1651                                        handled = 0;
1652                                        break;
1653                                       
1654                                /* Re-Auth-Request-Type already handled */
1655                               
1656                                case DIAM_ATTR_REPLY_MESSAGE:
1657                                        CONV2RAD_STR(RADIUS_ATTR_REPLY_MESSAGE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1658                                        break;
1659                                       
1660                                case DIAM_ATTR_SERVICE_TYPE:
1661                                        CONV2RAD_32B(RADIUS_ATTR_SERVICE_TYPE, ahdr->avp_value->u32);
1662                                        break;
1663                               
1664                                case DIAM_ATTR_STATE:
1665                                        CONV2RAD_STR(RADIUS_ATTR_STATE, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 2);
1666                                        break;
1667                                       
1668                                case DIAM_ATTR_TUNNELING:
1669                                        {
1670#define CONV2RAD_TUN_STR( _attr_, _data_, _len_, _trunc_)       {                               \
1671        size_t __l = (size_t)(_len_);                                                           \
1672        size_t __w = (__l > 252) ? 252 : __l;                                                   \
1673        size_t __off = 0;                                                                       \
1674        if ((_trunc_) == 0) {                                                                   \
1675                CHECK_PARAMS( __l <= 252 );                                                     \
1676        }                                                                                       \
1677        if ((__l > 252) && (_trunc_ == 1)) {                                                    \
1678                TRACE_DEBUG(FULL, "Attribute truncated!");                                      \
1679                __l = 252;                                                                      \
1680        }                                                                                       \
1681        buf[0] = tuntag;                                                                        \
1682        memcpy(&buf[1], (_data_), __w);                                                         \
1683        CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), &buf[0], __w + 1));                 \
1684        while (__l -= __w) {                                                                    \
1685                __off += __w;                                                                   \
1686                __w = (__l > 253) ? 253 : __l;                                                  \
1687                CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (_data_) + __off, __w));    \
1688        }                                                                                       \
1689}
1690
1691#define CONV2RAD_TUN_32B( _attr_, _data_)       {                                               \
1692        uint32_t __v = htonl((uint32_t)(_data_) | (tuntag << 24));                              \
1693        CHECK_MALLOC(radius_msg_add_attr(*rad_fw, (_attr_), (uint8_t *)&__v, sizeof(__v)));     \
1694}
1695                                                struct avp *inavp, *innext;
1696                                                tuntag++;
1697                                                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &innext, NULL) );
1698                                                while (innext) {
1699                                                        inavp = innext;
1700                                                        CHECK_FCT( fd_msg_browse(inavp, MSG_BRW_NEXT, &innext, NULL) );
1701                                                        CHECK_FCT( fd_msg_avp_hdr ( inavp, &ahdr ) );
1702                                                       
1703                                                        if ( ! (ahdr->avp_flags & AVP_FLAG_VENDOR)) {
1704                                                                switch (ahdr->avp_code) {
1705                                                                        case DIAM_ATTR_TUNNEL_TYPE:
1706                                                                                CONV2RAD_TUN_32B( RADIUS_ATTR_TUNNEL_TYPE, ahdr->avp_value->u32);
1707                                                                                break;
1708                                                                               
1709                                                                        case DIAM_ATTR_TUNNEL_MEDIUM_TYPE:
1710                                                                                CONV2RAD_TUN_32B( RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, ahdr->avp_value->u32);
1711                                                                                break;
1712                                                                               
1713                                                                        case DIAM_ATTR_TUNNEL_CLIENT_ENDPOINT:
1714                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_CLIENT_ENDPOINT, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1715                                                                                break;
1716                                                                               
1717                                                                        case DIAM_ATTR_TUNNEL_SERVER_ENDPOINT:
1718                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_SERVER_ENDPOINT, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1719                                                                                break;
1720                                                                               
1721                                                                        case DIAM_ATTR_TUNNEL_PREFERENCE:
1722                                                                                CONV2RAD_TUN_32B( RADIUS_ATTR_TUNNEL_PREFERENCE, ahdr->avp_value->u32);
1723                                                                                break;
1724                                                                               
1725                                                                        case DIAM_ATTR_TUNNEL_CLIENT_AUTH_ID:
1726                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_CLIENT_AUTH_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1727                                                                                break;
1728                                                                               
1729                                                                        case DIAM_ATTR_TUNNEL_SERVER_AUTH_ID:
1730                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_SERVER_AUTH_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1731                                                                                break;
1732                                                                               
1733                                                                        case DIAM_ATTR_TUNNEL_ASSIGNMENT_ID:
1734                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_ASSIGNMENT_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1735                                                                                break;
1736                                                                               
1737                                                                        case DIAM_ATTR_TUNNEL_PASSWORD:
1738                                                                                {
1739                                                                                        /* This AVP must be encoded for RADIUS (similar to radius_msg_add_attr_user_password)
1740                                                                                            0                   1                   2                   3
1741                                                                                            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
1742                                                                                           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1743                                                                                           |     Type      |    Length     |     Tag       |   Salt
1744                                                                                           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1745                                                                                              Salt (cont)  |   String ...
1746                                                                                           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1747                                                                                        */
1748                                                                                        size_t pos;
1749                                                                                        int i;
1750                                                                                        uint8_t * secret;       /* S */
1751                                                                                        size_t secret_len;
1752                                                                                        uint8_t hash[16];       /* b(i) */
1753                                                                                        const uint8_t *addr[3];
1754                                                                                        size_t len[3];
1755                                                                                       
1756                                                                                        /* We need the request authenticator */
1757                                                                                        CHECK_PARAMS(req_auth);
1758
1759                                                                                        /* Retrieve the shared secret */
1760                                                                                        CHECK_FCT(rgw_clients_getkey(cli, &secret, &secret_len));
1761                                                                                       
1762                                                                                        /* Beginning of the buffer */
1763                                                                                        buf[0] = tuntag;
1764                                                                                        buf[1] = (uint8_t)(lrand48()); /* A (hi bits) */
1765                                                                                        buf[2] = (uint8_t)(lrand48()); /* A (low bits) */
1766                                                                                       
1767                                                                                        /* The plain text string P */
1768                                                                                        CHECK_PARAMS(ahdr->avp_value->os.len < 240);
1769                                                                                        buf[3] = ahdr->avp_value->os.len;
1770                                                                                        memcpy(&buf[4], ahdr->avp_value->os.data, ahdr->avp_value->os.len);
1771                                                                                        memset(&buf[4 + ahdr->avp_value->os.len], 0, sizeof(buf) - 4 - ahdr->avp_value->os.len);
1772                                                                                       
1773                                                                                        /* Initial b1 = MD5(S + R + A) */
1774                                                                                        addr[0] = secret;
1775                                                                                        len[0] = secret_len;
1776                                                                                        addr[1] = req_auth;
1777                                                                                        len[1] = 16;
1778                                                                                        addr[2] = &buf[1];
1779                                                                                        len[2] = 2;
1780                                                                                        md5_vector(3, addr, len, hash);
1781                                                                                       
1782                                                                                        /* Initial c(1) = p(1) xor b(1) */
1783                                                                                        for (i = 0; i < 16; i++) {
1784                                                                                                buf[i + 3] ^= hash[i];
1785                                                                                        }
1786                                                                                        pos = 16;
1787                                                                                       
1788                                                                                        /* loop */
1789                                                                                        while (pos < ahdr->avp_value->os.len + 1) {
1790                                                                                                addr[0] = secret;
1791                                                                                                len[0] = secret_len;
1792                                                                                                addr[1] = &buf[pos - 13];
1793                                                                                                len[1] = 16;
1794                                                                                                /* b(i) = MD5( S + c(i-1) */
1795                                                                                                md5_vector(2, addr, len, hash);
1796                                                                                               
1797                                                                                                /* c(i) = p(i) xor b(i) */
1798                                                                                                for (i = 0; i < 16; i++)
1799                                                                                                        buf[pos + i + 3] ^= hash[i];
1800
1801                                                                                                pos += 16;
1802                                                                                        }
1803                                                                                       
1804                                                                                        CONV2RAD_STR(RADIUS_ATTR_TUNNEL_PASSWORD, &buf[0], pos + 3, 0);
1805                                                                                }
1806                                                                                break;
1807                                                                               
1808                                                                        case DIAM_ATTR_TUNNEL_PRIVATE_GROUP_ID:
1809                                                                                CONV2RAD_TUN_STR(RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1810                                                                                break;
1811                                                                       
1812                                                                        default:
1813                                                                                TRACE_DEBUG(FULL, "Ignored unknown AVP inside Tunneling AVP (%d)", ahdr->avp_code);
1814                                                                }
1815                                                        } else {
1816                                                                TRACE_DEBUG(FULL, "Ignored unknown Vendor AVP inside Tunneling AVP (%d, %d)", ahdr->avp_vendor, ahdr->avp_code);
1817                                                        }
1818                                                }
1819                                        }
1820                                        break;
1821                                       
1822                                case DIAM_ATTR_USER_NAME:
1823                                        CONV2RAD_STR(RADIUS_ATTR_USER_NAME, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1824                                        break;
1825                               
1826                                /* User-Password never present in answers */
1827                                       
1828                /* RFC 4072 (AVP in the order of the EAP Command AVP Table) */
1829                        /*
1830                              o  Diameter Accounting-EAP-Auth-Method AVPs, if present, are
1831                                 discarded.
1832                        */
1833                                case DIAM_ATTR_ACCOUNTING_EAP_AUTH_METHOD:
1834                                        break;
1835                                       
1836                        /*
1837                              o  Diameter EAP-Master-Session-Key AVP can be translated to the
1838                                 vendor-specific RADIUS MS-MPPE-Recv-Key and MS-MPPE-Send-Key
1839                                 attributes [RFC2548].  The first up to 32 octets of the key is
1840                                 stored into MS-MPPE-Recv-Key, and the next up to 32 octets (if
1841                                 present) are stored into MS-MPPE-Send-Key.  The encryption of this
1842                                 attribute is described in [RFC2548].
1843                        */
1844                                case DIAM_ATTR_EAP_MASTER_SESSION_KEY:
1845                                        {
1846                                                uint8_t * secret;       /* S */
1847                                                size_t secret_len;
1848                                                size_t recv_len, send_len;
1849
1850                                                /* We need the request authenticator */
1851                                                CHECK_PARAMS(req_auth);
1852
1853                                                /* Retrieve the shared secret */
1854                                                CHECK_FCT(rgw_clients_getkey(cli, &secret, &secret_len));
1855                                               
1856                                                if (ahdr->avp_value->os.len != 64) {
1857                                                        TRACE_DEBUG(INFO, "Received EAP-Master-Session-Key attribute with length %d != 64.\n", ahdr->avp_value->os.len)
1858                                                }
1859                                               
1860                                                CHECK_PARAMS(ahdr->avp_value->os.len <= 64);
1861                                                recv_len = ahdr->avp_value->os.len >= 32 ? 32 : ahdr->avp_value->os.len;
1862                                                send_len = ahdr->avp_value->os.len - recv_len;
1863                                               
1864                                                if ( ! radius_msg_add_mppe_keys(*rad_fw, req_auth, secret, secret_len, 
1865                                                                ahdr->avp_value->os.data + recv_len, send_len,
1866                                                                ahdr->avp_value->os.data, recv_len) ) {
1867                                                        TRACE_DEBUG(INFO, "Error while converting EAP-Master-Session-Key to RADIUS message");
1868                                                        return ENOMEM;
1869                                                }
1870                                        }
1871                                        break;
1872                               
1873                                case DIAM_ATTR_EAP_KEY_NAME:
1874                                        CONV2RAD_STR(RADIUS_ATTR_EAP_KEY_NAME, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 1);
1875                                        break;
1876                               
1877                        /*
1878                              o  Diameter EAP-Payload AVP is translated to RADIUS EAP-Message
1879                                 attribute(s).  If necessary, the value is split into multiple
1880                                 RADIUS EAP-Message attributes.
1881                        */
1882                                case DIAM_ATTR_EAP_PAYLOAD:
1883                                        if ( ! radius_msg_add_eap(*rad_fw, ahdr->avp_value->os.data, ahdr->avp_value->os.len) ) {
1884                                                TRACE_DEBUG(INFO, "Error while converting EAP payload to RADIUS message");
1885                                                return ENOMEM;
1886                                        }
1887                                        break;
1888                                       
1889                        /*
1890                              o  Diameter EAP-Reissued-Payload AVP is translated to a message that
1891                                 contains RADIUS EAP-Message attribute(s), and a RADIUS Error-Cause
1892                                 attribute [RFC3576] with value 202 (decimal), "Invalid EAP Packet
1893                                 (Ignored)" [RFC3579].
1894                        */
1895                                case DIAM_ATTR_EAP_REISSUED_PAYLOAD:
1896                                        if ( ! radius_msg_add_eap(*rad_fw, ahdr->avp_value->os.data, ahdr->avp_value->os.len) ) {
1897                                                TRACE_DEBUG(INFO, "Error while converting EAP reissued payload to RADIUS message");
1898                                                return ENOMEM;
1899                                        }
1900                                       
1901                                        error_cause = 202; /* Invalid EAP Packet */
1902                                        break;
1903                       
1904                                default:
1905                                        /* Leave the AVP in the message for further treatment */
1906                                        handled = 0;
1907                        }
1908                } else {
1909                        /* Vendor-specific AVPs */
1910                        switch (ahdr->avp_vendor) {
1911                               
1912                                default: /* unknown vendor */
1913                                        handled = 0;
1914                        }
1915                }
1916               
1917                if (handled) {
1918                        CHECK_FCT( fd_msg_free( avp ) );
1919                }
1920        }
1921       
1922        CHECK_FCT( fd_msg_free( asid ) );
1923        CHECK_FCT( fd_msg_free( aoh ) );
1924        free(req_auth);
1925       
1926        if (error_cause) {
1927                if ( ! radius_msg_add_attr_int32(*rad_fw, RADIUS_ATTR_ERROR_CAUSE, error_cause) ) {
1928                        TRACE_DEBUG(INFO, "Error while adding Error-Cause attribute in RADIUS message");
1929                        return ENOMEM;
1930                }
1931        }               
1932
1933        if ((*rad_fw)->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
1934                /* Add the auth-application-id required for STR, or 0 if no STR is required */
1935                CHECK_FCT( fd_msg_hdr( *diam_ans, &hdr ) );
1936                if (sizeof(buf) < (sz = snprintf((char *)buf, sizeof(buf), CLASS_AAI_PREFIX "%u", 
1937                                no_str ? 0 : hdr->msg_appl))) {
1938                        TRACE_DEBUG(INFO, "Data truncated in Class attribute: %s", buf);
1939                }
1940                CONV2RAD_STR(RADIUS_ATTR_CLASS, buf, sz, 0);
1941        }
1942       
1943        return 0;
1944}
1945
1946/* The exported symbol */
1947struct rgw_api rgwp_descriptor = {
1948        .rgwp_name       = "auth",
1949        .rgwp_conf_parse = auth_conf_parse,
1950        .rgwp_conf_free  = auth_conf_free,
1951        .rgwp_rad_req    = auth_rad_req,
1952        .rgwp_diam_ans   = auth_diam_ans
1953};     
Note: See TracBrowser for help on using the repository browser.