Navigation


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

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

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

File size: 61.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 Accounting-Request messages translation plugin */
37
38#include "rgw_common.h"
39
40
41/* Other constants we use */
42#define AI_ACCT                 3       /* Diameter Base Accounting application */
43#define CC_AC                   271     /* ACR/ACA */
44#define ACV_ART_START_RECORD            2       /* START_RECORD */
45#define ACV_ART_INTERIM_RECORD          3       /* INTERIM_RECORD */
46#define ACV_ART_STOP_RECORD             4       /* STOP_RECORD */
47#define ACV_ART_AUTHORIZE_AUTHENTICATE  3       /* AUTHORIZE_AUTHENTICATE */
48
49
50/* The state we keep for this plugin */
51struct rgwp_config {
52        struct {
53                struct dict_object * Accounting_Record_Number;  /* Accounting-Record-Number */
54                struct dict_object * Accounting_Record_Type;    /* Accounting-Record-Type */
55                struct dict_object * Acct_Application_Id;       /* Acct-Application-Id */
56                struct dict_object * Acct_Delay_Time;           /* Acct-Delay-Time */
57                struct dict_object * Accounting_Input_Octets;   /* Accounting-Input-Octets */
58                struct dict_object * Accounting_Output_Octets;  /* Accounting-Output-Octets */
59                struct dict_object * Accounting_Input_Packets;  /* Accounting-Input-Packets */
60                struct dict_object * Accounting_Output_Packets; /* Accounting-Output-Packets */
61                struct dict_object * Acct_Link_Count;           /* Acct-Link-Count */
62                struct dict_object * Acct_Authentic;            /* Acct-Authentic */
63                struct dict_object * Acct_Multi_Session_Id;     /* Acct-Multi-Session-Id */
64                struct dict_object * Acct_Session_Id;           /* Acct-Session-Id */
65                struct dict_object * Acct_Session_Time;         /* Acct-Session-Time */
66               
67                struct dict_object * ARAP_Password;             /* ARAP-Password */
68                struct dict_object * ARAP_Security;             /* ARAP-Security */
69                struct dict_object * ARAP_Security_Data;        /* ARAP-Security-Data */
70                struct dict_object * Auth_Application_Id;       /* Auth-Application-Id */
71                struct dict_object * Auth_Request_Type;         /* Auth-Request-Type */
72                struct dict_object * Authorization_Lifetime;    /* Authorization-Lifetime */
73                struct dict_object * Callback_Number;           /* Callback-Number */
74                struct dict_object * Callback_Id;               /* Callback-Id */
75                struct dict_object * Called_Station_Id;         /* Called-Station-Id */
76                struct dict_object * Calling_Station_Id;        /* Calling-Station-Id */
77                struct dict_object * Class;                     /* Class */
78                struct dict_object * CHAP_Algorithm;            /* CHAP-Algorithm */
79                struct dict_object * CHAP_Auth;                 /* CHAP-Auth */
80                struct dict_object * CHAP_Challenge;            /* CHAP-Challenge */
81                struct dict_object * CHAP_Ident;                /* CHAP-Ident */
82                struct dict_object * CHAP_Response;             /* CHAP-Response */
83                struct dict_object * Connect_Info;              /* Connect-Info */
84                struct dict_object * Destination_Host;          /* Destination-Host */
85                struct dict_object * Destination_Realm;         /* Destination-Realm */
86                struct dict_object * EAP_Payload;               /* EAP-Payload */
87                struct dict_object * Error_Message;             /* Error-Message */
88                struct dict_object * Error_Reporting_Host;      /* Error-Reporting-Host */
89                struct dict_object * Event_Timestamp;           /* Event-Timestamp */
90                struct dict_object * Failed_AVP;                /* Failed-AVP */
91                struct dict_object * Framed_AppleTalk_Link;     /* Framed-AppleTalk-Link */
92                struct dict_object * Framed_AppleTalk_Network;  /* Framed-AppleTalk-Network */
93                struct dict_object * Framed_AppleTalk_Zone;     /* Framed-AppleTalk-Zone */
94                struct dict_object * Framed_Compression;        /* Framed-Compression */
95                struct dict_object * Framed_IP_Address;         /* Framed-IP-Address */
96                struct dict_object * Framed_IP_Netmask;         /* Framed-IP-Netmask */
97                struct dict_object * Framed_Interface_Id;       /* Framed-Interface-Id */
98                struct dict_object * Framed_IPv6_Prefix;        /* Framed-IPv6-Prefix */
99                struct dict_object * Framed_IPX_Network;        /* Framed-IPX-Network */
100                struct dict_object * Framed_MTU;                /* Framed-MTU */
101                struct dict_object * Framed_Protocol;           /* Framed-Protocol */
102                struct dict_object * Framed_Pool;               /* Framed-Pool */
103                struct dict_object * Framed_IPv6_Route;         /* Framed-IPv6-Route */
104                struct dict_object * Framed_IPv6_Pool;          /* Framed-IPv6-Pool */
105                struct dict_object * Framed_Route;              /* Framed-Route */
106                struct dict_object * Framed_Routing;            /* Framed-Routing */
107                struct dict_object * Filter_Id;                 /* Filter-Id */
108                struct dict_object * Idle_Timeout;              /* Idle-Timeout */
109                struct dict_object * Login_IP_Host;             /* Login-IP-Host */
110                struct dict_object * Login_IPv6_Host;           /* Login-IPv6-Host */
111                struct dict_object * Login_LAT_Group;           /* Login-LAT-Group */
112                struct dict_object * Login_LAT_Node;            /* Login-LAT-Node */
113                struct dict_object * Login_LAT_Port;            /* Login-LAT-Port */
114                struct dict_object * Login_LAT_Service;         /* Login-LAT-Service */
115                struct dict_object * Login_Service;             /* Login-Service */
116                struct dict_object * Login_TCP_Port;            /* Login-TCP-Port */
117                struct dict_object * NAS_Identifier;            /* NAS-Identifier */
118                struct dict_object * NAS_IP_Address;            /* NAS-IP-Address */
119                struct dict_object * NAS_IPv6_Address;          /* NAS-IPv6-Address */
120                struct dict_object * NAS_Port;                  /* NAS-Port */
121                struct dict_object * NAS_Port_Id;               /* NAS-Port-Id */
122                struct dict_object * NAS_Port_Type;             /* NAS-Port-Type */
123                struct dict_object * Origin_AAA_Protocol;       /* Origin-AAA-Protocol */
124                struct dict_object * Origin_Host;               /* Origin-Host */
125                struct dict_object * Origin_Realm;              /* Origin-Realm */
126                struct dict_object * Originating_Line_Info;     /* Originating-Line-Info */
127                struct dict_object * Port_Limit;                /* Port-Limit */
128                struct dict_object * Re_Auth_Request_Type;      /* Re-Auth-Request-Type */
129                struct dict_object * Result_Code;               /* Result-Code */
130                struct dict_object * Service_Type;              /* Service-Type */
131                struct dict_object * Session_Id;                /* Session-Id */
132                struct dict_object * Session_Timeout;           /* Session-Timeout */
133                struct dict_object * State;                     /* State */
134                struct dict_object * Termination_Cause;         /* Termination-Cause */
135                struct dict_object * Tunneling;                 /* Tunneling */
136                struct dict_object * Tunnel_Type;               /* Tunnel-Type */
137                struct dict_object * Tunnel_Assignment_Id;      /* Tunnel-Assignment-Id */
138                struct dict_object * Tunnel_Medium_Type;        /* Tunnel-Medium-Type */
139                struct dict_object * Tunnel_Client_Endpoint;    /* Tunnel-Client-Endpoint */
140                struct dict_object * Tunnel_Server_Endpoint;    /* Tunnel-Server-Endpoint */
141                struct dict_object * Tunnel_Private_Group_Id;   /* Tunnel-Private-Group-Id */
142                struct dict_object * Tunnel_Preference;         /* Tunnel-Preference */
143                struct dict_object * Tunnel_Client_Auth_Id;     /* Tunnel-Client-Auth-Id */
144                struct dict_object * Tunnel_Server_Auth_Id;     /* Tunnel-Server-Auth-Id */
145                struct dict_object * User_Name;                 /* User-Name */
146               
147                struct dict_object * Session_Termination_Request;/* STR */
148        } dict; /* cache of the dictionary objects we use */
149        struct session_handler * sess_hdl; /* We store RADIUS request authenticator information in the session */
150        char * confstr;
151       
152        int ignore_nai;
153};
154
155/* The state we store in the session */
156struct sess_state {
157        application_id_t auth_appl;     /* Auth-Application-Id used for this session, if available (stored in a Class attribute) */
158        int              send_str;      /* If not 0, we must send a STR when the ACA is received. */
159        uint32_t         term_cause;    /* If not 0, the Termination-Cause to put in the STR. */
160};
161
162/* Initialize the plugin */
163static int acct_conf_parse(char * conffile, struct rgwp_config ** state)
164{
165        struct rgwp_config * new;
166        struct dict_object * app;
167       
168        TRACE_ENTRY("%p %p", conffile, state);
169        CHECK_PARAMS( state );
170       
171        CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
172        memset(new, 0, sizeof(struct rgwp_config));
173       
174        CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free, NULL ) );
175        new->confstr = conffile;
176       
177        if (conffile && strstr(conffile, "nonai"))
178                new->ignore_nai = 1;
179       
180        /* Resolve all dictionary objects we use */
181        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Record-Number", &new->dict.Accounting_Record_Number, ENOENT) );
182        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Record-Type", &new->dict.Accounting_Record_Type, ENOENT) );
183        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Application-Id", &new->dict.Acct_Application_Id, ENOENT) );
184        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Delay-Time", &new->dict.Acct_Delay_Time, ENOENT) );
185        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Input-Octets", &new->dict.Accounting_Input_Octets, ENOENT) );
186        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Output-Octets", &new->dict.Accounting_Output_Octets, ENOENT) );
187        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Input-Packets", &new->dict.Accounting_Input_Packets, ENOENT) );
188        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Output-Packets", &new->dict.Accounting_Output_Packets, ENOENT) );
189        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Authentic", &new->dict.Acct_Authentic, ENOENT) );
190        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Link-Count", &new->dict.Acct_Link_Count, ENOENT) );
191        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Multi-Session-Id", &new->dict.Acct_Multi_Session_Id, ENOENT) );
192        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Session-Id", &new->dict.Acct_Session_Id, ENOENT) );
193        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Session-Time", &new->dict.Acct_Session_Time, ENOENT) );
194       
195        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "ARAP-Password", &new->dict.ARAP_Password, ENOENT) );
196        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "ARAP-Security", &new->dict.ARAP_Security, ENOENT) );
197        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "ARAP-Security-Data", &new->dict.ARAP_Security_Data, ENOENT) );
198        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Application-Id", &new->dict.Auth_Application_Id, ENOENT) );
199        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Request-Type", &new->dict.Auth_Request_Type, ENOENT) );
200        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Authorization-Lifetime", &new->dict.Authorization_Lifetime, ENOENT) );
201        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Callback-Number", &new->dict.Callback_Number, ENOENT) );
202        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Callback-Id", &new->dict.Callback_Id, ENOENT) );
203        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Called-Station-Id", &new->dict.Called_Station_Id, ENOENT) );
204        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Calling-Station-Id", &new->dict.Calling_Station_Id, ENOENT) );
205        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Class", &new->dict.Class, ENOENT) );
206        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Connect-Info", &new->dict.Connect_Info, ENOENT) );
207        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &new->dict.Destination_Host, ENOENT) );
208        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &new->dict.Destination_Realm, ENOENT) );
209        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "EAP-Payload", &new->dict.EAP_Payload, ENOENT) );
210        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &new->dict.Error_Message, ENOENT) );
211        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &new->dict.Error_Reporting_Host, ENOENT) );
212        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Event-Timestamp", &new->dict.Event_Timestamp, ENOENT) );
213        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP", &new->dict.Failed_AVP, ENOENT) );
214        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-AppleTalk-Link", &new->dict.Framed_AppleTalk_Link, ENOENT) );
215        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-AppleTalk-Network", &new->dict.Framed_AppleTalk_Network, ENOENT) );
216        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-AppleTalk-Zone", &new->dict.Framed_AppleTalk_Zone, ENOENT) );
217        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-Compression", &new->dict.Framed_Compression, ENOENT) );
218        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-IP-Address", &new->dict.Framed_IP_Address, ENOENT) );
219        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-IP-Netmask", &new->dict.Framed_IP_Netmask, ENOENT) );
220        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-Interface-Id", &new->dict.Framed_Interface_Id, ENOENT) );
221        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-IPv6-Prefix", &new->dict.Framed_IPv6_Prefix, ENOENT) );
222        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-IPX-Network", &new->dict.Framed_IPX_Network, ENOENT) );
223        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-MTU", &new->dict.Framed_MTU, ENOENT) );
224        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-Protocol", &new->dict.Framed_Protocol, ENOENT) );
225        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-Pool", &new->dict.Framed_Pool, ENOENT) );
226        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-Route", &new->dict.Framed_Route, ENOENT) );
227        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-IPv6-Route", &new->dict.Framed_IPv6_Route, ENOENT) );
228        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-IPv6-Pool", &new->dict.Framed_IPv6_Pool, ENOENT) );
229        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Framed-Routing", &new->dict.Framed_Routing, ENOENT) );
230        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Filter-Id", &new->dict.Filter_Id, ENOENT) );
231        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Idle-Timeout", &new->dict.Idle_Timeout, ENOENT) );
232        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-IP-Host", &new->dict.Login_IP_Host, ENOENT) );
233        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-IPv6-Host", &new->dict.Login_IPv6_Host, ENOENT) );
234        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-LAT-Group", &new->dict.Login_LAT_Group, ENOENT) );
235        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-LAT-Node", &new->dict.Login_LAT_Node, ENOENT) );
236        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-LAT-Port", &new->dict.Login_LAT_Port, ENOENT) );
237        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-LAT-Service", &new->dict.Login_LAT_Service, ENOENT) );
238        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-Service", &new->dict.Login_Service, ENOENT) );
239        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Login-TCP-Port", &new->dict.Login_TCP_Port, ENOENT) );
240        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-Identifier", &new->dict.NAS_Identifier, ENOENT) );
241        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-IP-Address", &new->dict.NAS_IP_Address, ENOENT) );
242        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-IPv6-Address", &new->dict.NAS_IPv6_Address, ENOENT) );
243        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-Port", &new->dict.NAS_Port, ENOENT) );
244        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-Port-Id", &new->dict.NAS_Port_Id, ENOENT) );
245        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "NAS-Port-Type", &new->dict.NAS_Port_Type, ENOENT) );
246        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-AAA-Protocol", &new->dict.Origin_AAA_Protocol, ENOENT) );
247        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &new->dict.Origin_Host, ENOENT) );
248        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &new->dict.Origin_Realm, ENOENT) );
249        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Originating-Line-Info", &new->dict.Originating_Line_Info, ENOENT) );
250        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Port-Limit", &new->dict.Port_Limit, ENOENT) );
251        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) );
252        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &new->dict.Result_Code, ENOENT) );
253        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Service-Type", &new->dict.Service_Type, ENOENT) );
254        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &new->dict.Session_Id, ENOENT) );
255        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Timeout", &new->dict.Session_Timeout, ENOENT) );
256        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "State", &new->dict.State, ENOENT) );
257        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Termination-Cause", &new->dict.Termination_Cause, ENOENT) );
258        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunneling", &new->dict.Tunneling, ENOENT) );
259        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Assignment-Id", &new->dict.Tunnel_Assignment_Id, ENOENT) );
260        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Type", &new->dict.Tunnel_Type, ENOENT) );
261        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Medium-Type", &new->dict.Tunnel_Medium_Type, ENOENT) );
262        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Client-Endpoint", &new->dict.Tunnel_Client_Endpoint, ENOENT) );
263        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Server-Endpoint", &new->dict.Tunnel_Server_Endpoint, ENOENT) );
264        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) );
265        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Tunnel-Preference", &new->dict.Tunnel_Preference, ENOENT) );
266        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) );
267        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) );
268        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "User-Name", &new->dict.User_Name, ENOENT) );
269       
270        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Session-Termination-Request", &new->dict.Session_Termination_Request, ENOENT) );
271       
272        /* This plugin provides the following Diameter authentication applications support: */
273        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Base Accounting", &app, ENOENT) );
274        CHECK_FCT( fd_disp_app_support ( app, NULL, 0, 1 ) );
275       
276        *state = new;
277        return 0;
278}
279
280/* deinitialize */
281static void acct_conf_free(struct rgwp_config * state)
282{
283        TRACE_ENTRY("%p", state);
284        CHECK_PARAMS_DO( state, return );
285        CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl, NULL ),  );
286        free(state);
287        return;
288}
289
290/* Incoming RADIUS request */
291static int acct_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 )
292{
293        int idx;
294        int send_str=0;
295        uint32_t str_cause=0;
296        uint32_t e2eid = 0;
297        application_id_t auth_appl=0;
298        int got_id = 0;
299        uint32_t status_type;
300        uint32_t termination_action = 0;
301        uint32_t gigawords_in=0, gigawords_out=0;
302        size_t nattr_used = 0;
303        union avp_value value;
304        struct avp ** avp_tun = NULL, *avp = NULL;
305       
306        const char * prefix = "Diameter/";
307        size_t pref_len;
308        uint8_t * si = NULL;
309        size_t si_len = 0;
310        uint8_t * un = NULL;
311        size_t un_len = 0;
312       
313        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
314        CHECK_PARAMS(rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCOUNTING_REQUEST) && rad_ans && diam_fw && *diam_fw);
315       
316        pref_len = strlen(prefix);
317       
318        /*
319              Either NAS-IP-Address or NAS-Identifier MUST be present in a
320              RADIUS Accounting-Request.  It SHOULD contain a NAS-Port or NAS-
321              Port-Type attribute or both unless the service does not involve a
322              port or the NAS does not distinguish among its ports.
323        */
324        /* We also enforce that the message contains a CLASS attribute with Diameter/ prefix containing the Session-Id. */
325        for (idx = 0; idx < rad_req->attr_used; idx++) {
326                struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
327                uint8_t * v = (uint8_t *)(attr + 1);
328                size_t attr_len = attr->length - sizeof(struct radius_attr_hdr);
329               
330                switch (attr->type) {
331                        case RADIUS_ATTR_NAS_IP_ADDRESS:
332                        case RADIUS_ATTR_NAS_IDENTIFIER:
333                        case RADIUS_ATTR_NAS_IPV6_ADDRESS:
334                                got_id = 1;
335                                break;
336                               
337                        case RADIUS_ATTR_TERMINATION_ACTION:
338                                CHECK_PARAMS( attr->length == 6 );
339                                termination_action  = (v[0] << 24)
340                                                   | (v[1] << 16)
341                                                   | (v[2] <<  8)
342                                                   |  v[3] ;
343                                break;
344                               
345                        case RADIUS_ATTR_ACCT_INPUT_GIGAWORDS:
346                                CHECK_PARAMS( attr->length == 6 );
347                                gigawords_in  = (v[0] << 24)
348                                                   | (v[1] << 16)
349                                                   | (v[2] <<  8)
350                                                   |  v[3] ;
351                                break;
352                               
353                        case RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS:
354                                CHECK_PARAMS( attr->length == 6 );
355                                gigawords_out  = (v[0] << 24)
356                                                   | (v[1] << 16)
357                                                   | (v[2] <<  8)
358                                                   |  v[3] ;
359                                break;
360                               
361                        case RADIUS_ATTR_CLASS:
362                                if ((attr_len > pref_len ) && ! strncmp((char *)v, prefix, pref_len)) {
363                                        int i;
364                                        si = v + pref_len;
365                                        si_len = attr_len - pref_len;
366                                        TRACE_DEBUG(ANNOYING, "Found Class attribute with '%s' prefix (attr #%d), SI:'%.*s'.", prefix, idx, si_len, si);
367                                        /* Remove from the message */
368                                        for (i = idx + 1; i < rad_req->attr_used; i++)
369                                                rad_req->attr_pos[i - 1] = rad_req->attr_pos[i];
370                                        rad_req->attr_used -= 1;
371                                }
372                                break;
373
374                        case RADIUS_ATTR_USER_NAME:
375                                if (attr_len) {
376                                        un = v;
377                                        un_len = attr_len;
378                                        TRACE_DEBUG(ANNOYING, "Found a User-Name attribute: '%.*s'", un_len, un);
379                                }
380                                break;
381                       
382                }
383        }
384       
385        /* Check basic information is there */
386        if (!got_id || radius_msg_get_attr_int32(rad_req, RADIUS_ATTR_ACCT_STATUS_TYPE, &status_type)) {
387                TRACE_DEBUG(INFO, "[acct.rgwx] RADIUS Account-Request from %s did not contain a NAS ip/identifier or Acct-Status-Type attribute, reject.", rgw_clients_id(cli));
388                return EINVAL;
389        }
390       
391        /*
392              -- RFC2866:
393              In Accounting-Request Packets, the Authenticator value is a 16
394              octet MD5 [5] checksum, called the Request Authenticator.
395
396              The NAS and RADIUS accounting server share a secret.  The Request
397              Authenticator field in Accounting-Request packets contains a one-
398              way MD5 hash calculated over a stream of octets consisting of the
399              Code + Identifier + Length + 16 zero octets + request attributes +
400              shared secret (where + indicates concatenation).  The 16 octet MD5
401              hash value is stored in the Authenticator field of the
402              Accounting-Request packet.
403
404              Note that the Request Authenticator of an Accounting-Request can
405              not be done the same way as the Request Authenticator of a RADIUS
406              Access-Request, because there is no User-Password attribute in an
407              Accounting-Request.
408             
409             
410              -- RFC5080:
411              The Request Authenticator field MUST contain the correct data, as
412              given by the above calculation.  Invalid packets are silently
413              discarded.  Note that some early implementations always set the
414              Request Authenticator to all zeros.  New implementations of RADIUS
415              clients MUST use the above algorithm to calculate the Request
416              Authenticator field.  New RADIUS server implementations MUST
417              silently discard invalid packets.
418             
419        */     
420        {
421                uint8_t save[MD5_MAC_LEN];
422                uint8_t * secret;
423                size_t secret_len;
424               
425                /* Get the shared secret */
426                CHECK_FCT(rgw_clients_getkey(cli, &secret, &secret_len));
427               
428                /* Copy the received Request Authenticator */
429                memcpy(&save[0], &rad_req->hdr->authenticator[0], MD5_MAC_LEN);
430               
431                /* Compute the same authenticator */
432                radius_msg_finish_acct(rad_req, secret, secret_len);
433               
434                /* And now compare with the received value */
435                if (memcmp(&save[0], &rad_req->hdr->authenticator[0], MD5_MAC_LEN)) {
436                        /* Invalid authenticator */
437                        TRACE_DEBUG_BUFFER(FULL+1, "Received ReqAuth: ", &save[0], MD5_MAC_LEN, "" );
438                        TRACE_DEBUG_BUFFER(FULL+1, "Expected ReqAuth: ", &rad_req->hdr->authenticator[0], MD5_MAC_LEN, "" );
439                        TRACE_DEBUG(INFO, "[acct.rgwx] Invalid Request Authenticator in Account-Request from %s, discarding the message.", rgw_clients_id(cli));
440                        return EINVAL;
441                }
442        }
443       
444       
445        /* Handle the Accounting-On case: nothing to do, just reply OK */
446        if (status_type == RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON) {
447                TRACE_DEBUG(FULL, "[acct.rgwx] Received Accounting-On Acct-Status-Type attribute, replying without translation to Diameter.");
448                CHECK_MALLOC( *rad_ans = radius_msg_new(RADIUS_CODE_ACCOUNTING_RESPONSE, rad_req->hdr->identifier) );
449                return -2;
450        }
451       
452        if (status_type == RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF) {
453                TRACE_DEBUG(FULL, "[acct.rgwx] Received Accounting-Off Acct-Status-Type attribute, we must terminate all active sessions.");
454                TODO("RADIUS side is rebooting, send STR on all sessions?");
455                return ENOTSUP;
456        }
457       
458        /* Check if we got a valid session information, otherwise the server will not be able to handle the data... */
459        if (!*session && !si) {
460                TRACE_DEBUG(INFO, "[acct.rgwx] RADIUS Account-Request from %s did not contain a CLASS attribute with Diameter session information, reject.", rgw_clients_id(cli));
461                return EINVAL;
462        }
463       
464        /* Add the Destination-Realm */
465        CHECK_FCT( fd_msg_avp_new ( cs->dict.Destination_Realm, 0, &avp ) );
466        idx = 0;
467        if (un && ! cs->ignore_nai) {
468                /* Is there an '@' in the user name? We don't care for decorated NAI here */
469                for (idx = un_len - 2; idx > 0; idx--) {
470                        if (un[idx] == '@') {
471                                idx++;
472                                break;
473                        }
474                }
475        }
476        if (idx == 0) {
477                /* Not found in the User-Name => we use the local domain of this gateway */
478                value.os.data = (uint8_t *)fd_g_config->cnf_diamrlm;
479                value.os.len  = fd_g_config->cnf_diamrlm_len;
480        } else {
481                value.os.data = un + idx;
482                value.os.len  = un_len - idx;
483        }
484        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
485        CHECK_FCT( fd_msg_avp_add ( *diam_fw, *session ? MSG_BRW_LAST_CHILD : MSG_BRW_FIRST_CHILD, avp) );
486       
487        /* Create the Session-Id AVP if needed */
488        if (!*session) {
489                CHECK_FCT( fd_sess_fromsid ( (char *)/* cast should be removed later */si, si_len, session, NULL) );
490               
491                TRACE_DEBUG(FULL, "[acct.rgwx] Translating new accounting message for session '%.*s'...", si_len, si);
492               
493                /* Add the Session-Id AVP as first AVP */
494                CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
495                value.os.data = (unsigned char *)si;
496                value.os.len = si_len;
497                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
498                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
499        }
500       
501               
502        /* Add the command code */
503        {
504                struct msg_hdr * header = NULL;
505                CHECK_FCT( fd_msg_hdr ( *diam_fw, &header ) );
506                header->msg_flags = CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE;
507                header->msg_code = CC_AC;
508                header->msg_appl = AI_ACCT;
509               
510                /* Add the Acct-Application-Id */
511                CHECK_FCT( fd_msg_avp_new ( cs->dict.Acct_Application_Id, 0, &avp ) );
512                value.i32 = header->msg_appl;
513                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
514                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
515               
516                /* save the end to end id */
517                e2eid = header->msg_eteid;
518        }
519       
520        /* Convert the RADIUS attributes, as they appear in the message */
521        for (idx = 0; idx < rad_req->attr_used; idx++) {
522                struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
523
524                switch (attr->type) {
525                        /*     
526                              Any attribute valid in a RADIUS Access-Request or Access-Accept
527                              packet is valid in a RADIUS Accounting-Request packet, except that
528                              the following attributes MUST NOT be present in an Accounting-
529                              Request:  User-Password, CHAP-Password, Reply-Message, State.
530                        */
531                        case RADIUS_ATTR_USER_PASSWORD:
532                        case RADIUS_ATTR_CHAP_PASSWORD:
533                        case RADIUS_ATTR_REPLY_MESSAGE:
534                        case RADIUS_ATTR_STATE:
535                        case RADIUS_ATTR_MESSAGE_AUTHENTICATOR:
536                        case RADIUS_ATTR_EAP_MESSAGE:
537                                TRACE_DEBUG(INFO, "[acct.rgwx] RADIUS Account-Request contains a forbidden attribute (%hhd), reject.", attr->type);
538                                return EINVAL;
539                               
540                       
541                        /* This macro converts a RADIUS attribute to a Diameter AVP of type OctetString */
542                        #define CONV2DIAM_STR( _dictobj_ )      \
543                                CHECK_PARAMS( attr->length >= 2 );                                              \
544                                /* Create the AVP with the specified dictionary model */                        \
545                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
546                                value.os.len = attr->length - 2;                                                \
547                                value.os.data = (unsigned char *)(attr + 1);                                    \
548                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
549                                /* Add the AVP in the Diameter message. */                                      \
550                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
551                               
552                        /* Same thing, for scalar AVPs of 32 bits */
553                        #define CONV2DIAM_32B( _dictobj_ )      \
554                                CHECK_PARAMS( attr->length == 6 );                                              \
555                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
556                                {                                                                               \
557                                        uint8_t * v = (uint8_t *)(attr + 1);                                    \
558                                        value.u32  = (v[0] << 24)                                               \
559                                                   | (v[1] << 16)                                               \
560                                                   | (v[2] <<  8)                                               \
561                                                   |  v[3] ;                                                    \
562                                }                                                                               \
563                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
564                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
565                               
566                        /* And the 64b version */
567                        #define CONV2DIAM_64B( _dictobj_ )      \
568                                CHECK_PARAMS( attr->length == 10);                                              \
569                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
570                                {                                                                               \
571                                        uint8_t * v = (uint8_t *)(attr + 1);                                    \
572                                        value.u64  = ((uint64_t)(v[0]) << 56)                                   \
573                                                   | ((uint64_t)(v[1]) << 48)                                   \
574                                                   | ((uint64_t)(v[2]) << 40)                                   \
575                                                   | ((uint64_t)(v[3]) << 32)                                   \
576                                                   | ((uint64_t)(v[4]) << 24)                                   \
577                                                   | ((uint64_t)(v[5]) << 16)                                   \
578                                                   | ((uint64_t)(v[6]) <<  8)                                   \
579                                                   |  (uint64_t)(v[7]) ;                                        \
580                                }                                                                               \
581                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
582                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
583                               
584                       
585                        /* Attributes as listed in RFC2866, section 5.13  and RFC4005, section 10.2.1 */
586                        case RADIUS_ATTR_USER_NAME:
587                                CONV2DIAM_STR( User_Name );
588                                break;
589                               
590                        case RADIUS_ATTR_NAS_IP_ADDRESS:
591                                CONV2DIAM_STR( NAS_IP_Address );
592                                break;
593                               
594                        case RADIUS_ATTR_NAS_PORT:
595                                CONV2DIAM_32B( NAS_Port );
596                                break;
597                               
598                        case RADIUS_ATTR_SERVICE_TYPE:
599                                CONV2DIAM_32B( Service_Type );
600                                break;
601                               
602                        case RADIUS_ATTR_FRAMED_PROTOCOL:
603                                CONV2DIAM_32B( Framed_Protocol );
604                                break;
605                               
606                        case RADIUS_ATTR_FRAMED_IP_ADDRESS:
607                                CONV2DIAM_STR( Framed_IP_Address );
608                                break;
609                               
610                        case RADIUS_ATTR_FRAMED_IP_NETMASK:
611                                CONV2DIAM_STR( Framed_IP_Netmask );
612                                break;
613                               
614                        case RADIUS_ATTR_FRAMED_ROUTING:
615                                CONV2DIAM_32B( Framed_Routing );
616                                break;
617                               
618                        case RADIUS_ATTR_FILTER_ID:
619                                CONV2DIAM_STR( Filter_Id );
620                                break;
621                               
622                        case RADIUS_ATTR_FRAMED_MTU:
623                                CONV2DIAM_32B( Framed_MTU );
624                                break;
625                       
626                        case RADIUS_ATTR_FRAMED_COMPRESSION:
627                                CONV2DIAM_32B( Framed_Compression );
628                                break;
629                       
630                        case RADIUS_ATTR_LOGIN_IP_HOST:
631                                CONV2DIAM_STR( Login_IP_Host );
632                                break;
633                               
634                        case RADIUS_ATTR_LOGIN_SERVICE:
635                                CONV2DIAM_32B( Login_Service );
636                                break;
637                               
638                        case RADIUS_ATTR_LOGIN_TCP_PORT:
639                                CONV2DIAM_32B( Login_TCP_Port );
640                                break;
641                               
642                        case RADIUS_ATTR_CALLBACK_NUMBER:
643                                CONV2DIAM_STR( Callback_Number );
644                                break;
645                               
646                        case RADIUS_ATTR_CALLBACK_ID:
647                                CONV2DIAM_STR( Callback_Id );
648                                break;
649                               
650                        case RADIUS_ATTR_FRAMED_ROUTE:
651                                CONV2DIAM_STR( Framed_Route );
652                                break;
653                               
654                        case RADIUS_ATTR_FRAMED_IPX_NETWORK:
655                                CONV2DIAM_32B( Framed_IPX_Network );
656                                break;
657                               
658                        case RADIUS_ATTR_CLASS:
659                                CONV2DIAM_STR( Class );
660                                /* In addition, save the data in the session if it is "our" CLASS_AAI_PREFIX Class attribute */
661                                {
662                                        char buf[32];
663                                        char * attr_val, *auth_val;
664                                        attr_val = (char *)(attr + 1);
665                                        auth_val = attr_val + strlen(CLASS_AAI_PREFIX);
666                                        if (    (attr->length > sizeof(struct radius_attr_hdr) + strlen(CLASS_AAI_PREFIX)  )
667                                                && (attr->length < sizeof(struct radius_attr_hdr) + strlen(CLASS_AAI_PREFIX) + sizeof(buf))
668                                                && ! strncmp(attr_val, CLASS_AAI_PREFIX, strlen(CLASS_AAI_PREFIX))) {
669                                       
670                                                memset(buf, 0, sizeof(buf));
671                                                memcpy(buf, auth_val, attr->length - sizeof(struct radius_attr_hdr) - strlen(CLASS_AAI_PREFIX));
672                                                if (sscanf(buf, "%u", &auth_appl) == 1) {
673                                                        TRACE_DEBUG(ANNOYING, "Found Class attribute with '%s' prefix (attr #%d), AAI:%u.", CLASS_AAI_PREFIX, idx, auth_appl);
674                                                }
675                                        }
676                                }
677                                break;
678                       
679                        case RADIUS_ATTR_VENDOR_SPECIFIC:
680                                if (attr->length >= 6) {
681                                        uint32_t vendor_id;
682                                        uint8_t * c = (uint8_t *)(attr + 1);
683                                       
684                                        vendor_id = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3];
685                                        c += 4;
686                                       
687                                        switch (vendor_id) {
688                                               
689                                                /* For the vendors we KNOW they follow the VSA recommended format, we convert following the rules of RFC4005 (9.6.2) */
690                                                case RADIUS_VENDOR_ID_MICROSOFT : /* RFC 2548 */
691                                                /* other vendors ? */
692                                                {
693                                                        size_t left;
694                                                        struct radius_attr_vendor *vtlv;
695                                                       
696                                                        left = attr->length - 6;
697                                                        vtlv = (struct radius_attr_vendor *)c;
698                                               
699                                                        while ((left >= 2) && (vtlv->vendor_length <= left)) {
700                                                                /* Search our dictionary for corresponding Vendor's AVP */
701                                                                struct dict_avp_request req;
702                                                                struct dict_object * avp_model = NULL;
703                                                                memset(&req, 0, sizeof(struct dict_avp_request));
704                                                                req.avp_vendor = vendor_id;
705                                                                req.avp_code = vtlv->vendor_type;
706                                                               
707                                                                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE_AND_VENDOR, &req, &avp_model, 0) );
708                                                                if (!avp_model) {
709                                                                        TRACE_DEBUG(FULL, "Unknown attribute (vendor 0x%x, code 0x%x) ignored.", req.avp_vendor, req.avp_code);
710                                                                } else {
711                                                                        CHECK_FCT( fd_msg_avp_new ( avp_model, 0, &avp ) );
712                                                                        value.os.len = vtlv->vendor_length - 2;
713                                                                        value.os.data = (unsigned char *)(vtlv + 1);
714                                                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
715                                                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
716                                                                }
717                                                                c += vtlv->vendor_length;
718                                                                left -= vtlv->vendor_length;
719                                                                vtlv = (struct radius_attr_vendor *)c;
720                                                        }
721                                                }
722                                                break;
723                                               
724                                                /* Other vendors we KNOw how to convert the attributes would be added here... */
725                                                /* case RADIUS_VENDOR_ID_CISCO :
726                                                        break; */
727                                                /* case RADIUS_VENDOR_ID_IETF : (extended RADIUS attributes)
728                                                        break; */
729                                               
730                                                /* When we don't know, just discard the attribute... VSA are optional with regards to RADIUS anyway */
731                                                default:
732                                                        /* do nothing */
733                                                        TRACE_DEBUG(FULL, "VSA attribute from vendor %d discarded", vendor_id);
734                                                       
735                                        }
736                                }
737                                break;
738                               
739                        case RADIUS_ATTR_SESSION_TIMEOUT:
740                                /* Translation depends on Termination-Action : rfc4005#section-9.2.1 */
741                                if (termination_action != RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
742                                        CONV2DIAM_32B( Session_Timeout );
743                                } else {
744                                        CONV2DIAM_32B( Authorization_Lifetime );
745                                        /* And add this additional AVP */
746                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Re_Auth_Request_Type, 0, &avp ) );
747                                        value.u32 = ACV_ART_AUTHORIZE_AUTHENTICATE;
748                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
749                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
750                                }
751                                break;
752                               
753                        case RADIUS_ATTR_IDLE_TIMEOUT:
754                                CONV2DIAM_32B( Idle_Timeout );
755                                break;
756                       
757                        case RADIUS_ATTR_TERMINATION_ACTION:
758                                /* Just remove */
759                                break;
760                       
761                        case RADIUS_ATTR_CALLED_STATION_ID:
762                                CONV2DIAM_STR( Called_Station_Id );
763                                break;
764                       
765                        case RADIUS_ATTR_CALLING_STATION_ID:
766                                CONV2DIAM_STR( Calling_Station_Id );
767                                break;
768                       
769                        case RADIUS_ATTR_NAS_IDENTIFIER:
770                                CONV2DIAM_STR( NAS_Identifier );
771                                break;
772                       
773                        /* Proxy-State is handled by echo_drop.rgwx plugin, we ignore it here */
774                       
775                        case RADIUS_ATTR_LOGIN_LAT_SERVICE:
776                                CONV2DIAM_STR( Login_LAT_Service );
777                                break;
778                       
779                        case RADIUS_ATTR_LOGIN_LAT_NODE:
780                                CONV2DIAM_STR( Login_LAT_Node );
781                                break;
782                       
783                        case RADIUS_ATTR_LOGIN_LAT_GROUP:
784                                CONV2DIAM_STR( Login_LAT_Group );
785                                break;
786                       
787                        case RADIUS_ATTR_FRAMED_APPLETALK_LINK:
788                                CONV2DIAM_32B( Framed_AppleTalk_Link );
789                                break;
790                               
791                        case RADIUS_ATTR_FRAMED_APPLETALK_NETWORK:
792                                CONV2DIAM_32B( Framed_AppleTalk_Network );
793                                break;
794                               
795                        case RADIUS_ATTR_FRAMED_APPLETALK_ZONE:
796                                CONV2DIAM_STR( Framed_AppleTalk_Zone );
797                                break;
798                       
799                        case RADIUS_ATTR_ACCT_STATUS_TYPE:
800                                /*
801                                      -  If the RADIUS message received is an Accounting-Request, the
802                                         Acct-Status-Type attribute value must be converted to a
803                                         Accounting-Record-Type AVP value.  If the Acct-Status-Type
804                                         attribute value is STOP, the local server MUST issue a
805                                         Session-Termination-Request message once the Diameter
806                                         Accounting-Answer message has been received.
807                                */
808                                switch (status_type) {
809                                        case RADIUS_ACCT_STATUS_TYPE_START:
810                                                value.u32 = ACV_ART_START_RECORD;
811                                                break;
812                                        case RADIUS_ACCT_STATUS_TYPE_STOP:
813                                                value.u32 = ACV_ART_STOP_RECORD;
814                                                send_str = 1; /* Register this info in the session */
815                                                break;
816                                        case RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE:
817                                                value.u32 = ACV_ART_INTERIM_RECORD;
818                                                break;
819                                        default:
820                                                TRACE_DEBUG(INFO, "Unknown RADIUS_ATTR_ACCT_STATUS_TYPE value %d, abording...", status_type);
821                                                return ENOTSUP;
822                                }
823                                CHECK_FCT( fd_msg_avp_new ( cs->dict.Accounting_Record_Type, 0, &avp ) );
824                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
825                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
826                               
827                                /* While here, we also add the Accouting-Record-Number AVP.
828                                          The Accounting-Record-Number AVP (AVP Code 485) is of type Unsigned32
829                                           and identifies this record within one session.  As Session-Id AVPs
830                                           are globally unique, the combination of Session-Id and Accounting-
831                                           Record-Number AVPs is also globally unique, and can be used in
832                                           matching accounting records with confirmations.  An easy way to
833                                           produce unique numbers is to set the value to 0 for records of type
834                                           EVENT_RECORD and START_RECORD, and set the value to 1 for the first
835                                           INTERIM_RECORD, 2 for the second, and so on until the value for
836                                           STOP_RECORD is one more than for the last INTERIM_RECORD.
837                                           
838                                  -- we actually use the end-to-end id of the message here, which remains constant
839                                    if we send a duplicate, so it has the same properties as the suggested algorithm.
840                                    Anyway, it assumes that we are not converting twice the same RADIUS message.
841                                   . */
842                                CHECK_FCT( fd_msg_avp_new ( cs->dict.Accounting_Record_Number, 0, &avp ) );
843                                value.u32 = e2eid;
844                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
845                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
846                               
847                                break;
848                       
849                        case RADIUS_ATTR_ACCT_DELAY_TIME:
850                                CONV2DIAM_32B( Acct_Delay_Time );
851                                break;
852                               
853                        /*
854                              -  If the RADIUS message contains the Accounting-Input-Octets,
855                                 Accounting-Input-Packets, Accounting-Output-Octets, or
856                                 Accounting-Output-Packets, these attributes must be converted
857                                 to the Diameter equivalents.  Further, if the Acct-Input-
858                                 Gigawords or Acct-Output-Gigawords attributes are present,
859                                 these must be used to properly compute the Diameter accounting
860                                 AVPs.
861                        */
862                        case RADIUS_ATTR_ACCT_INPUT_OCTETS:
863                                memset(&value, 0, sizeof(value));
864                                {
865                                        uint8_t * v = (uint8_t *)(attr + 1);
866                                        value.u64  = (v[0] << 24)
867                                                   | (v[1] << 16)
868                                                   | (v[2] <<  8)
869                                                   |  v[3] ;
870                                }
871                                value.u64 += ((uint64_t)gigawords_in << 32);
872                                CHECK_FCT( fd_msg_avp_new ( cs->dict.Accounting_Input_Octets, 0, &avp ) );
873                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
874                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
875                                break;
876                               
877                        case RADIUS_ATTR_ACCT_OUTPUT_OCTETS:
878                                memset(&value, 0, sizeof(value));
879                                {
880                                        uint8_t * v = (uint8_t *)(attr + 1);
881                                        value.u64  = (v[0] << 24)
882                                                   | (v[1] << 16)
883                                                   | (v[2] <<  8)
884                                                   |  v[3] ;
885                                }
886                                value.u64 += ((uint64_t)gigawords_out << 32);
887                                CHECK_FCT( fd_msg_avp_new ( cs->dict.Accounting_Output_Octets, 0, &avp ) );
888                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
889                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
890                                break;
891                               
892                        case RADIUS_ATTR_ACCT_SESSION_ID:
893                                CONV2DIAM_STR( Acct_Session_Id );
894                                break;
895                               
896                        case RADIUS_ATTR_ACCT_AUTHENTIC:
897                                CONV2DIAM_32B( Acct_Authentic );
898                                break;
899                               
900                        case RADIUS_ATTR_ACCT_SESSION_TIME:
901                                CONV2DIAM_32B( Acct_Session_Time );
902                                break;
903                               
904                        case RADIUS_ATTR_ACCT_INPUT_PACKETS:
905                                memset(&value, 0, sizeof(value));
906                                {
907                                        uint8_t * v = (uint8_t *)(attr + 1);
908                                        value.u64  = (v[0] << 24)
909                                                   | (v[1] << 16)
910                                                   | (v[2] <<  8)
911                                                   |  v[3] ;
912                                }
913                                /* value.u64 += (gigawords_in << 32); */
914                                CHECK_FCT( fd_msg_avp_new ( cs->dict.Accounting_Input_Packets, 0, &avp ) );
915                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
916                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
917                                break;
918                               
919                        case RADIUS_ATTR_ACCT_OUTPUT_PACKETS:
920                                memset(&value, 0, sizeof(value));
921                                {
922                                        uint8_t * v = (uint8_t *)(attr + 1);
923                                        value.u64  = (v[0] << 24)
924                                                   | (v[1] << 16)
925                                                   | (v[2] <<  8)
926                                                   |  v[3] ;
927                                }
928                                /* value.u64 += (gigawords_out << 32); */
929                                CHECK_FCT( fd_msg_avp_new ( cs->dict.Accounting_Output_Packets, 0, &avp ) );
930                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
931                                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
932                                break;
933                               
934                        /*
935                              -  If the Accounting message contains an Acct-Termination-Cause
936                                 attribute, it should be translated to the equivalent
937                                 Termination-Cause AVP value.
938                        */
939                        case RADIUS_ATTR_ACCT_TERMINATE_CAUSE:
940                                /* rfc4005#section-9.3.5 */
941                                {
942                                        uint8_t * v = (uint8_t *)(attr + 1);
943                                        str_cause  = (v[0] << 24)
944                                                   | (v[1] << 16)
945                                                   | (v[2] <<  8)
946                                                   |  v[3] ;
947                                }
948                                str_cause += 10; /* This seems to be the rule, we can modify later if needed */
949                                break;
950
951                        case RADIUS_ATTR_ACCT_MULTI_SESSION_ID:
952                                CONV2DIAM_STR( Acct_Multi_Session_Id );
953                                break;
954                               
955                        case RADIUS_ATTR_ACCT_LINK_COUNT:
956                                CONV2DIAM_32B( Acct_Link_Count );
957                                break;
958                               
959                        /* CHAP-Challenge is not present in Accounting-Request */
960                       
961                        case RADIUS_ATTR_NAS_PORT_TYPE:
962                                CONV2DIAM_32B( NAS_Port_Type );
963                                break;
964                       
965                        case RADIUS_ATTR_PORT_LIMIT:
966                                CONV2DIAM_32B( Port_Limit );
967                                break;
968                       
969                        case RADIUS_ATTR_LOGIN_LAT_PORT:
970                                CONV2DIAM_STR( Login_LAT_Port );
971                                break;
972                       
973                        /* RFC 3162 */ 
974                        case RADIUS_ATTR_NAS_IPV6_ADDRESS:
975                                CONV2DIAM_STR( NAS_IPv6_Address );
976                                break;
977                               
978                        case RADIUS_ATTR_FRAMED_INTERFACE_ID:
979                                CONV2DIAM_64B( Framed_Interface_Id );
980                                break;
981                               
982                        case RADIUS_ATTR_FRAMED_IPV6_PREFIX:
983                                CONV2DIAM_STR( Framed_IPv6_Prefix );
984                                break;
985                               
986                        case RADIUS_ATTR_LOGIN_IPV6_HOST:
987                                CONV2DIAM_STR( Login_IPv6_Host );
988                                break;
989                               
990                        case RADIUS_ATTR_FRAMED_IPV6_ROUTE:
991                                CONV2DIAM_STR( Framed_IPv6_Route );
992                                break;
993                               
994                        case RADIUS_ATTR_FRAMED_IPV6_POOL:
995                                CONV2DIAM_STR( Framed_IPv6_Pool );
996                                break;
997                               
998                        /* RFC 2868 */
999                        /* Prepare the top-level Tunneling AVP for each tag values, as needed, and add to the Diameter message.
1000                                This macro is called when an AVP is added inside the group, so we will not have empty grouped AVPs */
1001                        #define AVP_TUN_PREPARE() {                                                                             \
1002                                                if (avp_tun == NULL) {                                                          \
1003                                                        CHECK_MALLOC( avp_tun = calloc(sizeof(struct avp *), 32 ) );            \
1004                                                }                                                                               \
1005                                                tag = *(uint8_t *)(attr + 1);                                                   \
1006                                                if (tag > 0x1F) tag = 0;                                                        \
1007                                                if (avp_tun[tag] == NULL) {                                                     \
1008                                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Tunneling, 0, &avp_tun[tag] ) );   \
1009                                                        CHECK_FCT( fd_msg_avp_add (*diam_fw, MSG_BRW_LAST_CHILD, avp_tun[tag]));\
1010                                                }                                                                               \
1011                                        }
1012                       
1013                        /* Convert an attribute to an OctetString AVP and add inside the Tunneling AVP corresponding to the tag */
1014                        #define CONV2DIAM_TUN_STR( _dictobj_ ) {                                                \
1015                                uint8_t tag;                                                                    \
1016                                CHECK_PARAMS( attr->length >= 3);                                               \
1017                                AVP_TUN_PREPARE();                                                              \
1018                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
1019                                value.os.len = attr->length - (tag ? 3 : 2);                                    \
1020                                value.os.data = ((unsigned char *)(attr + 1)) + (tag ? 1 : 0);                  \
1021                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
1022                                CHECK_FCT( fd_msg_avp_add ( avp_tun[tag], MSG_BRW_LAST_CHILD, avp) );           \
1023                                }
1024                               
1025                        /* Convert an attribute to a scalar AVP and add inside the Tunneling AVP corresponding to the tag */
1026                        #define CONV2DIAM_TUN_24B( _dictobj_ ) {                                                \
1027                                uint8_t tag;                                                                    \
1028                                CHECK_PARAMS( attr->length == 6);                                               \
1029                                AVP_TUN_PREPARE();                                                              \
1030                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
1031                                {                                                                               \
1032                                        uint8_t * v = (uint8_t *)(attr + 1);                                    \
1033                                        value.u32 = (v[1] << 16) | (v[2] <<8) | v[3] ;                          \
1034                                }                                                                               \
1035                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
1036                                CHECK_FCT( fd_msg_avp_add ( avp_tun[tag], MSG_BRW_LAST_CHILD, avp) );           \
1037                                }
1038
1039                        /*
1040                              -  If the RADIUS message contains Tunnel information [RADTunnels],
1041                                 the attributes or tagged groups should each be converted to a
1042                                 Diameter Tunneling Grouped AVP set.  If the tunnel information
1043                                 contains a Tunnel-Password attribute, the RADIUS encryption
1044                                 must be resolved, and the password forwarded, by using Diameter
1045                                 security methods.
1046                                    -> If the RADIUS message does not use properly the Tag info, result is unpredictable here..
1047                        */
1048                        case RADIUS_ATTR_TUNNEL_TYPE:
1049                                CONV2DIAM_TUN_24B( Tunnel_Type );
1050                                break;
1051                       
1052                        case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
1053                                CONV2DIAM_TUN_24B( Tunnel_Medium_Type );
1054                                break;
1055                       
1056                        case RADIUS_ATTR_TUNNEL_CLIENT_ENDPOINT:
1057                                CONV2DIAM_TUN_STR( Tunnel_Client_Endpoint );
1058                                break;
1059                       
1060                        case RADIUS_ATTR_TUNNEL_SERVER_ENDPOINT:
1061                                CONV2DIAM_TUN_STR( Tunnel_Server_Endpoint );
1062                                break;
1063                       
1064                        /* Tunnel-Password never present in an Accounting-Request */
1065
1066                        case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
1067                                CONV2DIAM_TUN_STR( Tunnel_Private_Group_Id );
1068                                break;
1069                       
1070                        case RADIUS_ATTR_TUNNEL_ASSIGNMENT_ID:
1071                                CONV2DIAM_TUN_STR( Tunnel_Assignment_Id );
1072                                break;
1073                       
1074                        /* Tunnel-Reference never present in an Accounting-Request */
1075                       
1076                        case RADIUS_ATTR_TUNNEL_CLIENT_AUTH_ID:
1077                                CONV2DIAM_TUN_STR( Tunnel_Client_Auth_Id );
1078                                break;
1079                       
1080                        case RADIUS_ATTR_TUNNEL_SERVER_AUTH_ID:
1081                                CONV2DIAM_TUN_STR( Tunnel_Server_Auth_Id );
1082                                break;
1083                       
1084                /* RFC 2869 */
1085                        /*
1086                                                              Acct-Input-Gigawords, Acct-Output-
1087                           Gigawords, Event-Timestamp, and NAS-Port-Id may have 0-1 instances in
1088                           an Accounting-Request packet.  Connect-Info may have 0+ instances in
1089                           an Accounting-Request packet.  The other attributes added in this
1090                           document must not be present in an Accounting-Request.
1091                        */
1092                        case RADIUS_ATTR_ACCT_INPUT_GIGAWORDS:
1093                                break; /* we already saved the value in gigawords_in */
1094                               
1095                        case RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS:
1096                                break; /* we already saved the value in gigawords_out */
1097                               
1098                        case RADIUS_ATTR_EVENT_TIMESTAMP:
1099                                /* RADIUS:
1100                                      The Value field is four octets encoding an unsigned integer with
1101                                      the number of seconds since January 1, 1970 00:00 UTC.
1102                                   Diameter:
1103                                      The Time format is derived from the OctetString AVP Base Format.
1104                                      The string MUST contain four octets, in the same format as the
1105                                      first four bytes are in the NTP timestamp format.  The NTP
1106                                      Timestamp format is defined in Chapter 3 of [RFC4330].
1107
1108                                      This represents the number of seconds since 0h on 1 January 1900
1109                                      with respect to the Coordinated Universal Time (UTC).
1110                                     
1111                                      -- RFC4330:
1112                                         NTP timestamps are represented as a 64-bit unsigned
1113                                           fixed-point number, in seconds relative to 0h on 1 January 1900.  The
1114                                           integer part is in the first 32 bits, and the fraction part in the
1115                                           last 32 bits.  In the fraction part, the non-significant low-order
1116                                           bits are not specified and are ordinarily set to 0.
1117                                */
1118                                {
1119                                        uint32_t ts;
1120                                       
1121                                        uint8_t * v = (uint8_t *)(attr + 1);
1122                                        /* Read the RADIUS attribute value */
1123                                        ts  = (v[0] << 24)
1124                                                   | (v[1] << 16)
1125                                                   | (v[2] <<  8)
1126                                                   |  v[3] ;
1127                                       
1128                                        /* Add the 70 missing years */
1129                                        ts += 2208988800U; /* 60 * 60 * 24 * ( 365 * 70 + 17 ) */
1130                                       
1131                                        /* Convert to network byte order */
1132                                        ts = htonl(ts);
1133                                       
1134                                         /* Diameter Time datatype is derived from OctetString */
1135                                        value.os.data = (void *) &ts;
1136                                        value.os.len = sizeof(uint32_t);
1137                                       
1138                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Event_Timestamp, 0, &avp ) );
1139                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
1140                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
1141                                }
1142                                break;
1143                       
1144                        case RADIUS_ATTR_NAS_PORT_ID:
1145                                CONV2DIAM_STR( NAS_Port_Id );
1146                                break;
1147                                               
1148                        case RADIUS_ATTR_CONNECT_INFO:
1149                                CONV2DIAM_STR( Connect_Info );
1150                                break;
1151                       
1152                        case RADIUS_ATTR_FRAMED_POOL: /* To follow the IPv6 version */
1153                                CONV2DIAM_STR( Framed_Pool );
1154                                break;
1155                               
1156                       
1157                /* RFC 3579 */
1158                        /*
1159                         The EAP-Message and Message-Authenticator attributes specified in
1160                           this document MUST NOT be present in an Accounting-Request.
1161                        */                             
1162                        case RADIUS_ATTR_ORIGINATING_LINE_INFO:
1163                                CONV2DIAM_STR( Originating_Line_Info );
1164                                break;
1165                               
1166                /* Default */           
1167                        default: /* unknown attribute */
1168                                /* We just keep the attribute in the RADIUS message */
1169                                rad_req->attr_pos[nattr_used++] = rad_req->attr_pos[idx];
1170                }
1171        }
1172       
1173        /* Update the radius message to remove all handled attributes */
1174        rad_req->attr_used = nattr_used;
1175       
1176        /* Store useful information in the session */
1177        {
1178                struct sess_state * st;
1179                CHECK_PARAMS(session);
1180               
1181                CHECK_MALLOC( st = malloc(sizeof(struct sess_state)) );
1182                memset(st, 0, sizeof(struct sess_state));
1183                st->auth_appl = auth_appl;
1184                if (auth_appl) { /* We use the value 0 for servers which indicated NO STATE MAINTAINED, hence have no need for STR */
1185                        st->send_str = send_str;
1186                }
1187                st->term_cause = str_cause;
1188                CHECK_FCT( fd_sess_state_store( cs->sess_hdl, *session, &st ) );
1189        }
1190       
1191        return 0;
1192}
1193
1194/* Callback when an STA is received after having sent an STR. */
1195static void handle_sta(void * data, struct msg ** answer)
1196{
1197        struct rgwp_config * cs = data;
1198        struct avp *avp;
1199        struct avp_hdr *ahdr;
1200       
1201        CHECK_PARAMS_DO( data && answer && *answer, goto out );
1202       
1203        /* Check the Diameter error code */
1204        CHECK_FCT_DO( fd_msg_search_avp (*answer, cs->dict.Result_Code, &avp), goto out );
1205        CHECK_PARAMS_DO( avp, goto out );
1206        CHECK_FCT_DO( fd_msg_avp_hdr ( avp, &ahdr ), goto out );
1207        if (ahdr->avp_value->u32 != ER_DIAMETER_SUCCESS)
1208                goto out;
1209       
1210        /* OK, discard the message without complaining */
1211        fd_msg_free(*answer);
1212        *answer = NULL;
1213               
1214out:
1215        if (answer && *answer) {
1216                TRACE_DEBUG(INFO, "Received the following problematic STA message, discarding anyway...");
1217                fd_msg_dump_walk( INFO, *answer );
1218                fd_msg_free(*answer);
1219                *answer = NULL;
1220        }
1221        return;
1222}
1223
1224static int acct_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli, int * stateful )
1225{
1226        struct sess_state * st = NULL, stloc;
1227        struct avp *avp, *next;
1228        struct avp_hdr *ahdr, *sid, *oh, *or;
1229       
1230        TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
1231        CHECK_PARAMS(cs);
1232       
1233        if (session) {
1234                CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, session, &st ) );
1235        }
1236       
1237        if (!st) {
1238                TRACE_DEBUG(INFO, "Received an ACA without corresponding session information, cannot translate to RADIUS");
1239                return EINVAL;
1240        }
1241       
1242        /* Free the state */
1243        memcpy(&stloc, st, sizeof(struct sess_state));
1244        free(st);
1245        st = &stloc;
1246       
1247        /* Search these AVPs first */
1248        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Session_Id, &avp) );
1249        CHECK_FCT( fd_msg_avp_hdr ( avp, &sid ) );
1250       
1251        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Host, &avp) );
1252        CHECK_FCT( fd_msg_avp_hdr ( avp, &oh ) );
1253
1254        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Origin_Realm, &avp) );
1255        CHECK_FCT( fd_msg_avp_hdr ( avp, &or ) );
1256
1257        /* Check the Diameter error code */
1258        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Result_Code, &avp) );
1259        ASSERT( avp ); /* otherwise the message should have been discarded a lot earlier because of ABNF */
1260        CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1261        switch (ahdr->avp_value->u32) {
1262                case ER_DIAMETER_SUCCESS:
1263                case ER_DIAMETER_LIMITED_SUCCESS:
1264                        (*rad_fw)->hdr->code = RADIUS_CODE_ACCOUNTING_RESPONSE;
1265                        break;
1266               
1267                default:
1268                        fd_log_debug("[acct.rgwx] Received Diameter answer with error code '%d' from server '%.*s', session %.*s, not translating into Accounting-Response\n",
1269                                        ahdr->avp_value->u32, 
1270                                        oh->avp_value->os.len, oh->avp_value->os.data,
1271                                        sid->avp_value->os.len, sid->avp_value->os.data);
1272                        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Error_Message, &avp) );
1273                        if (avp) {
1274                                CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1275                                fd_log_debug("[acct.rgwx]   Error-Message content: '%.*s'\n",
1276                                                ahdr->avp_value->os.len, ahdr->avp_value->os.data);
1277                        }
1278                        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Error_Reporting_Host, &avp) );
1279                        if (avp) {
1280                                CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1281                                fd_log_debug("[acct.rgwx]   Error-Reporting-Host: '%.*s'\n",
1282                                                ahdr->avp_value->os.len, ahdr->avp_value->os.data);
1283                        }
1284                        CHECK_FCT( fd_msg_search_avp (*diam_ans, cs->dict.Failed_AVP, &avp) );
1285                        if (avp) {
1286                                fd_log_debug("[acct.rgwx]   Failed-AVP was included in the message.\n");
1287                                /* Dump its content ? */
1288                        }
1289                       
1290                        /* Now, destroy the Diameter message, since we know it is not converted to RADIUS */
1291                        CHECK_FCT( fd_msg_free(*diam_ans) );
1292                        *diam_ans = NULL;
1293
1294                        return -1;
1295        }
1296        /* Remove this Result-Code avp */
1297        CHECK_FCT( fd_msg_free( avp ) );
1298       
1299        /* If it was a response to a STOP record, we must send an STR for this session */
1300        if (st->send_str) {
1301                struct msg * str = NULL;
1302                struct msg_hdr * hdr = NULL;
1303                char * fqdn;
1304                char * realm;
1305                union avp_value avp_val;
1306               
1307                /* Create a new STR message */
1308                CHECK_FCT(  fd_msg_new ( cs->dict.Session_Termination_Request, MSGFL_ALLOC_ETEID, &str )  );
1309               
1310                /* Set the application-id to the auth application if available, accouting otherwise (not sure what is actually expected...) */
1311                CHECK_FCT( fd_msg_hdr ( str, &hdr ) );
1312                hdr->msg_appl = st->auth_appl ?: AI_ACCT;
1313               
1314                /* Add the Session-Id AVP as first AVP */
1315                CHECK_FCT( fd_msg_avp_new (  cs->dict.Session_Id, 0, &avp ) );
1316                CHECK_FCT( fd_msg_avp_setvalue ( avp, sid->avp_value ) );
1317                CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_FIRST_CHILD, avp) );
1318
1319                /* Add the Destination-Realm as next AVP */
1320                CHECK_FCT( fd_msg_avp_new ( cs->dict.Destination_Realm, 0, &avp ) );
1321                CHECK_FCT( fd_msg_avp_setvalue ( avp, or->avp_value ) );
1322                CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_LAST_CHILD, avp) );
1323
1324                /* Get information on the NAS */
1325                CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
1326
1327                /* Add the Origin-Host as next AVP */
1328                CHECK_FCT( fd_msg_avp_new ( cs->dict.Origin_Host, 0, &avp ) );
1329                memset(&avp_val, 0, sizeof(avp_val));
1330                avp_val.os.data = (unsigned char *)fqdn;
1331                avp_val.os.len = strlen(fqdn);
1332                CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
1333                CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_LAST_CHILD, avp) );
1334
1335                /* Add the Origin-Realm as next AVP */
1336                CHECK_FCT( fd_msg_avp_new ( cs->dict.Origin_Realm, 0, &avp ) );
1337                memset(&avp_val, 0, sizeof(avp_val));
1338                avp_val.os.data = (unsigned char *)realm;
1339                avp_val.os.len = strlen(realm);
1340                CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
1341                CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_LAST_CHILD, avp) );
1342               
1343                /* Auth-Application-Id -- if we did not get it from our Class attribute, we just set "0" */
1344                CHECK_FCT( fd_msg_avp_new ( cs->dict.Auth_Application_Id, 0, &avp ) );
1345                avp_val.u32 = st->auth_appl;
1346                CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
1347                CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_LAST_CHILD, avp) );
1348               
1349                /* Termination-Cause */
1350                CHECK_FCT( fd_msg_avp_new ( cs->dict.Termination_Cause, 0, &avp ) );
1351                avp_val.u32 = st->term_cause;
1352                CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
1353                CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_LAST_CHILD, avp) );
1354               
1355                /* Send this message */
1356                CHECK_FCT( fd_msg_send ( &str, handle_sta, cs ) );
1357        }
1358       
1359        /*
1360                No attributes should be found in
1361                   Accounting-Response packets except Proxy-State and possibly Vendor-
1362                   Specific.
1363        */
1364
1365        /* Now loop in the list of AVPs and convert those that we know how */
1366        CHECK_FCT( fd_msg_browse(*diam_ans, MSG_BRW_FIRST_CHILD, &next, NULL) );
1367       
1368        while (next) {
1369                int handled = 1;
1370                avp = next;
1371                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &next, NULL) );
1372               
1373                CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
1374               
1375                if (!(ahdr->avp_flags & AVP_FLAG_VENDOR)) {
1376                        switch (ahdr->avp_code) {
1377                                /* Based on RFC4005, sec 3.10 */
1378                                case DIAM_ATTR_SESSION_ID:
1379                                case DIAM_ATTR_ORIGIN_HOST:
1380                                case DIAM_ATTR_ORIGIN_REALM:
1381                                case DIAM_ATTR_ACCOUNTING_RECORD_TYPE:
1382                                case DIAM_ATTR_ACCOUNTING_RECORD_NUMBER:
1383                                case DIAM_ATTR_ACCT_APPLICATION_ID:
1384                                case DIAM_ATTR_VENDOR_SPECIFIC_APPLICATION_ID:
1385                                case DIAM_ATTR_USER_NAME:
1386                                case DIAM_ATTR_ACCOUNTING_SUB_SESSION_ID:
1387                                case DIAM_ATTR_ACCT_SESSION_ID:
1388                                case DIAM_ATTR_ACCT_MULTI_SESSION_ID:
1389                                case DIAM_ATTR_EVENT_TIMESTAMP:
1390                                case DIAM_ATTR_ORIGIN_AAA_PROTOCOL:
1391                                case DIAM_ATTR_ORIGIN_STATE_ID:
1392                                case DIAM_ATTR_NAS_IDENTIFIER:
1393                                case DIAM_ATTR_NAS_IP_ADDRESS:
1394                                case DIAM_ATTR_NAS_IPV6_ADDRESS:
1395                                case DIAM_ATTR_NAS_PORT:
1396                                case DIAM_ATTR_NAS_PORT_ID:
1397                                case DIAM_ATTR_NAS_PORT_TYPE:
1398                                case DIAM_ATTR_SERVICE_TYPE:
1399                                case DIAM_ATTR_TERMINATION_CAUSE:
1400                                case DIAM_ATTR_ACCOUNTING_REALTIME_REQUIRED:
1401                                case DIAM_ATTR_ACCT_INTERIM_INTERVAL:
1402                                case DIAM_ATTR_CLASS:
1403                                        /* We just remove these AVP, they are not expected in RADIUS client */
1404                                        break;
1405                                       
1406                                default:
1407                                        /* Leave the AVP in the message for further treatment */
1408                                        handled = 0;
1409                        }
1410                } else {
1411                        /* Vendor-specific AVPs */
1412                        switch (ahdr->avp_vendor) {
1413                               
1414                                default: /* unknown vendor */
1415                                        handled = 0;
1416                        }
1417                }
1418               
1419                if (handled) {
1420                        CHECK_FCT( fd_msg_free( avp ) );
1421                }
1422        }
1423       
1424        /*
1425              The Authenticator field in an Accounting-Response packet is called
1426              the Response Authenticator, and contains a one-way MD5 hash
1427              calculated over a stream of octets consisting of the Accounting-
1428              Response Code, Identifier, Length, the Request Authenticator field
1429              from the Accounting-Request packet being replied to, and the
1430              response attributes if any, followed by the shared secret.  The
1431              resulting 16 octet MD5 hash value is stored in the Authenticator
1432              field of the Accounting-Response packet.
1433             
1434              -- done in radius_msg_finish_srv
1435        */
1436
1437        return 0;
1438}
1439
1440/* The exported symbol */
1441struct rgw_api rgwp_descriptor = {
1442        .rgwp_name       = "acct",
1443        .rgwp_conf_parse = acct_conf_parse,
1444        .rgwp_conf_free  = acct_conf_free,
1445        .rgwp_rad_req    = acct_rad_req,
1446        .rgwp_diam_ans   = acct_diam_ans
1447};     
Note: See TracBrowser for help on using the repository browser.