summaryrefslogtreecommitdiff
path: root/accel-pppd/radius
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/radius')
-rw-r--r--accel-pppd/radius/CMakeLists.txt19
-rw-r--r--accel-pppd/radius/acct.c328
-rw-r--r--accel-pppd/radius/attr_defs.h287
-rw-r--r--accel-pppd/radius/auth.c497
-rw-r--r--accel-pppd/radius/dict.c356
-rw-r--r--accel-pppd/radius/dict/dictionary79
-rw-r--r--accel-pppd/radius/dict/dictionary.cisco156
-rw-r--r--accel-pppd/radius/dict/dictionary.microsoft83
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc2865137
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc286657
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc286716
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc286854
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc286939
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc357630
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc358016
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc40729
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc43728
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc467528
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc467962
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc481811
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc48498
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc51769
-rw-r--r--accel-pppd/radius/dict2c.py20
-rw-r--r--accel-pppd/radius/dm_coa.c295
-rw-r--r--accel-pppd/radius/packet.c644
-rw-r--r--accel-pppd/radius/radius.c529
-rw-r--r--accel-pppd/radius/radius.h117
-rw-r--r--accel-pppd/radius/radius_p.h122
-rw-r--r--accel-pppd/radius/req.c277
29 files changed, 4293 insertions, 0 deletions
diff --git a/accel-pppd/radius/CMakeLists.txt b/accel-pppd/radius/CMakeLists.txt
new file mode 100644
index 00000000..322bee51
--- /dev/null
+++ b/accel-pppd/radius/CMakeLists.txt
@@ -0,0 +1,19 @@
+SET(sources
+ dict.c
+ req.c
+ packet.c
+ auth.c
+ acct.c
+ dm_coa.c
+ radius.c
+)
+
+ADD_DEFINITIONS(-DDICTIONARY="${CMAKE_INSTALL_PREFIX}/share/accel-ppp/radius/dictionary")
+
+ADD_LIBRARY(radius SHARED ${sources})
+
+INSTALL(TARGETS radius
+ LIBRARY DESTINATION lib/accel-ppp
+)
+FILE(GLOB dict "${CMAKE_CURRENT_SOURCE_DIR}/dict/*")
+INSTALL(FILES ${dict} DESTINATION share/accel-ppp/radius)
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c
new file mode 100644
index 00000000..ddb3e086
--- /dev/null
+++ b/accel-pppd/radius/acct.c
@@ -0,0 +1,328 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include "linux_ppp.h"
+
+#include <openssl/md5.h>
+
+#include "log.h"
+#include "radius_p.h"
+
+#include "memdebug.h"
+
+#define STAT_UPDATE_INTERVAL (10 * 60 * 1000)
+
+static int req_set_RA(struct rad_req_t *req, const char *secret)
+{
+ MD5_CTX ctx;
+
+ if (rad_packet_build(req->pack, req->RA))
+ return -1;
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, req->pack->buf, req->pack->len);
+ MD5_Update(&ctx, secret, strlen(secret));
+ MD5_Final(req->pack->buf + 4, &ctx);
+
+ return 0;
+}
+
+static void req_set_stat(struct rad_req_t *req, struct ppp_t *ppp)
+{
+ struct ifpppstatsreq ifreq;
+ time_t stop_time;
+
+ if (ppp->stop_time)
+ stop_time = ppp->stop_time;
+ else
+ time(&stop_time);
+
+ memset(&ifreq, 0, sizeof(ifreq));
+ ifreq.stats_ptr = (void *)&ifreq.stats;
+ strcpy(ifreq.ifr__name, ppp->ifname);
+
+ if (ioctl(sock_fd, SIOCGPPPSTATS, &ifreq)) {
+ log_ppp_error("radius: failed to get ppp statistics: %s\n", strerror(errno));
+ return;
+ }
+
+ if (ifreq.stats.p.ppp_ibytes < req->rpd->acct_input_octets)
+ req->rpd->acct_input_gigawords++;
+ req->rpd->acct_input_octets = ifreq.stats.p.ppp_ibytes;
+
+ if (ifreq.stats.p.ppp_obytes < req->rpd->acct_output_octets)
+ req->rpd->acct_output_gigawords++;
+ req->rpd->acct_output_octets = ifreq.stats.p.ppp_obytes;
+
+ rad_packet_change_int(req->pack, NULL, "Acct-Input-Octets", ifreq.stats.p.ppp_ibytes);
+ rad_packet_change_int(req->pack, NULL, "Acct-Output-Octets", ifreq.stats.p.ppp_obytes);
+ rad_packet_change_int(req->pack, NULL, "Acct-Input-Packets", ifreq.stats.p.ppp_ipackets);
+ rad_packet_change_int(req->pack, NULL, "Acct-Output-Packets", ifreq.stats.p.ppp_opackets);
+ rad_packet_change_int(req->pack, NULL, "Acct-Input-Gigawords", req->rpd->acct_input_gigawords);
+ rad_packet_change_int(req->pack, NULL, "Acct-Output-Gigawords", req->rpd->acct_output_gigawords);
+ rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", stop_time - ppp->start_time);
+}
+
+static int rad_acct_read(struct triton_md_handler_t *h)
+{
+ struct rad_req_t *req = container_of(h, typeof(*req), hnd);
+ struct rad_packet_t *pack;
+ int r;
+
+ if (req->reply) {
+ rad_packet_free(req->reply);
+ req->reply = NULL;
+ }
+
+ while (1) {
+ r = rad_packet_recv(h->fd, &pack, NULL);
+
+ if (pack) {
+ if (req->reply)
+ rad_packet_free(req->reply);
+ req->reply = pack;
+ if (conf_interim_verbose) {
+ log_ppp_info2("recv ");
+ rad_packet_print(req->reply, log_ppp_info2);
+ }
+ }
+
+ if (r)
+ break;
+ }
+
+ if (!req->reply)
+ return 0;
+
+ if (req->reply->code != CODE_ACCOUNTING_RESPONSE || req->reply->id != req->pack->id) {
+ rad_packet_free(req->reply);
+ req->reply = NULL;
+ } else {
+ if (req->timeout.tpd)
+ triton_timer_del(&req->timeout);
+ }
+
+ return 0;
+}
+
+static void rad_acct_timeout(struct triton_timer_t *t)
+{
+ struct rad_req_t *req = container_of(t, typeof(*req), timeout);
+ time_t ts, dt;
+
+ __sync_add_and_fetch(&stat_interim_lost, 1);
+
+ time(&ts);
+
+ dt = ts - req->rpd->acct_timestamp;
+
+ if (dt > conf_acct_timeout) {
+ log_ppp_warn("radius:acct: no response, terminating session...\n");
+ ppp_terminate(req->rpd->ppp, TERM_NAS_ERROR, 0);
+ return;
+ }
+ if (dt > conf_acct_timeout / 2) {
+ req->timeout.period += 1000;
+ triton_timer_mod(&req->timeout, 0);
+ } else if (dt > conf_acct_timeout / 3) {
+ if (req->timeout.period != conf_timeout * 2000) {
+ req->timeout.period = conf_timeout * 2000;
+ triton_timer_mod(&req->timeout, 0);
+ }
+ }
+
+ req->pack->id++;
+
+ rad_packet_change_int(req->pack, NULL, "Acct-Delay-Time", dt);
+ req_set_RA(req, conf_acct_secret);
+ rad_req_send(req, conf_interim_verbose);
+ __sync_add_and_fetch(&stat_interim_sent, 1);
+}
+
+static void rad_acct_interim_update(struct triton_timer_t *t)
+{
+ struct radius_pd_t *rpd = container_of(t, typeof(*rpd), acct_interim_timer);
+
+ if (rpd->acct_req->timeout.tpd)
+ return;
+
+ req_set_stat(rpd->acct_req, rpd->ppp);
+ if (!rpd->acct_interim_interval)
+ return;
+
+ time(&rpd->acct_timestamp);
+ rpd->acct_req->pack->id++;
+
+ rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Interim-Update");
+ rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", 0);
+ req_set_RA(rpd->acct_req, conf_acct_secret);
+ rad_req_send(rpd->acct_req, conf_interim_verbose);
+ __sync_add_and_fetch(&stat_interim_sent, 1);
+ if (conf_acct_timeout) {
+ rpd->acct_req->timeout.period = conf_timeout * 1000;
+ triton_timer_add(rpd->ppp->ctrl->ctx, &rpd->acct_req->timeout, 0);
+ }
+}
+
+int rad_acct_start(struct radius_pd_t *rpd)
+{
+ int i;
+ time_t ts;
+
+ rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ppp->username);
+ if (!rpd->acct_req) {
+ log_emerg("radius: out of memory\n");
+ return -1;
+ }
+
+ if (rad_req_acct_fill(rpd->acct_req)) {
+ log_ppp_error("radius:acct: failed to fill accounting attributes\n");
+ goto out_err;
+ }
+
+ //if (rad_req_add_val(rpd->acct_req, "Acct-Status-Type", "Start", 4))
+ // goto out_err;
+ //if (rad_req_add_str(rpd->acct_req, "Acct-Session-Id", rpd->ppp->sessionid, PPP_SESSIONID_LEN, 1))
+ // goto out_err;
+
+ if (rpd->acct_req->reply) {
+ rad_packet_free(rpd->acct_req->reply);
+ rpd->acct_req->reply = NULL;
+ }
+
+ time(&rpd->acct_timestamp);
+
+ for (i = 0; i < conf_max_try; i++) {
+ time(&ts);
+ rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
+ if (req_set_RA(rpd->acct_req, conf_acct_secret))
+ goto out_err;
+ if (rad_req_send(rpd->acct_req, conf_verbose))
+ goto out_err;
+ __sync_add_and_fetch(&stat_acct_sent, 1);
+ rad_req_wait(rpd->acct_req, conf_timeout);
+ if (!rpd->acct_req->reply) {
+ rpd->acct_req->pack->id++;
+ __sync_add_and_fetch(&stat_acct_lost, 1);
+ continue;
+ }
+ if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
+ rad_packet_free(rpd->acct_req->reply);
+ rpd->acct_req->reply = NULL;
+ rpd->acct_req->pack->id++;
+ __sync_add_and_fetch(&stat_acct_lost, 1);
+ } else
+ break;
+ }
+
+ if (!rpd->acct_req->reply) {
+ log_ppp_warn("radius:acct_start: no response\n");
+ goto out_err;
+ }
+
+ rpd->acct_req->hnd.read = rad_acct_read;
+
+ triton_md_register_handler(rpd->ppp->ctrl->ctx, &rpd->acct_req->hnd);
+ if (triton_md_enable_handler(&rpd->acct_req->hnd, MD_MODE_READ))
+ goto out_err;
+
+ rpd->acct_req->timeout.expire = rad_acct_timeout;
+ rpd->acct_req->timeout.period = conf_timeout * 1000;
+
+ rpd->acct_interim_timer.expire = rad_acct_interim_update;
+ rpd->acct_interim_timer.period = rpd->acct_interim_interval ? rpd->acct_interim_interval * 1000 : STAT_UPDATE_INTERVAL;
+ if (rpd->acct_interim_interval && triton_timer_add(rpd->ppp->ctrl->ctx, &rpd->acct_interim_timer, 0)) {
+ triton_md_unregister_handler(&rpd->acct_req->hnd);
+ triton_timer_del(&rpd->acct_req->timeout);
+ goto out_err;
+ }
+ return 0;
+
+out_err:
+ rad_req_free(rpd->acct_req);
+ rpd->acct_req = NULL;
+ return -1;
+}
+
+void rad_acct_stop(struct radius_pd_t *rpd)
+{
+ int i;
+ time_t ts;
+
+ if (rpd->acct_interim_timer.tpd)
+ triton_timer_del(&rpd->acct_interim_timer);
+
+ if (rpd->acct_req) {
+ triton_md_unregister_handler(&rpd->acct_req->hnd);
+ if (rpd->acct_req->timeout.tpd)
+ triton_timer_del(&rpd->acct_req->timeout);
+
+ switch (rpd->ppp->terminate_cause) {
+ case TERM_USER_REQUEST:
+ rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "User-Request");
+ break;
+ case TERM_SESSION_TIMEOUT:
+ rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Session-Timeout");
+ break;
+ case TERM_ADMIN_RESET:
+ rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Admin-Reset");
+ break;
+ case TERM_USER_ERROR:
+ case TERM_AUTH_ERROR:
+ rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "User-Error");
+ break;
+ case TERM_NAS_ERROR:
+ rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Error");
+ break;
+ case TERM_NAS_REQUEST:
+ rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Request");
+ break;
+ case TERM_NAS_REBOOT:
+ rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Reboot");
+ break;
+ }
+ rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Stop");
+ req_set_stat(rpd->acct_req, rpd->ppp);
+ req_set_RA(rpd->acct_req, conf_acct_secret);
+ /// !!! rad_req_add_val(rpd->acct_req, "Acct-Terminate-Cause", "");
+
+ if (rpd->acct_req->reply) {
+ rad_packet_free(rpd->acct_req->reply);
+ rpd->acct_req->reply = NULL;
+ }
+
+ time(&rpd->acct_timestamp);
+
+ for(i = 0; i < conf_max_try; i++) {
+ time(&ts);
+ rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
+ rpd->acct_req->pack->id++;
+ if (req_set_RA(rpd->acct_req, conf_acct_secret))
+ break;
+ if (rad_req_send(rpd->acct_req, conf_verbose))
+ break;
+ __sync_add_and_fetch(&stat_acct_sent, 1);
+ rad_req_wait(rpd->acct_req, conf_timeout);
+ if (!rpd->acct_req->reply) {
+ __sync_add_and_fetch(&stat_acct_lost, 1);
+ continue;
+ }
+ if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
+ rad_packet_free(rpd->acct_req->reply);
+ rpd->acct_req->reply = NULL;
+ __sync_add_and_fetch(&stat_acct_lost, 1);
+ } else
+ break;
+ }
+ if (!rpd->acct_req->reply)
+ log_ppp_warn("radius:acct_stop: no response\n");
+
+ rad_req_free(rpd->acct_req);
+ rpd->acct_req = NULL;
+ }
+}
+
diff --git a/accel-pppd/radius/attr_defs.h b/accel-pppd/radius/attr_defs.h
new file mode 100644
index 00000000..e9b617e4
--- /dev/null
+++ b/accel-pppd/radius/attr_defs.h
@@ -0,0 +1,287 @@
+#define User_Name 1
+#define User_Password 2
+#define CHAP_Password 3
+#define NAS_IP_Address 4
+#define NAS_Port 5
+#define Service_Type 6
+#define Framed_Protocol 7
+#define Framed_IP_Address 8
+#define Framed_IP_Netmask 9
+#define Framed_Routing 10
+#define Filter_Id 11
+#define Framed_MTU 12
+#define Framed_Compression 13
+#define Login_IP_Host 14
+#define Login_Service 15
+#define Login_TCP_Port 16
+#define Reply_Message 18
+#define Callback_Number 19
+#define Callback_Id 20
+#define Framed_Route 22
+#define Framed_IPX_Network 23
+#define State 24
+#define Class 25
+#define Vendor_Specific 26
+#define Session_Timeout 27
+#define Idle_Timeout 28
+#define Termination_Action 29
+#define Called_Station_Id 30
+#define Calling_Station_Id 31
+#define NAS_Identifier 32
+#define Proxy_State 33
+#define Login_LAT_Service 34
+#define Login_LAT_Node 35
+#define Login_LAT_Group 36
+#define Framed_AppleTalk_Link 37
+#define Framed_AppleTalk_Network 38
+#define Framed_AppleTalk_Zone 39
+#define CHAP_Challenge 60
+#define NAS_Port_Type 61
+#define Port_Limit 62
+#define Login_LAT_Port 63
+#define Service_Type_Login_User 1
+#define Service_Type_Framed_User 2
+#define Service_Type_Callback_Login_User 3
+#define Service_Type_Callback_Framed_User 4
+#define Service_Type_Outbound_User 5
+#define Service_Type_Administrative_User 6
+#define Service_Type_NAS_Prompt_User 7
+#define Service_Type_Authenticate_Only 8
+#define Service_Type_Callback_NAS_Prompt 9
+#define Service_Type_Call_Check 10
+#define Service_Type_Callback_Administrative 11
+#define Framed_Protocol_PPP 1
+#define Framed_Protocol_SLIP 2
+#define Framed_Protocol_ARAP 3
+#define Framed_Protocol_Gandalf_SLML 4
+#define Framed_Protocol_Xylogics_IPX_SLIP 5
+#define Framed_Protocol_X_75_Synchronous 6
+#define Framed_Routing_None 0
+#define Framed_Routing_Broadcast 1
+#define Framed_Routing_Listen 2
+#define Framed_Routing_Broadcast_Listen 3
+#define Framed_Compression_None 0
+#define Framed_Compression_Van_Jacobson_TCP_IP 1
+#define Framed_Compression_IPX_Header_Compression 2
+#define Framed_Compression_Stac_LZS 3
+#define Login_Service_Telnet 0
+#define Login_Service_Rlogin 1
+#define Login_Service_TCP_Clear 2
+#define Login_Service_PortMaster 3
+#define Login_Service_LAT 4
+#define Login_Service_X25_PAD 5
+#define Login_Service_X25_T3POS 6
+#define Login_Service_TCP_Clear_Quiet 8
+#define Login_TCP_Port_Telnet 23
+#define Login_TCP_Port_Rlogin 513
+#define Login_TCP_Port_Rsh 514
+#define Termination_Action_Default 0
+#define Termination_Action_RADIUS_Request 1
+#define NAS_Port_Type_Async 0
+#define NAS_Port_Type_Sync 1
+#define NAS_Port_Type_ISDN 2
+#define NAS_Port_Type_ISDN_V120 3
+#define NAS_Port_Type_ISDN_V110 4
+#define NAS_Port_Type_Virtual 5
+#define NAS_Port_Type_PIAFS 6
+#define NAS_Port_Type_HDLC_Clear_Channel 7
+#define NAS_Port_Type_X_25 8
+#define NAS_Port_Type_X_75 9
+#define NAS_Port_Type_G_3_Fax 10
+#define NAS_Port_Type_SDSL 11
+#define NAS_Port_Type_ADSL_CAP 12
+#define NAS_Port_Type_ADSL_DMT 13
+#define NAS_Port_Type_IDSL 14
+#define NAS_Port_Type_Ethernet 15
+#define NAS_Port_Type_xDSL 16
+#define NAS_Port_Type_Cable 17
+#define NAS_Port_Type_Wireless_Other 18
+#define NAS_Port_Type_Wireless_802_11 19
+#define Acct_Status_Type 40
+#define Acct_Delay_Time 41
+#define Acct_Input_Octets 42
+#define Acct_Output_Octets 43
+#define Acct_Session_Id 44
+#define Acct_Authentic 45
+#define Acct_Session_Time 46
+#define Acct_Input_Packets 47
+#define Acct_Output_Packets 48
+#define Acct_Terminate_Cause 49
+#define Acct_Multi_Session_Id 50
+#define Acct_Link_Count 51
+#define Acct_Status_Type_Start 1
+#define Acct_Status_Type_Stop 2
+#define Acct_Status_Type_Alive 3
+#define Acct_Status_Type_Interim_Update 3
+#define Acct_Status_Type_Accounting_On 7
+#define Acct_Status_Type_Accounting_Off 8
+#define Acct_Status_Type_Failed 15
+#define Acct_Authentic_RADIUS 1
+#define Acct_Authentic_Local 2
+#define Acct_Authentic_Remote 3
+#define Acct_Authentic_Diameter 4
+#define Acct_Terminate_Cause_User_Request 1
+#define Acct_Terminate_Cause_Lost_Carrier 2
+#define Acct_Terminate_Cause_Lost_Service 3
+#define Acct_Terminate_Cause_Idle_Timeout 4
+#define Acct_Terminate_Cause_Session_Timeout 5
+#define Acct_Terminate_Cause_Admin_Reset 6
+#define Acct_Terminate_Cause_Admin_Reboot 7
+#define Acct_Terminate_Cause_Port_Error 8
+#define Acct_Terminate_Cause_NAS_Error 9
+#define Acct_Terminate_Cause_NAS_Request 10
+#define Acct_Terminate_Cause_NAS_Reboot 11
+#define Acct_Terminate_Cause_Port_Unneeded 12
+#define Acct_Terminate_Cause_Port_Preempted 13
+#define Acct_Terminate_Cause_Port_Suspended 14
+#define Acct_Terminate_Cause_Service_Unavailable 15
+#define Acct_Terminate_Cause_Callback 16
+#define Acct_Terminate_Cause_User_Error 17
+#define Acct_Terminate_Cause_Host_Request 18
+#define Acct_Tunnel_Connection 68
+#define Acct_Tunnel_Packets_Lost 86
+#define Acct_Status_Type_Tunnel_Start 9
+#define Acct_Status_Type_Tunnel_Stop 10
+#define Acct_Status_Type_Tunnel_Reject 11
+#define Acct_Status_Type_Tunnel_Link_Start 12
+#define Acct_Status_Type_Tunnel_Link_Stop 13
+#define Acct_Status_Type_Tunnel_Link_Reject 14
+#define Tunnel_Type 64
+#define Tunnel_Medium_Type 65
+#define Tunnel_Client_Endpoint 66
+#define Tunnel_Server_Endpoint 67
+#define Tunnel_Password 69
+#define Tunnel_Private_Group_Id 81
+#define Tunnel_Assignment_Id 82
+#define Tunnel_Preference 83
+#define Tunnel_Client_Auth_Id 90
+#define Tunnel_Server_Auth_Id 91
+#define Tunnel_Type_PPTP 1
+#define Tunnel_Type_L2F 2
+#define Tunnel_Type_L2TP 3
+#define Tunnel_Type_ATMP 4
+#define Tunnel_Type_VTP 5
+#define Tunnel_Type_AH 6
+#define Tunnel_Type_IP 7
+#define Tunnel_Type_MIN_IP 8
+#define Tunnel_Type_ESP 9
+#define Tunnel_Type_GRE 10
+#define Tunnel_Type_DVS 11
+#define Tunnel_Type_IP_in_IP 12
+#define Tunnel_Medium_Type_IP 1
+#define Tunnel_Medium_Type_IPv4 1
+#define Tunnel_Medium_Type_IPv6 2
+#define Tunnel_Medium_Type_NSAP 3
+#define Tunnel_Medium_Type_HDLC 4
+#define Tunnel_Medium_Type_BBN_1822 5
+#define Tunnel_Medium_Type_IEEE_802 6
+#define Tunnel_Medium_Type_E_163 7
+#define Tunnel_Medium_Type_E_164 8
+#define Tunnel_Medium_Type_F_69 9
+#define Tunnel_Medium_Type_X_121 10
+#define Tunnel_Medium_Type_IPX 11
+#define Tunnel_Medium_Type_Appletalk 12
+#define Tunnel_Medium_Type_DecNet_IV 13
+#define Tunnel_Medium_Type_Banyan_Vines 14
+#define Tunnel_Medium_Type_E_164_NSAP 15
+#define Acct_Input_Gigawords 52
+#define Acct_Output_Gigawords 53
+#define Event_Timestamp 55
+#define ARAP_Password 70
+#define ARAP_Features 71
+#define ARAP_Zone_Access 72
+#define ARAP_Security 73
+#define ARAP_Security_Data 74
+#define Password_Retry 75
+#define Prompt 76
+#define Connect_Info 77
+#define Configuration_Token 78
+#define EAP_Message 79
+#define Message_Authenticator 80
+#define ARAP_Challenge_Response 84
+#define Acct_Interim_Interval 85
+#define NAS_Port_Id 87
+#define Framed_Pool 88
+#define ARAP_Zone_Access_Default_Zone 1
+#define ARAP_Zone_Access_Zone_Filter_Inclusive 2
+#define ARAP_Zone_Access_Zone_Filter_Exclusive 4
+#define Prompt_No_Echo 0
+#define Prompt_Echo 1
+#define Error_Cause 101
+#define Service_Type_Authorize_Only 17
+#define Error_Cause_Residual_Context_Removed 201
+#define Error_Cause_Invalid_EAP_Packet 202
+#define Error_Cause_Unsupported_Attribute 401
+#define Error_Cause_Missing_Attribute 402
+#define Error_Cause_NAS_Identification_Mismatch 403
+#define Error_Cause_Invalid_Request 404
+#define Error_Cause_Unsupported_Service 405
+#define Error_Cause_Unsupported_Extension 406
+#define Error_Cause_Administratively_Prohibited 501
+#define Error_Cause_Proxy_Request_Not_Routable 502
+#define Error_Cause_Session_Context_Not_Found 503
+#define Error_Cause_Session_Context_Not_Removable 504
+#define Error_Cause_Proxy_Processing_Error 505
+#define Error_Cause_Resources_Unavailable 506
+#define Error_Cause_Request_Initiated 507
+#define Acct_Terminate_Cause_Supplicant_Restart 19
+#define Acct_Terminate_Cause_Reauthentication_Failure 20
+#define Acct_Terminate_Cause_Port_Reinit 21
+#define Acct_Terminate_Cause_Port_Disabled 22
+#define NAS_Port_Type_Token_Ring 20
+#define NAS_Port_Type_FDDI 21
+#define Tunnel_Type_VLAN 13
+#define EAP_Key_Name 102
+#define Chargeable_User_Identity 89
+#define Error_Cause_Invalid_Attribute_Value 407
+#define Error_Cause_Multiple_Session_Selection_Unsupported 508
+#define Vendor_Microsoft 311
+#define MS_CHAP_Response 1
+#define MS_CHAP_Error 2
+#define MS_CHAP_CPW_1 3
+#define MS_CHAP_CPW_2 4
+#define MS_CHAP_LM_Enc_PW 5
+#define MS_CHAP_NT_Enc_PW 6
+#define MS_MPPE_Encryption_Policy 7
+#define MS_MPPE_Encryption_Type 8
+#define MS_MPPE_Encryption_Types 8
+#define MS_RAS_Vendor 9
+#define MS_CHAP_Domain 10
+#define MS_CHAP_Challenge 11
+#define MS_CHAP_MPPE_Keys 12
+#define MS_BAP_Usage 13
+#define MS_Link_Utilization_Threshold 14
+#define MS_Link_Drop_Time_Limit 15
+#define MS_MPPE_Send_Key 16
+#define MS_MPPE_Recv_Key 17
+#define MS_RAS_Version 18
+#define MS_Old_ARAP_Password 19
+#define MS_New_ARAP_Password 20
+#define MS_ARAP_PW_Change_Reason 21
+#define MS_Filter 22
+#define MS_Acct_Auth_Type 23
+#define MS_Acct_EAP_Type 24
+#define MS_CHAP2_Response 25
+#define MS_CHAP2_Success 26
+#define MS_CHAP2_CPW 27
+#define MS_Primary_DNS_Server 28
+#define MS_Secondary_DNS_Server 29
+#define MS_Primary_NBNS_Server 30
+#define MS_Secondary_NBNS_Server 31
+#define MS_BAP_Usage_Not_Allowed 0
+#define MS_BAP_Usage_Allowed 1
+#define MS_BAP_Usage_Required 2
+#define MS_ARAP_PW_Change_Reason_Just_Change_Password 1
+#define MS_ARAP_PW_Change_Reason_Expired_Password 2
+#define MS_ARAP_PW_Change_Reason_Admin_Requires_Password_Change 3
+#define MS_ARAP_PW_Change_Reason_Password_Too_Short 4
+#define MS_Acct_Auth_Type_PAP 1
+#define MS_Acct_Auth_Type_CHAP 2
+#define MS_Acct_Auth_Type_MS_CHAP_1 3
+#define MS_Acct_Auth_Type_MS_CHAP_2 4
+#define MS_Acct_Auth_Type_EAP 5
+#define MS_Acct_EAP_Type_MD5 4
+#define MS_Acct_EAP_Type_OTP 5
+#define MS_Acct_EAP_Type_Generic_Token_Card 6
+#define MS_Acct_EAP_Type_TLS 13
+#define Traffic_Shape_in 231
diff --git a/accel-pppd/radius/auth.c b/accel-pppd/radius/auth.c
new file mode 100644
index 00000000..692830ed
--- /dev/null
+++ b/accel-pppd/radius/auth.c
@@ -0,0 +1,497 @@
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+
+#include "triton.h"
+#include "events.h"
+#include "log.h"
+#include "pwdb.h"
+
+#include "radius_p.h"
+#include "attr_defs.h"
+
+#include "memdebug.h"
+
+static int decrypt_chap_mppe_keys(struct rad_req_t *req, struct rad_attr_t *attr, const uint8_t *challenge, uint8_t *key)
+{
+ MD5_CTX md5_ctx;
+ SHA_CTX sha1_ctx;
+ uint8_t md5[MD5_DIGEST_LENGTH];
+ uint8_t sha1[SHA_DIGEST_LENGTH];
+ uint8_t plain[32];
+ int i;
+
+ if (attr->len != 32) {
+ log_ppp_warn("radius: %s: incorrect attribute length (%i)\n", attr->attr->name, attr->len);
+ return -1;
+ }
+
+ memcpy(plain, attr->val.octets, 32);
+
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, conf_auth_secret, strlen(conf_auth_secret));
+ MD5_Update(&md5_ctx, req->pack->buf + 4, 16);
+ MD5_Final(md5, &md5_ctx);
+
+ for (i = 0; i < 16; i++)
+ plain[i] ^= md5[i];
+
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, conf_auth_secret, strlen(conf_auth_secret));
+ MD5_Update(&md5_ctx, attr->val.octets, 16);
+ MD5_Final(md5, &md5_ctx);
+
+ for (i = 0; i < 16; i++)
+ plain[i + 16] ^= md5[i];
+
+ SHA1_Init(&sha1_ctx);
+ SHA1_Update(&sha1_ctx, plain + 8, 16);
+ SHA1_Update(&sha1_ctx, plain + 8, 16);
+ SHA1_Update(&sha1_ctx, challenge, 8);
+ SHA1_Final(sha1, &sha1_ctx);
+
+ memcpy(key, sha1, 16);
+
+ return 0;
+}
+
+static int decrypt_mppe_key(struct rad_req_t *req, struct rad_attr_t *attr, uint8_t *key)
+{
+ MD5_CTX md5_ctx;
+ uint8_t md5[16];
+ uint8_t plain[32];
+ int i;
+
+ if (attr->len != 34) {
+ log_ppp_warn("radius: %s: incorrect attribute length (%i)\n", attr->attr->name, attr->len);
+ return -1;
+ }
+
+ if ((attr->val.octets[0] & 0x80) == 0) {
+ log_ppp_warn("radius: %s: incorrect salt value (%x)\n", attr->attr->name, attr->len);
+ return -1;
+ }
+
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, conf_auth_secret, strlen(conf_auth_secret));
+ MD5_Update(&md5_ctx, req->pack->buf + 4, 16);
+ MD5_Update(&md5_ctx, attr->val.octets, 2);
+ MD5_Final(md5, &md5_ctx);
+
+ memcpy(plain, attr->val.octets + 2, 32);
+
+ for (i = 0; i < 16; i++)
+ plain[i] ^= md5[i];
+
+ if (plain[0] != 16) {
+ log_ppp_warn("radius: %s: incorrect key length (%i)\n", attr->attr->name, plain[0]);
+ return -1;
+ }
+
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, conf_auth_secret, strlen(conf_auth_secret));
+ MD5_Update(&md5_ctx, attr->val.octets + 2, 16);
+ MD5_Final(md5, &md5_ctx);
+
+ plain[16] ^= md5[0];
+
+ memcpy(key, plain + 1, 16);
+
+ return 0;
+}
+
+
+static uint8_t* encrypt_password(const char *passwd, const char *secret, const uint8_t *RA, int *epasswd_len)
+{
+ uint8_t *epasswd;
+ int i, j, chunk_cnt;
+ uint8_t b[16], c[16];
+ MD5_CTX ctx;
+
+ if (strlen(passwd))
+ chunk_cnt = (strlen(passwd) - 1) / 16 + 1;
+ else {
+ *epasswd_len = 0;
+ return (uint8_t *)1;
+ }
+
+ epasswd = _malloc(chunk_cnt * 16);
+ if (!epasswd) {
+ log_emerg("radius: out of memory\n");
+ return NULL;
+ }
+
+ memset(epasswd, 0, chunk_cnt * 16);
+ memcpy(epasswd, passwd, strlen(passwd));
+ memcpy(c, RA, 16);
+
+ for (i = 0; i < chunk_cnt; i++) {
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, secret, strlen(secret));
+ MD5_Update(&ctx, c, 16);
+ MD5_Final(b, &ctx);
+
+ for(j = 0; j < 16; j++)
+ epasswd[i * 16 + j] ^= b[j];
+
+ memcpy(c, epasswd + i * 16, 16);
+ }
+
+ *epasswd_len = chunk_cnt * 16;
+ return epasswd;
+}
+
+static int rad_auth_send(struct rad_req_t *req)
+{
+ int i;
+
+ for(i = 0; i < conf_max_try; i++) {
+ __sync_add_and_fetch(&stat_auth_sent, 1);
+ if (rad_req_send(req, conf_verbose))
+ goto out;
+
+ rad_req_wait(req, conf_timeout);
+
+ if (req->reply) {
+ if (req->reply->id != req->pack->id) {
+ __sync_add_and_fetch(&stat_auth_lost, 1);
+ rad_packet_free(req->reply);
+ req->reply = NULL;
+ } else
+ break;
+ } else
+ __sync_add_and_fetch(&stat_auth_lost, 1);
+ }
+
+ if (!req->reply)
+ log_ppp_warn("radius:auth: no response\n");
+ else if (req->reply->code == CODE_ACCESS_ACCEPT) {
+ if (rad_proc_attrs(req))
+ return PWDB_DENIED;
+ return PWDB_SUCCESS;
+ }
+
+out:
+ return PWDB_DENIED;
+}
+
+int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args)
+{
+ struct rad_req_t *req;
+ int r = PWDB_DENIED;
+ //int id = va_arg(args, int);
+ const char *passwd = va_arg(args, const char *);
+ uint8_t *epasswd;
+ int epasswd_len;
+
+ req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
+ if (!req)
+ return PWDB_DENIED;
+
+ epasswd = encrypt_password(passwd, conf_auth_secret, req->RA, &epasswd_len);
+ if (!epasswd)
+ goto out;
+
+ if (rad_packet_add_octets(req->pack, NULL, "User-Password", epasswd, epasswd_len)) {
+ if (epasswd_len)
+ _free(epasswd);
+ goto out;
+ }
+
+ if (epasswd_len)
+ _free(epasswd);
+
+ if (conf_sid_in_auth)
+ if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ppp->sessionid))
+ return -1;
+
+ r = rad_auth_send(req);
+ if (r == PWDB_SUCCESS) {
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = req->pack,
+ .reply = req->reply,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ }
+
+out:
+ rad_req_free(req);
+
+ return r;
+}
+
+int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args)
+{
+ int r = PWDB_DENIED;
+ uint8_t chap_password[17];
+
+ int id = va_arg(args, int);
+ uint8_t *challenge = va_arg(args, uint8_t *);
+ int challenge_len = va_arg(args, int);
+ uint8_t *response = va_arg(args, uint8_t *);
+
+ chap_password[0] = id;
+ memcpy(chap_password + 1, response, 16);
+
+ if (!rpd->auth_req) {
+ rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
+ if (!rpd->auth_req)
+ return PWDB_DENIED;
+
+ if (challenge_len == 16)
+ memcpy(rpd->auth_req->RA, challenge, 16);
+ else {
+ if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "CHAP-Challenge", challenge, challenge_len))
+ goto out;
+ }
+
+ if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "CHAP-Password", chap_password, 17))
+ goto out;
+ } else {
+ if (challenge_len == 16)
+ memcpy(rpd->auth_req->RA, challenge, 16);
+ else {
+ if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "CHAP-Challenge", challenge, challenge_len))
+ goto out;
+ }
+
+ if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "CHAP-Password", chap_password, 17))
+ goto out;
+
+ if (rpd->attr_state) {
+ if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) {
+ if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
+ goto out;
+ } else {
+ if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
+ goto out;
+ }
+ }
+
+ if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA))
+ return -1;
+ }
+
+ if (conf_sid_in_auth)
+ if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ppp->sessionid))
+ goto out;
+
+ r = rad_auth_send(rpd->auth_req);
+ if (r == PWDB_SUCCESS) {
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = rpd->auth_req->pack,
+ .reply = rpd->auth_req->reply,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ rpd->auth_req->pack->id++;
+ }
+
+ return r;
+out:
+ rad_req_free(rpd->auth_req);
+ rpd->auth_req = NULL;
+
+ return r;
+}
+
+static void setup_mppe(struct rad_req_t *req, const uint8_t *challenge)
+{
+ struct rad_attr_t *attr;
+ uint8_t mppe_recv_key[16];
+ uint8_t mppe_send_key[16];
+ struct ev_mppe_keys_t ev_mppe = {
+ .ppp = req->rpd->ppp,
+ };
+
+ list_for_each_entry(attr, &req->reply->attrs, entry) {
+ if (attr->vendor && attr->vendor->id == Vendor_Microsoft) {
+ switch (attr->attr->id) {
+ case MS_CHAP_MPPE_Keys:
+ if (decrypt_chap_mppe_keys(req, attr, challenge, mppe_recv_key))
+ continue;
+ ev_mppe.recv_key = mppe_recv_key;
+ ev_mppe.send_key = mppe_recv_key;
+ break;
+ case MS_MPPE_Recv_Key:
+ if (decrypt_mppe_key(req, attr, mppe_recv_key))
+ continue;
+ ev_mppe.recv_key = mppe_recv_key;
+ break;
+ case MS_MPPE_Send_Key:
+ if (decrypt_mppe_key(req, attr, mppe_send_key))
+ continue;
+ ev_mppe.send_key = mppe_send_key;
+ break;
+ case MS_MPPE_Encryption_Policy:
+ ev_mppe.policy = attr->val.integer;
+ break;
+ case MS_MPPE_Encryption_Type:
+ ev_mppe.type = attr->val.integer;
+ break;
+ }
+ }
+ }
+
+ if (ev_mppe.recv_key && ev_mppe.send_key)
+ triton_event_fire(EV_MPPE_KEYS, &ev_mppe);
+}
+
+int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args)
+{
+ int r = PWDB_DENIED;
+ uint8_t response[50];
+
+ int id = va_arg(args, int);
+ const uint8_t *challenge = va_arg(args, const uint8_t *);
+ int challenge_len = va_arg(args, int);
+ const uint8_t *lm_response = va_arg(args, const uint8_t *);
+ const uint8_t *nt_response = va_arg(args, const uint8_t *);
+ int flags = va_arg(args, int);
+
+ response[0] = id;
+ response[1] = flags;
+ memcpy(response + 2, lm_response, 24);
+ memcpy(response + 2 + 24, nt_response, 24);
+
+ if (!rpd->auth_req) {
+ rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
+ if (!rpd->auth_req)
+ return PWDB_DENIED;
+
+ if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len))
+ goto out;
+
+ if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response)))
+ goto out;
+ } else {
+ if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len))
+ goto out;
+
+ if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response)))
+ goto out;
+
+ if (rpd->attr_state) {
+ if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) {
+ if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
+ goto out;
+ } else {
+ if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
+ goto out;
+ }
+ }
+
+ if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA))
+ return -1;
+ }
+
+ if (conf_sid_in_auth)
+ if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ppp->sessionid))
+ goto out;
+
+ r = rad_auth_send(rpd->auth_req);
+ if (r == PWDB_SUCCESS) {
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = rpd->auth_req->pack,
+ .reply = rpd->auth_req->reply,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ setup_mppe(rpd->auth_req, challenge);
+ rpd->auth_req->pack->id++;
+ }
+
+ return r;
+out:
+ rad_req_free(rpd->auth_req);
+ rpd->auth_req = NULL;
+
+ return r;
+}
+
+int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args)
+{
+ int r = PWDB_DENIED;
+ struct rad_attr_t *ra;
+ uint8_t mschap_response[50];
+
+ int id = va_arg(args, int);
+ const uint8_t *challenge = va_arg(args, const uint8_t *);
+ const uint8_t *peer_challenge = va_arg(args, const uint8_t *);
+ const uint8_t *reserved = va_arg(args, const uint8_t *);
+ const uint8_t *response = va_arg(args, const uint8_t *);
+ int flags = va_arg(args, int);
+ uint8_t *authenticator = va_arg(args, uint8_t *);
+
+ mschap_response[0] = id;
+ mschap_response[1] = flags;
+ memcpy(mschap_response + 2, peer_challenge, 16);
+ memcpy(mschap_response + 2 + 16, reserved, 8);
+ memcpy(mschap_response + 2 + 16 + 8, response, 24);
+
+ if (!rpd->auth_req) {
+ rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
+ if (!rpd->auth_req)
+ return PWDB_DENIED;
+
+ if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16))
+ goto out;
+
+ if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response)))
+ goto out;
+ } else {
+ if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16))
+ goto out;
+
+ if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response)))
+ goto out;
+
+ if (rpd->attr_state) {
+ if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) {
+ if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
+ goto out;
+ } else {
+ if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
+ goto out;
+ }
+ }
+
+ if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA))
+ return -1;
+ }
+
+ if (conf_sid_in_auth)
+ if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ppp->sessionid))
+ goto out;
+
+ r = rad_auth_send(rpd->auth_req);
+ if (r == PWDB_SUCCESS) {
+ ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP2-Success");
+ if (!ra) {
+ log_error("radius:auth:mschap-v2: 'MS-CHAP-Success' not found in radius response\n");
+ r = PWDB_DENIED;
+ } else
+ memcpy(authenticator, ra->val.octets + 3, 40);
+ }
+ if (r == PWDB_SUCCESS) {
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = rpd->auth_req->pack,
+ .reply = rpd->auth_req->reply,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ setup_mppe(rpd->auth_req, NULL);
+ rpd->auth_req->pack->id++;
+ }
+
+ return r;
+out:
+ rad_req_free(rpd->auth_req);
+ rpd->auth_req = NULL;
+
+ return r;
+}
+
+
diff --git a/accel-pppd/radius/dict.c b/accel-pppd/radius/dict.c
new file mode 100644
index 00000000..9704569e
--- /dev/null
+++ b/accel-pppd/radius/dict.c
@@ -0,0 +1,356 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "list.h"
+#include "radius_p.h"
+#include "log.h"
+
+#include "memdebug.h"
+
+static struct rad_dict_t *dict;
+
+static char *skip_word(char *ptr)
+{
+ for(; *ptr; ptr++)
+ if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
+ break;
+ return ptr;
+}
+static char *skip_space(char *ptr)
+{
+ for(; *ptr; ptr++)
+ if (*ptr != ' ' && *ptr != '\t')
+ break;
+ return ptr;
+}
+static int split(char *buf, char **ptr)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ buf = skip_word(buf);
+ if (!*buf)
+ return i;
+
+ *buf = 0;
+
+ buf = skip_space(buf + 1);
+ if (!*buf)
+ return i;
+
+ ptr[i] = buf;
+ }
+
+ buf = skip_word(buf);
+ //if (*buf == '\n')
+ *buf = 0;
+ //else if (*buf)
+ // return -1;
+
+ return i;
+}
+
+struct rad_dict_attr_t *find_attr(struct list_head *items, const char *name)
+{
+ struct rad_dict_attr_t *attr;
+
+ list_for_each_entry(attr, items, entry)
+ if (!strcmp(attr->name, name))
+ return attr;
+
+ return NULL;
+}
+
+#define BUF_SIZE 1024
+
+static char *path, *fname1, *buf;
+static int dict_load(const char *fname)
+{
+ FILE *f;
+ char *ptr[3], *endptr;
+ int r, n = 0;
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_value_t *val;
+ struct rad_dict_vendor_t *vendor;
+ struct list_head *items;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ log_emerg("radius: open dictioanary '%s': %s\n", fname, strerror(errno));
+ return -1;
+ }
+
+ items = &dict->items;
+
+ while (fgets(buf, BUF_SIZE, f)) {
+ n++;
+ if (buf[0] == '#' || buf[0] == '\n' || buf[0] == 0)
+ continue;
+ r = split(buf, ptr);
+ if (r == 1) {
+ if (!strcmp(buf, "BEGIN-VENDOR")) {
+ vendor = rad_dict_find_vendor_name(ptr[0]);
+ if (!vendor) {
+ log_emerg("radius:%s:%i: vendor not found\n", fname, n);
+ goto out_err;
+ }
+ items = &vendor->items;
+ } else if (!strcmp(buf, "END-VENDOR"))
+ items = &dict->items;
+ else if (!strcmp(buf, "$INCLUDE")) {
+ for (r = strlen(path) - 1; r; r--)
+ if (path[r] == '/') {
+ path[r + 1] = 0;
+ break;
+ }
+ strcpy(fname1, path);
+ strcat(fname1, ptr[0]);
+ if (dict_load(fname1))
+ goto out_err;
+ } else
+ goto out_err_syntax;
+ } else if (r == 2) {
+ if (!strcmp(buf, "VENDOR")) {
+ vendor = malloc(sizeof(*vendor));
+ if (!vendor) {
+ log_emerg("radius: out of memory\n");
+ goto out_err;
+ }
+ vendor->id = strtol(ptr[1], &endptr, 10);
+ if (*endptr != 0)
+ goto out_err_syntax;
+ vendor->name = strdup(ptr[0]);
+ if (!vendor->name) {
+ log_emerg("radius: out of memory\n");
+ goto out_err;
+ }
+ INIT_LIST_HEAD(&vendor->items);
+ list_add_tail(&vendor->entry, &dict->vendors);
+ } else
+ goto out_err_syntax;
+ } else if (r == 3) {
+ if (!strcmp(buf, "ATTRIBUTE")) {
+ attr = malloc(sizeof(*attr));
+ if (!attr) {
+ log_emerg("radius: out of memory\n");
+ goto out_err;
+ }
+ memset(attr, 0, sizeof(*attr));
+ INIT_LIST_HEAD(&attr->values);
+ list_add_tail(&attr->entry, items);
+ attr->name = strdup(ptr[0]);
+ attr->id = strtol(ptr[1], &endptr, 10);
+ if (*endptr != 0)
+ goto out_err_syntax;
+ if (!strcmp(ptr[2], "integer"))
+ attr->type = ATTR_TYPE_INTEGER;
+ else if (!strcmp(ptr[2], "string"))
+ attr->type = ATTR_TYPE_STRING;
+ else if (!strcmp(ptr[2], "date"))
+ attr->type = ATTR_TYPE_DATE;
+ else if (!strcmp(ptr[2], "ipaddr"))
+ attr->type = ATTR_TYPE_IPADDR;
+ else if (!strcmp(ptr[2], "octets"))
+ attr->type = ATTR_TYPE_OCTETS;
+ else {
+ log_emerg("radius:%s:%i: unknown attribute type\n", fname, n);
+ goto out_err;
+ }
+ } else if (!strcmp(buf, "VALUE")) {
+ attr = find_attr(items, ptr[0]);
+ if (!attr) {
+ log_emerg("radius:%s:%i: unknown attribute\n", fname, n);
+ goto out_err;
+ }
+ val = malloc(sizeof(*val));
+ if (!val) {
+ log_emerg("radius: out of memory\n");
+ goto out_err;
+ }
+ memset(val, 0, sizeof(*val));
+ list_add_tail(&val->entry, &attr->values);
+ val->name = strdup(ptr[1]);
+ switch (attr->type) {
+ case ATTR_TYPE_INTEGER:
+ val->val.integer = strtol(ptr[2], &endptr, 10);
+ if (*endptr != 0)
+ goto out_err_syntax;
+ break;
+ case ATTR_TYPE_STRING:
+ val->val.string = strdup(ptr[2]);
+ break;
+ case ATTR_TYPE_DATE:
+ log_warn("radius:%s:%i: VALUE of type 'date' is not implemented yet\n", fname, n);
+ break;
+ case ATTR_TYPE_IPADDR:
+ log_warn("radius:%s:%i: VALUE of type 'ipaddr' is not implemented yet\n", fname, n);
+ break;
+ }
+ } else
+ goto out_err_syntax;
+ } else
+ goto out_err_syntax;
+ }
+
+ fclose(f);
+
+ return 0;
+
+out_err_syntax:
+ log_emerg("radius:%s:%i: syntaxis error\n", fname, n);
+out_err:
+ fclose(f);
+ return -1;
+}
+
+int rad_dict_load(const char *fname)
+{
+ int r = -1;
+
+ dict = malloc(sizeof(*dict));
+ if (!dict) {
+ log_emerg("radius: out of memory\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&dict->items);
+ INIT_LIST_HEAD(&dict->vendors);
+
+ path = _malloc(PATH_MAX);
+ if (!path) {
+ log_emerg("radius: out of memory\n");
+ goto out_free_dict;
+ }
+
+ fname1 = _malloc(PATH_MAX);
+ if (!fname1) {
+ log_emerg("radius: out of memory\n");
+ goto out_free_path;
+ }
+
+ buf = _malloc(BUF_SIZE);
+ if (!buf) {
+ log_emerg("radius: out of memory\n");
+ goto out_free_fname1;
+ }
+
+ strcpy(path, fname);
+
+ r = dict_load(fname);
+
+out_free_fname1:
+ _free(fname1);
+out_free_path:
+ _free(path);
+out_free_dict:
+ if (r)
+ rad_dict_free(dict);
+ return r;
+}
+
+void rad_dict_free(struct rad_dict_t *dict)
+{
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_value_t *val;
+
+ while (!list_empty(&dict->items)) {
+ attr = list_entry(dict->items.next, typeof(*attr), entry);
+ while (!list_empty(&attr->values)) {
+ val = list_entry(attr->values.next, typeof(*val), entry);
+ list_del(&val->entry);
+ _free((char*)val->name);
+ if (attr->type == ATTR_TYPE_STRING)
+ _free((char*)val->val.string);
+ _free(val);
+ }
+ list_del(&attr->entry);
+ _free((char*)attr->name);
+ _free(attr);
+ }
+ free(dict);
+}
+
+static struct rad_dict_attr_t *dict_find_attr(struct list_head *items, const char *name)
+{
+ struct rad_dict_attr_t *attr;
+
+ list_for_each_entry(attr, items, entry)
+ if (!strcmp(attr->name, name))
+ return attr;
+
+ return NULL;
+}
+
+__export struct rad_dict_attr_t *rad_dict_find_attr(const char *name)
+{
+ return dict_find_attr(&dict->items, name);
+}
+
+__export struct rad_dict_attr_t *rad_dict_find_attr_id(struct rad_dict_vendor_t *vendor, int id)
+{
+ struct rad_dict_attr_t *attr;
+ struct list_head *items = vendor ? &vendor->items : &dict->items;
+
+ list_for_each_entry(attr, items, entry)
+ if (attr->id == id)
+ return attr;
+
+ return NULL;
+}
+
+__export struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *attr, const char *name)
+{
+ struct rad_dict_value_t *val;
+
+ list_for_each_entry(val, &attr->values, entry)
+ if (!strcmp(val->name, name))
+ return val;
+
+ return NULL;
+}
+
+__export struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *attr, rad_value_t v)
+{
+ struct rad_dict_value_t *val;
+
+ if (attr->type != ATTR_TYPE_INTEGER)
+ return NULL;
+
+ list_for_each_entry(val, &attr->values, entry)
+ if (val->val.integer == v.integer)
+ return val;
+
+ return NULL;
+}
+
+__export struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name)
+{
+ struct rad_dict_vendor_t *vendor;
+
+ list_for_each_entry(vendor, &dict->vendors, entry) {
+ if (!strcmp(vendor->name, name))
+ return vendor;
+ }
+
+ return NULL;
+}
+
+__export struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id)
+{
+ struct rad_dict_vendor_t *vendor;
+
+ list_for_each_entry(vendor, &dict->vendors, entry) {
+ if (vendor->id == id)
+ return vendor;
+ }
+
+ return NULL;
+}
+
+__export struct rad_dict_attr_t *rad_dict_find_vendor_attr(struct rad_dict_vendor_t *vendor, const char *name)
+{
+ return dict_find_attr(&vendor->items, name);
+}
+
diff --git a/accel-pppd/radius/dict/dictionary b/accel-pppd/radius/dict/dictionary
new file mode 100644
index 00000000..27973105
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary
@@ -0,0 +1,79 @@
+# -*- text -*-
+#
+# Version $Id: dictionary,v 1.155 2008/04/20 14:47:55 aland Exp $
+#
+# DO NOT EDIT THE FILES IN THIS DIRECTORY
+#
+# The files in this directory are maintained and updated by
+# the FreeRADIUS project. Newer releases of software may update
+# or change these files.
+#
+# Use the main dictionary file (usually /etc/raddb/dictionary)
+# for local system attributes and $INCLUDEs.
+#
+#
+#
+# This file contains dictionary translations for parsing
+# requests and generating responses. All transactions are
+# composed of Attribute/Value Pairs. The value of each attribute
+# is specified as one of 4 data types. Valid data types are:
+#
+# text - printable, generally UTF-8 encoded (subset of 'string')
+# string - 0-253 octets
+# ipaddr - 4 octets in network byte order
+# integer - 32 bit value in big endian order (high byte first)
+# date - 32 bit value in big endian order - seconds since
+# 00:00:00 GMT, Jan. 1, 1970
+# ifid - 8 octets in network byte order
+# ipv6addr - 16 octets in network byte order
+# ipv6prefix - 18 octets in network byte order
+# ether - 6 octets of hh:hh:hh:hh:hh:hh
+# where 'h' is hex digits, upper or lowercase.
+#
+# FreeRADIUS includes extended data types which are not defined
+# in the RFC's. These data types are:
+#
+# abinary - Ascend's binary filter format.
+# octets - raw octets, printed and input as hex strings.
+# e.g.: 0x123456789abcdef
+#
+#
+# Enumerated values are stored in the user file with dictionary
+# VALUE translations for easy administration.
+#
+# Example:
+#
+# ATTRIBUTE VALUE
+# --------------- -----
+# Framed-Protocol = PPP
+# 7 = 1 (integer encoding)
+#
+
+#
+# Include compatibility dictionary for older users file. Move
+# this directive to the end of this file if you want to see the
+# old names in the logfiles, INSTEAD OF the new names.
+#
+#
+# Include the RFC dictionaries next.
+#
+# For a complete list of the standard attributes and values,
+# see:
+# http://www.iana.org/assignments/radius-types
+#
+$INCLUDE dictionary.rfc2865
+$INCLUDE dictionary.rfc2866
+$INCLUDE dictionary.rfc2867
+$INCLUDE dictionary.rfc2868
+$INCLUDE dictionary.rfc2869
+$INCLUDE dictionary.rfc3576
+$INCLUDE dictionary.rfc3580
+$INCLUDE dictionary.rfc4072
+$INCLUDE dictionary.rfc4372
+$INCLUDE dictionary.rfc4679
+$INCLUDE dictionary.rfc5176
+
+$INCLUDE dictionary.microsoft
+$INCLUDE dictionary.cisco
+
+ATTRIBUTE Traffic-Shape-in 231 integer
diff --git a/accel-pppd/radius/dict/dictionary.cisco b/accel-pppd/radius/dict/dictionary.cisco
new file mode 100644
index 00000000..6d1efbe8
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.cisco
@@ -0,0 +1,156 @@
+# -*- text -*-
+#
+# dictionary.cisco
+#
+# Accounting VSAs originally by
+# "Marcelo M. Sosa Lugones" <marcelo@sosa.com.ar>
+#
+# Version: $Id: dictionary.cisco,v 1.16 2006/06/05 16:55:21 pnixon Exp $
+#
+# For documentation on Cisco RADIUS attributes, see:
+#
+# http://www.cisco.com/univercd/cc/td/doc/product/access/acs_serv/vapp_dev/vsaig3.htm
+#
+# For general documentation on Cisco RADIUS configuration, see:
+#
+# http://www.cisco.com/en/US/partner/tech/tk583/tk547/tsd_technology_support_sub-protocol_home.html
+#
+
+VENDOR Cisco 9
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Cisco
+
+ATTRIBUTE Cisco-AVPair 1 string
+ATTRIBUTE Cisco-NAS-Port 2 string
+
+#
+# T.37 Store-and-Forward attributes.
+#
+ATTRIBUTE Cisco-Fax-Account-Id-Origin 3 string
+ATTRIBUTE Cisco-Fax-Msg-Id 4 string
+ATTRIBUTE Cisco-Fax-Pages 5 string
+ATTRIBUTE Cisco-Fax-Coverpage-Flag 6 string
+ATTRIBUTE Cisco-Fax-Modem-Time 7 string
+ATTRIBUTE Cisco-Fax-Connect-Speed 8 string
+ATTRIBUTE Cisco-Fax-Recipient-Count 9 string
+ATTRIBUTE Cisco-Fax-Process-Abort-Flag 10 string
+ATTRIBUTE Cisco-Fax-Dsn-Address 11 string
+ATTRIBUTE Cisco-Fax-Dsn-Flag 12 string
+ATTRIBUTE Cisco-Fax-Mdn-Address 13 string
+ATTRIBUTE Cisco-Fax-Mdn-Flag 14 string
+ATTRIBUTE Cisco-Fax-Auth-Status 15 string
+ATTRIBUTE Cisco-Email-Server-Address 16 string
+ATTRIBUTE Cisco-Email-Server-Ack-Flag 17 string
+ATTRIBUTE Cisco-Gateway-Id 18 string
+ATTRIBUTE Cisco-Call-Type 19 string
+ATTRIBUTE Cisco-Port-Used 20 string
+ATTRIBUTE Cisco-Abort-Cause 21 string
+
+#
+# Voice over IP attributes.
+#
+ATTRIBUTE h323-remote-address 23 string
+ATTRIBUTE h323-conf-id 24 string
+ATTRIBUTE h323-setup-time 25 string
+ATTRIBUTE h323-call-origin 26 string
+ATTRIBUTE h323-call-type 27 string
+ATTRIBUTE h323-connect-time 28 string
+ATTRIBUTE h323-disconnect-time 29 string
+ATTRIBUTE h323-disconnect-cause 30 string
+ATTRIBUTE h323-voice-quality 31 string
+ATTRIBUTE h323-gw-id 33 string
+ATTRIBUTE h323-incoming-conf-id 35 string
+
+ATTRIBUTE h323-credit-amount 101 string
+ATTRIBUTE h323-credit-time 102 string
+ATTRIBUTE h323-return-code 103 string
+ATTRIBUTE h323-prompt-id 104 string
+ATTRIBUTE h323-time-and-day 105 string
+ATTRIBUTE h323-redirect-number 106 string
+ATTRIBUTE h323-preferred-lang 107 string
+ATTRIBUTE h323-redirect-ip-address 108 string
+ATTRIBUTE h323-billing-model 109 string
+ATTRIBUTE h323-currency 110 string
+ATTRIBUTE subscriber 111 string
+ATTRIBUTE gw-rxd-cdn 112 string
+ATTRIBUTE gw-final-xlated-cdn 113 string
+ATTRIBUTE remote-media-address 114 string
+ATTRIBUTE release-source 115 string
+ATTRIBUTE gw-rxd-cgn 116 string
+ATTRIBUTE gw-final-xlated-cgn 117 string
+
+# SIP Attributes
+ATTRIBUTE call-id 141 string
+ATTRIBUTE session-protocol 142 string
+ATTRIBUTE method 143 string
+ATTRIBUTE prev-hop-via 144 string
+ATTRIBUTE prev-hop-ip 145 string
+ATTRIBUTE incoming-req-uri 146 string
+ATTRIBUTE outgoing-req-uri 147 string
+ATTRIBUTE next-hop-ip 148 string
+ATTRIBUTE next-hop-dn 149 string
+ATTRIBUTE sip-hdr 150 string
+
+#
+# Extra attributes sent by the Cisco, if you configure
+# "radius-server vsa accounting" (requires IOS11.2+).
+#
+ATTRIBUTE Cisco-Multilink-ID 187 integer
+ATTRIBUTE Cisco-Num-In-Multilink 188 integer
+ATTRIBUTE Cisco-Pre-Input-Octets 190 integer
+ATTRIBUTE Cisco-Pre-Output-Octets 191 integer
+ATTRIBUTE Cisco-Pre-Input-Packets 192 integer
+ATTRIBUTE Cisco-Pre-Output-Packets 193 integer
+ATTRIBUTE Cisco-Maximum-Time 194 integer
+ATTRIBUTE Cisco-Disconnect-Cause 195 integer
+ATTRIBUTE Cisco-Data-Rate 197 integer
+ATTRIBUTE Cisco-PreSession-Time 198 integer
+ATTRIBUTE Cisco-PW-Lifetime 208 integer
+ATTRIBUTE Cisco-IP-Direct 209 integer
+ATTRIBUTE Cisco-PPP-VJ-Slot-Comp 210 integer
+ATTRIBUTE Cisco-PPP-Async-Map 212 integer
+ATTRIBUTE Cisco-IP-Pool-Definition 217 string
+ATTRIBUTE Cisco-Assign-IP-Pool 218 integer
+ATTRIBUTE Cisco-Route-IP 228 integer
+ATTRIBUTE Cisco-Link-Compression 233 integer
+ATTRIBUTE Cisco-Target-Util 234 integer
+ATTRIBUTE Cisco-Maximum-Channels 235 integer
+ATTRIBUTE Cisco-Data-Filter 242 integer
+ATTRIBUTE Cisco-Call-Filter 243 integer
+ATTRIBUTE Cisco-Idle-Limit 244 integer
+ATTRIBUTE Cisco-Account-Info 250 string
+ATTRIBUTE Cisco-Service-Info 251 string
+ATTRIBUTE Cisco-Command-Code 252 string
+ATTRIBUTE Cisco-Control-Info 253 string
+ATTRIBUTE Cisco-Xmit-Rate 255 integer
+
+VALUE Cisco-Disconnect-Cause Unknown 2
+VALUE Cisco-Disconnect-Cause CLID-Authentication-Failure 4
+VALUE Cisco-Disconnect-Cause No-Carrier 10
+VALUE Cisco-Disconnect-Cause Lost-Carrier 11
+VALUE Cisco-Disconnect-Cause No-Detected-Result-Codes 12
+VALUE Cisco-Disconnect-Cause User-Ends-Session 20
+VALUE Cisco-Disconnect-Cause Idle-Timeout 21
+VALUE Cisco-Disconnect-Cause Exit-Telnet-Session 22
+VALUE Cisco-Disconnect-Cause No-Remote-IP-Addr 23
+VALUE Cisco-Disconnect-Cause Exit-Raw-TCP 24
+VALUE Cisco-Disconnect-Cause Password-Fail 25
+VALUE Cisco-Disconnect-Cause Raw-TCP-Disabled 26
+VALUE Cisco-Disconnect-Cause Control-C-Detected 27
+VALUE Cisco-Disconnect-Cause EXEC-Program-Destroyed 28
+VALUE Cisco-Disconnect-Cause Timeout-PPP-LCP 40
+VALUE Cisco-Disconnect-Cause Failed-PPP-LCP-Negotiation 41
+VALUE Cisco-Disconnect-Cause Failed-PPP-PAP-Auth-Fail 42
+VALUE Cisco-Disconnect-Cause Failed-PPP-CHAP-Auth 43
+VALUE Cisco-Disconnect-Cause Failed-PPP-Remote-Auth 44
+VALUE Cisco-Disconnect-Cause PPP-Remote-Terminate 45
+VALUE Cisco-Disconnect-Cause PPP-Closed-Event 46
+VALUE Cisco-Disconnect-Cause Session-Timeout 100
+VALUE Cisco-Disconnect-Cause Session-Failed-Security 101
+VALUE Cisco-Disconnect-Cause Session-End-Callback 102
+VALUE Cisco-Disconnect-Cause Invalid-Protocol 120
+
+END-VENDOR Cisco
diff --git a/accel-pppd/radius/dict/dictionary.microsoft b/accel-pppd/radius/dict/dictionary.microsoft
new file mode 100644
index 00000000..9ca6b8e9
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.microsoft
@@ -0,0 +1,83 @@
+# -*- text -*-
+#
+# Microsoft's VSA's, from RFC 2548
+#
+# $Id: dictionary.microsoft,v 1.8 2005/08/08 22:23:37 aland Exp $
+#
+
+VENDOR Microsoft 311
+
+BEGIN-VENDOR Microsoft
+ATTRIBUTE MS-CHAP-Response 1 octets
+ATTRIBUTE MS-CHAP-Error 2 string
+ATTRIBUTE MS-CHAP-CPW-1 3 octets
+ATTRIBUTE MS-CHAP-CPW-2 4 octets
+ATTRIBUTE MS-CHAP-LM-Enc-PW 5 octets
+ATTRIBUTE MS-CHAP-NT-Enc-PW 6 octets
+ATTRIBUTE MS-MPPE-Encryption-Policy 7 integer
+# This is referred to as both singular and plural in the RFC.
+# Plural seems to make more sense.
+ATTRIBUTE MS-MPPE-Encryption-Type 8 integer
+ATTRIBUTE MS-MPPE-Encryption-Types 8 integer
+ATTRIBUTE MS-RAS-Vendor 9 integer # content is Vendor-ID
+ATTRIBUTE MS-CHAP-Domain 10 string
+ATTRIBUTE MS-CHAP-Challenge 11 octets
+ATTRIBUTE MS-CHAP-MPPE-Keys 12 octets encrypt=1
+ATTRIBUTE MS-BAP-Usage 13 integer
+ATTRIBUTE MS-Link-Utilization-Threshold 14 integer # values are 1-100
+ATTRIBUTE MS-Link-Drop-Time-Limit 15 integer
+ATTRIBUTE MS-MPPE-Send-Key 16 octets encrypt=2
+ATTRIBUTE MS-MPPE-Recv-Key 17 octets encrypt=2
+ATTRIBUTE MS-RAS-Version 18 string
+ATTRIBUTE MS-Old-ARAP-Password 19 octets
+ATTRIBUTE MS-New-ARAP-Password 20 octets
+ATTRIBUTE MS-ARAP-PW-Change-Reason 21 integer
+
+ATTRIBUTE MS-Filter 22 octets
+ATTRIBUTE MS-Acct-Auth-Type 23 integer
+ATTRIBUTE MS-Acct-EAP-Type 24 integer
+
+ATTRIBUTE MS-CHAP2-Response 25 octets
+ATTRIBUTE MS-CHAP2-Success 26 octets
+ATTRIBUTE MS-CHAP2-CPW 27 octets
+
+ATTRIBUTE MS-Primary-DNS-Server 28 ipaddr
+ATTRIBUTE MS-Secondary-DNS-Server 29 ipaddr
+ATTRIBUTE MS-Primary-NBNS-Server 30 ipaddr
+ATTRIBUTE MS-Secondary-NBNS-Server 31 ipaddr
+
+#ATTRIBUTE MS-ARAP-Challenge 33 octets
+
+#
+# Integer Translations
+#
+
+# MS-BAP-Usage Values
+
+VALUE MS-BAP-Usage Not-Allowed 0
+VALUE MS-BAP-Usage Allowed 1
+VALUE MS-BAP-Usage Required 2
+
+# MS-ARAP-Password-Change-Reason Values
+
+VALUE MS-ARAP-PW-Change-Reason Just-Change-Password 1
+VALUE MS-ARAP-PW-Change-Reason Expired-Password 2
+VALUE MS-ARAP-PW-Change-Reason Admin-Requires-Password-Change 3
+VALUE MS-ARAP-PW-Change-Reason Password-Too-Short 4
+
+# MS-Acct-Auth-Type Values
+
+VALUE MS-Acct-Auth-Type PAP 1
+VALUE MS-Acct-Auth-Type CHAP 2
+VALUE MS-Acct-Auth-Type MS-CHAP-1 3
+VALUE MS-Acct-Auth-Type MS-CHAP-2 4
+VALUE MS-Acct-Auth-Type EAP 5
+
+# MS-Acct-EAP-Type Values
+
+VALUE MS-Acct-EAP-Type MD5 4
+VALUE MS-Acct-EAP-Type OTP 5
+VALUE MS-Acct-EAP-Type Generic-Token-Card 6
+VALUE MS-Acct-EAP-Type TLS 13
+
+END-VENDOR Microsoft
diff --git a/accel-pppd/radius/dict/dictionary.rfc2865 b/accel-pppd/radius/dict/dictionary.rfc2865
new file mode 100644
index 00000000..7e5bf583
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc2865
@@ -0,0 +1,137 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 2865.
+# http://www.ietf.org/rfc/rfc2865.txt
+#
+# $Id: dictionary.rfc2865,v 1.3 2005/08/10 20:59:40 aland Exp $
+#
+ATTRIBUTE User-Name 1 string
+ATTRIBUTE User-Password 2 octets
+ATTRIBUTE CHAP-Password 3 octets
+ATTRIBUTE NAS-IP-Address 4 ipaddr
+ATTRIBUTE NAS-Port 5 integer
+ATTRIBUTE Service-Type 6 integer
+ATTRIBUTE Framed-Protocol 7 integer
+ATTRIBUTE Framed-IP-Address 8 ipaddr
+ATTRIBUTE Framed-IP-Netmask 9 ipaddr
+ATTRIBUTE Framed-Routing 10 integer
+ATTRIBUTE Filter-Id 11 string
+ATTRIBUTE Framed-MTU 12 integer
+ATTRIBUTE Framed-Compression 13 integer
+ATTRIBUTE Login-IP-Host 14 ipaddr
+ATTRIBUTE Login-Service 15 integer
+ATTRIBUTE Login-TCP-Port 16 integer
+# Attribute 17 is undefined
+ATTRIBUTE Reply-Message 18 string
+ATTRIBUTE Callback-Number 19 string
+ATTRIBUTE Callback-Id 20 string
+# Attribute 21 is undefined
+ATTRIBUTE Framed-Route 22 string
+ATTRIBUTE Framed-IPX-Network 23 ipaddr
+ATTRIBUTE State 24 octets
+ATTRIBUTE Class 25 octets
+ATTRIBUTE Vendor-Specific 26 octets
+ATTRIBUTE Session-Timeout 27 integer
+ATTRIBUTE Idle-Timeout 28 integer
+ATTRIBUTE Termination-Action 29 integer
+ATTRIBUTE Called-Station-Id 30 string
+ATTRIBUTE Calling-Station-Id 31 string
+ATTRIBUTE NAS-Identifier 32 string
+ATTRIBUTE Proxy-State 33 octets
+ATTRIBUTE Login-LAT-Service 34 string
+ATTRIBUTE Login-LAT-Node 35 string
+ATTRIBUTE Login-LAT-Group 36 octets
+ATTRIBUTE Framed-AppleTalk-Link 37 integer
+ATTRIBUTE Framed-AppleTalk-Network 38 integer
+ATTRIBUTE Framed-AppleTalk-Zone 39 string
+
+ATTRIBUTE CHAP-Challenge 60 octets
+ATTRIBUTE NAS-Port-Type 61 integer
+ATTRIBUTE Port-Limit 62 integer
+ATTRIBUTE Login-LAT-Port 63 integer
+
+#
+# Integer Translations
+#
+
+# Service types
+
+VALUE Service-Type Login-User 1
+VALUE Service-Type Framed-User 2
+VALUE Service-Type Callback-Login-User 3
+VALUE Service-Type Callback-Framed-User 4
+VALUE Service-Type Outbound-User 5
+VALUE Service-Type Administrative-User 6
+VALUE Service-Type NAS-Prompt-User 7
+VALUE Service-Type Authenticate-Only 8
+VALUE Service-Type Callback-NAS-Prompt 9
+VALUE Service-Type Call-Check 10
+VALUE Service-Type Callback-Administrative 11
+
+# Framed Protocols
+
+VALUE Framed-Protocol PPP 1
+VALUE Framed-Protocol SLIP 2
+VALUE Framed-Protocol ARAP 3
+VALUE Framed-Protocol Gandalf-SLML 4
+VALUE Framed-Protocol Xylogics-IPX-SLIP 5
+VALUE Framed-Protocol X.75-Synchronous 6
+
+# Framed Routing Values
+
+VALUE Framed-Routing None 0
+VALUE Framed-Routing Broadcast 1
+VALUE Framed-Routing Listen 2
+VALUE Framed-Routing Broadcast-Listen 3
+
+# Framed Compression Types
+
+VALUE Framed-Compression None 0
+VALUE Framed-Compression Van-Jacobson-TCP-IP 1
+VALUE Framed-Compression IPX-Header-Compression 2
+VALUE Framed-Compression Stac-LZS 3
+
+# Login Services
+
+VALUE Login-Service Telnet 0
+VALUE Login-Service Rlogin 1
+VALUE Login-Service TCP-Clear 2
+VALUE Login-Service PortMaster 3
+VALUE Login-Service LAT 4
+VALUE Login-Service X25-PAD 5
+VALUE Login-Service X25-T3POS 6
+VALUE Login-Service TCP-Clear-Quiet 8
+
+# Login-TCP-Port (see /etc/services for more examples)
+
+VALUE Login-TCP-Port Telnet 23
+VALUE Login-TCP-Port Rlogin 513
+VALUE Login-TCP-Port Rsh 514
+
+# Termination Options
+
+VALUE Termination-Action Default 0
+VALUE Termination-Action RADIUS-Request 1
+
+# NAS Port Types
+
+VALUE NAS-Port-Type Async 0
+VALUE NAS-Port-Type Sync 1
+VALUE NAS-Port-Type ISDN 2
+VALUE NAS-Port-Type ISDN-V120 3
+VALUE NAS-Port-Type ISDN-V110 4
+VALUE NAS-Port-Type Virtual 5
+VALUE NAS-Port-Type PIAFS 6
+VALUE NAS-Port-Type HDLC-Clear-Channel 7
+VALUE NAS-Port-Type X.25 8
+VALUE NAS-Port-Type X.75 9
+VALUE NAS-Port-Type G.3-Fax 10
+VALUE NAS-Port-Type SDSL 11
+VALUE NAS-Port-Type ADSL-CAP 12
+VALUE NAS-Port-Type ADSL-DMT 13
+VALUE NAS-Port-Type IDSL 14
+VALUE NAS-Port-Type Ethernet 15
+VALUE NAS-Port-Type xDSL 16
+VALUE NAS-Port-Type Cable 17
+VALUE NAS-Port-Type Wireless-Other 18
+VALUE NAS-Port-Type Wireless-802.11 19
diff --git a/accel-pppd/radius/dict/dictionary.rfc2866 b/accel-pppd/radius/dict/dictionary.rfc2866
new file mode 100644
index 00000000..15472bd5
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc2866
@@ -0,0 +1,57 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 2866.
+# http://www.ietf.org/rfc/rfc2866.txt
+#
+# $Id: dictionary.rfc2866,v 1.2 2005/08/08 22:23:38 aland Exp $
+#
+ATTRIBUTE Acct-Status-Type 40 integer
+ATTRIBUTE Acct-Delay-Time 41 integer
+ATTRIBUTE Acct-Input-Octets 42 integer
+ATTRIBUTE Acct-Output-Octets 43 integer
+ATTRIBUTE Acct-Session-Id 44 string
+ATTRIBUTE Acct-Authentic 45 integer
+ATTRIBUTE Acct-Session-Time 46 integer
+ATTRIBUTE Acct-Input-Packets 47 integer
+ATTRIBUTE Acct-Output-Packets 48 integer
+ATTRIBUTE Acct-Terminate-Cause 49 integer
+ATTRIBUTE Acct-Multi-Session-Id 50 string
+ATTRIBUTE Acct-Link-Count 51 integer
+
+# Accounting Status Types
+
+VALUE Acct-Status-Type Start 1
+VALUE Acct-Status-Type Stop 2
+VALUE Acct-Status-Type Alive 3 # dup
+VALUE Acct-Status-Type Interim-Update 3
+VALUE Acct-Status-Type Accounting-On 7
+VALUE Acct-Status-Type Accounting-Off 8
+VALUE Acct-Status-Type Failed 15
+
+# Authentication Types
+
+VALUE Acct-Authentic RADIUS 1
+VALUE Acct-Authentic Local 2
+VALUE Acct-Authentic Remote 3
+VALUE Acct-Authentic Diameter 4
+
+# Acct Terminate Causes
+
+VALUE Acct-Terminate-Cause User-Request 1
+VALUE Acct-Terminate-Cause Lost-Carrier 2
+VALUE Acct-Terminate-Cause Lost-Service 3
+VALUE Acct-Terminate-Cause Idle-Timeout 4
+VALUE Acct-Terminate-Cause Session-Timeout 5
+VALUE Acct-Terminate-Cause Admin-Reset 6
+VALUE Acct-Terminate-Cause Admin-Reboot 7
+VALUE Acct-Terminate-Cause Port-Error 8
+VALUE Acct-Terminate-Cause NAS-Error 9
+VALUE Acct-Terminate-Cause NAS-Request 10
+VALUE Acct-Terminate-Cause NAS-Reboot 11
+VALUE Acct-Terminate-Cause Port-Unneeded 12
+VALUE Acct-Terminate-Cause Port-Preempted 13
+VALUE Acct-Terminate-Cause Port-Suspended 14
+VALUE Acct-Terminate-Cause Service-Unavailable 15
+VALUE Acct-Terminate-Cause Callback 16
+VALUE Acct-Terminate-Cause User-Error 17
+VALUE Acct-Terminate-Cause Host-Request 18
diff --git a/accel-pppd/radius/dict/dictionary.rfc2867 b/accel-pppd/radius/dict/dictionary.rfc2867
new file mode 100644
index 00000000..b018aba4
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc2867
@@ -0,0 +1,16 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 2867.
+# http://www.ietf.org/rfc/rfc2867.txt
+#
+# $Id: dictionary.rfc2867,v 1.2 2005/08/08 22:23:38 aland Exp $
+#
+ATTRIBUTE Acct-Tunnel-Connection 68 string
+ATTRIBUTE Acct-Tunnel-Packets-Lost 86 integer
+
+VALUE Acct-Status-Type Tunnel-Start 9
+VALUE Acct-Status-Type Tunnel-Stop 10
+VALUE Acct-Status-Type Tunnel-Reject 11
+VALUE Acct-Status-Type Tunnel-Link-Start 12
+VALUE Acct-Status-Type Tunnel-Link-Stop 13
+VALUE Acct-Status-Type Tunnel-Link-Reject 14
diff --git a/accel-pppd/radius/dict/dictionary.rfc2868 b/accel-pppd/radius/dict/dictionary.rfc2868
new file mode 100644
index 00000000..f6a4047a
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc2868
@@ -0,0 +1,54 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 2868.
+# http://www.ietf.org/rfc/rfc2868.txt
+#
+# $Id: dictionary.rfc2868,v 1.4 2007/02/13 13:28:17 aland Exp $
+#
+ATTRIBUTE Tunnel-Type 64 integer has_tag
+ATTRIBUTE Tunnel-Medium-Type 65 integer has_tag
+ATTRIBUTE Tunnel-Client-Endpoint 66 string has_tag
+ATTRIBUTE Tunnel-Server-Endpoint 67 string has_tag
+
+ATTRIBUTE Tunnel-Password 69 string has_tag,encrypt=2
+
+ATTRIBUTE Tunnel-Private-Group-Id 81 string has_tag
+ATTRIBUTE Tunnel-Assignment-Id 82 string has_tag
+ATTRIBUTE Tunnel-Preference 83 integer has_tag
+
+ATTRIBUTE Tunnel-Client-Auth-Id 90 string has_tag
+ATTRIBUTE Tunnel-Server-Auth-Id 91 string has_tag
+
+# Tunnel Type
+
+VALUE Tunnel-Type PPTP 1
+VALUE Tunnel-Type L2F 2
+VALUE Tunnel-Type L2TP 3
+VALUE Tunnel-Type ATMP 4
+VALUE Tunnel-Type VTP 5
+VALUE Tunnel-Type AH 6
+VALUE Tunnel-Type IP 7
+VALUE Tunnel-Type MIN-IP 8
+VALUE Tunnel-Type ESP 9
+VALUE Tunnel-Type GRE 10
+VALUE Tunnel-Type DVS 11
+VALUE Tunnel-Type IP-in-IP 12
+
+# Tunnel Medium Type
+
+VALUE Tunnel-Medium-Type IP 1
+VALUE Tunnel-Medium-Type IPv4 1
+VALUE Tunnel-Medium-Type IPv6 2
+VALUE Tunnel-Medium-Type NSAP 3
+VALUE Tunnel-Medium-Type HDLC 4
+VALUE Tunnel-Medium-Type BBN-1822 5
+VALUE Tunnel-Medium-Type IEEE-802 6
+VALUE Tunnel-Medium-Type E.163 7
+VALUE Tunnel-Medium-Type E.164 8
+VALUE Tunnel-Medium-Type F.69 9
+VALUE Tunnel-Medium-Type X.121 10
+VALUE Tunnel-Medium-Type IPX 11
+VALUE Tunnel-Medium-Type Appletalk 12
+VALUE Tunnel-Medium-Type DecNet-IV 13
+VALUE Tunnel-Medium-Type Banyan-Vines 14
+VALUE Tunnel-Medium-Type E.164-NSAP 15
diff --git a/accel-pppd/radius/dict/dictionary.rfc2869 b/accel-pppd/radius/dict/dictionary.rfc2869
new file mode 100644
index 00000000..1a2631ec
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc2869
@@ -0,0 +1,39 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 2869.
+# http://www.ietf.org/rfc/rfc2869.txt
+#
+# $Id: dictionary.rfc2869,v 1.2 2005/08/08 22:23:39 aland Exp $
+#
+ATTRIBUTE Acct-Input-Gigawords 52 integer
+ATTRIBUTE Acct-Output-Gigawords 53 integer
+
+ATTRIBUTE Event-Timestamp 55 date
+
+ATTRIBUTE ARAP-Password 70 octets # 16 octets of data
+ATTRIBUTE ARAP-Features 71 octets # 14 octets of data
+ATTRIBUTE ARAP-Zone-Access 72 integer
+ATTRIBUTE ARAP-Security 73 integer
+ATTRIBUTE ARAP-Security-Data 74 string
+ATTRIBUTE Password-Retry 75 integer
+ATTRIBUTE Prompt 76 integer
+ATTRIBUTE Connect-Info 77 string
+ATTRIBUTE Configuration-Token 78 string
+ATTRIBUTE EAP-Message 79 octets
+ATTRIBUTE Message-Authenticator 80 octets
+
+ATTRIBUTE ARAP-Challenge-Response 84 octets # 8 octets of data
+ATTRIBUTE Acct-Interim-Interval 85 integer
+# 86: RFC 2867
+ATTRIBUTE NAS-Port-Id 87 string
+ATTRIBUTE Framed-Pool 88 string
+
+# ARAP Zone Access
+
+VALUE ARAP-Zone-Access Default-Zone 1
+VALUE ARAP-Zone-Access Zone-Filter-Inclusive 2
+VALUE ARAP-Zone-Access Zone-Filter-Exclusive 4
+
+# Prompt
+VALUE Prompt No-Echo 0
+VALUE Prompt Echo 1
diff --git a/accel-pppd/radius/dict/dictionary.rfc3576 b/accel-pppd/radius/dict/dictionary.rfc3576
new file mode 100644
index 00000000..35aeb326
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc3576
@@ -0,0 +1,30 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 3576.
+# http://www.ietf.org/rfc/rfc3576.txt
+#
+# $Id: dictionary.rfc3576,v 1.2 2005/08/08 22:23:39 aland Exp $
+#
+ATTRIBUTE Error-Cause 101 integer
+
+# Service Types
+
+VALUE Service-Type Authorize-Only 17
+
+# Error causes
+
+VALUE Error-Cause Residual-Context-Removed 201
+VALUE Error-Cause Invalid-EAP-Packet 202
+VALUE Error-Cause Unsupported-Attribute 401
+VALUE Error-Cause Missing-Attribute 402
+VALUE Error-Cause NAS-Identification-Mismatch 403
+VALUE Error-Cause Invalid-Request 404
+VALUE Error-Cause Unsupported-Service 405
+VALUE Error-Cause Unsupported-Extension 406
+VALUE Error-Cause Administratively-Prohibited 501
+VALUE Error-Cause Proxy-Request-Not-Routable 502
+VALUE Error-Cause Session-Context-Not-Found 503
+VALUE Error-Cause Session-Context-Not-Removable 504
+VALUE Error-Cause Proxy-Processing-Error 505
+VALUE Error-Cause Resources-Unavailable 506
+VALUE Error-Cause Request-Initiated 507
diff --git a/accel-pppd/radius/dict/dictionary.rfc3580 b/accel-pppd/radius/dict/dictionary.rfc3580
new file mode 100644
index 00000000..1bd4ca3e
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc3580
@@ -0,0 +1,16 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 3580.
+# http://www.ietf.org/rfc/rfc3580.txt
+#
+# $Id: dictionary.rfc3580,v 1.2 2005/08/08 22:23:39 aland Exp $
+#
+VALUE Acct-Terminate-Cause Supplicant-Restart 19
+VALUE Acct-Terminate-Cause Reauthentication-Failure 20
+VALUE Acct-Terminate-Cause Port-Reinit 21
+VALUE Acct-Terminate-Cause Port-Disabled 22
+
+VALUE NAS-Port-Type Token-Ring 20
+VALUE NAS-Port-Type FDDI 21
+
+VALUE Tunnel-Type VLAN 13
diff --git a/accel-pppd/radius/dict/dictionary.rfc4072 b/accel-pppd/radius/dict/dictionary.rfc4072
new file mode 100644
index 00000000..2280d075
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc4072
@@ -0,0 +1,9 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 4072
+# http://www.ietf.org/rfc/4072.txt
+#
+# $Id: dictionary.rfc4072,v 1.1 2007/11/14 09:00:25 aland Exp $
+#
+
+ATTRIBUTE EAP-Key-Name 102 string
diff --git a/accel-pppd/radius/dict/dictionary.rfc4372 b/accel-pppd/radius/dict/dictionary.rfc4372
new file mode 100644
index 00000000..b8af44ac
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc4372
@@ -0,0 +1,8 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 4372.
+# http://www.ietf.org/rfc/4372.txt
+#
+# $Id: dictionary.rfc4372,v 1.1 2007/04/07 14:47:34 aland Exp $
+#
+ATTRIBUTE Chargeable-User-Identity 89 string
diff --git a/accel-pppd/radius/dict/dictionary.rfc4675 b/accel-pppd/radius/dict/dictionary.rfc4675
new file mode 100644
index 00000000..8d1187f4
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc4675
@@ -0,0 +1,28 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 4675.
+# http://www.ietf.org/rfc/4675.txt
+#
+# $Id: dictionary.rfc4675,v 1.1 2007/04/07 14:54:14 aland Exp $
+#
+
+#
+# High byte = '1' (0x31) means the frames are tagged.
+# High byte = '2' (0x32) means the frames are untagged.
+#
+# Next 12 bits MUST be zero.
+#
+# Lower 12 bits is the IEEE-802.1Q VLAN VID.
+#
+ATTRIBUTE Egress-VLANID 56 integer
+ATTRIBUTE Ingress-Filters 57 integer
+
+#
+# First byte == '1' (0x31) means that the frames are tagged.
+# First byte == '2' (0x32) means that the frames are untagged.
+#
+ATTRIBUTE Egress-VLAN-Name 58 string
+ATTRIBUTE User-Priority-Table 59 octets # 8
+
+VALUE Ingress-Filters Enabled 1
+VALUE Ingress-Filters Disabled 2
diff --git a/accel-pppd/radius/dict/dictionary.rfc4679 b/accel-pppd/radius/dict/dictionary.rfc4679
new file mode 100644
index 00000000..39892a54
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc4679
@@ -0,0 +1,62 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 4679.
+# http://www.ietf.org/rfc/4679.txt
+#
+# $Id: dictionary.rfc4679,v 1.1 2007/04/08 14:18:01 aland Exp $
+#
+
+VENDOR ADSL-Forum 3561
+
+BEGIN-VENDOR ADSL-Forum
+
+#
+# The first two attributes are prefixed with "ADSL-" because of
+# conflicting names in dictionary.redback.
+#
+ATTRIBUTE ADSL-Agent-Circuit-Id 1 string
+ATTRIBUTE ADSL-Agent-Remote-Id 2 string
+ATTRIBUTE Actual-Data-Rate-Upstream 129 integer
+ATTRIBUTE Actual-Data-Rate-Downstream 130 integer
+ATTRIBUTE Minimum-Data-Rate-Upstream 131 integer
+ATTRIBUTE Minimum-Data-Rate-Downstream 132 integer
+ATTRIBUTE Attainable-Data-Rate-Upstream 133 integer
+ATTRIBUTE Attainable-Data-Rate-Downstream 134 integer
+ATTRIBUTE Maximum-Data-Rate-Upstream 135 integer
+ATTRIBUTE Maximum-Data-Rate-Downstream 136 integer
+ATTRIBUTE Minimum-Data-Rate-Upstream-Low-Power 137 integer
+ATTRIBUTE Minimum-Data-Rate-Downstream-Low-Power 138 integer
+ATTRIBUTE Maximum-Interleaving-Delay-Upstream 139 integer
+ATTRIBUTE Actual-Interleaving-Delay-Upstream 140 integer
+ATTRIBUTE Maximum-Interleaving-Delay-Downstream 141 integer
+ATTRIBUTE Actual-Interleaving-Delay-Downstream 142 integer
+
+#
+# This next attribute has a weird encoding.
+#
+# Octet[0] - 0x01 AAL5
+# Octet[0] - 0x02 Ethernet
+
+# Octet[1] - 0x00 Not Available
+# Octet[1] - 0x01 Untagged Ethernet
+# Octet[1] - 0x02 Single-Tagged Ethernet
+
+# Octet[2] - 0x00 Not available
+# Octet[2] - 0x01 PPPoA LLC
+# Octet[2] - 0x02 PPPoA Null
+# Octet[2] - 0x03 IPoA LLC
+# Octet[2] - 0x04 IPoA NULL
+# Octet[2] - 0x05 Ethernet over AAL5 LLC with FCS
+# Octet[2] - 0x06 Ethernet over AAL5 LLC without FCS
+# Octet[2] - 0x07 Ethernet over AAL5 Null with FCS
+# Octet[2] - 0x08 Ethernet over AAL5 Null without FCS
+#
+ATTRIBUTE Access-Loop-Encapsulation 144 octets # 3
+
+#
+# If this attribute exists, it means that IFW has been performed
+# for the subscribers session.
+#
+ATTRIBUTE IWF-Session 252 octets # 0
+
+END-VENDOR ADSL-Forum
diff --git a/accel-pppd/radius/dict/dictionary.rfc4818 b/accel-pppd/radius/dict/dictionary.rfc4818
new file mode 100644
index 00000000..4ea59452
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc4818
@@ -0,0 +1,11 @@
+# -*- text -*-
+##############################################################################
+#
+# Attributes and values defined in RFC 4818.
+# http://www.ietf.org/rfc/rfc4818.txt
+#
+# $Id: dictionary.rfc4818,v 1.1 2007/05/16 10:06:36 aland Exp $
+#
+##############################################################################
+
+ATTRIBUTE Delegated-IPv6-Prefix 123 ipv6prefix
diff --git a/accel-pppd/radius/dict/dictionary.rfc4849 b/accel-pppd/radius/dict/dictionary.rfc4849
new file mode 100644
index 00000000..1738eea0
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc4849
@@ -0,0 +1,8 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 4849.
+# http://www.ietf.org/rfc/rfc4849.txt
+#
+# $Id: dictionary.rfc4849,v 1.2 2007/06/15 13:08:03 aland Exp $
+#
+ATTRIBUTE NAS-Filter-Rule 92 string
diff --git a/accel-pppd/radius/dict/dictionary.rfc5176 b/accel-pppd/radius/dict/dictionary.rfc5176
new file mode 100644
index 00000000..93089612
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc5176
@@ -0,0 +1,9 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 5176.
+# http://www.ietf.org/rfc/rfc5176.txt
+#
+# $Id: dictionary.rfc5176,v 1.1 2008/03/08 16:17:44 aland Exp $
+#
+VALUE Error-Cause Invalid-Attribute-Value 407
+VALUE Error-Cause Multiple-Session-Selection-Unsupported 508
diff --git a/accel-pppd/radius/dict2c.py b/accel-pppd/radius/dict2c.py
new file mode 100644
index 00000000..ff0961e7
--- /dev/null
+++ b/accel-pppd/radius/dict2c.py
@@ -0,0 +1,20 @@
+import sys,re
+
+hdr = file(sys.argv[2],'w')
+
+def process(fname, hdr):
+ for line in file(fname):
+ if line[:-1].strip() == '':
+ continue
+ if line[0] == '#':
+ continue
+ f = re.compile('[$.a-zA-Z0-9\-]+').findall(line)
+ if f[0] == 'ATTRIBUTE' or f[0] == 'VENDOR':
+ hdr.write('#define {0} {1}\n'.format(f[1].replace('-','_').replace('.','_'), f[2]))
+ elif f[0] == 'VALUE':
+ hdr.write('#define {0}_{1} {2}\n'.format(f[1].replace('-','_').replace('.','_'), f[2].replace('-','_'),f[3]))
+ elif f[0] == '$INCLUDE':
+ process(f[1], hdr)
+
+if __name__ == '__main__':
+ process(sys.argv[1], hdr)
diff --git a/accel-pppd/radius/dm_coa.c b/accel-pppd/radius/dm_coa.c
new file mode 100644
index 00000000..366bb417
--- /dev/null
+++ b/accel-pppd/radius/dm_coa.c
@@ -0,0 +1,295 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <openssl/md5.h>
+
+#include "triton.h"
+#include "events.h"
+#include "log.h"
+
+#include "radius_p.h"
+
+#include "memdebug.h"
+
+#define PD_COA_PORT 3799
+
+struct dm_coa_serv_t
+{
+ struct triton_context_t ctx;
+ struct triton_md_handler_t hnd;
+};
+
+static struct dm_coa_serv_t serv;
+
+static int dm_coa_check_RA(struct rad_packet_t *pack, const char *secret)
+{
+ uint8_t RA[16];
+ MD5_CTX ctx;
+
+ memset(RA, 0, 16);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, pack->buf, 4);
+ MD5_Update(&ctx, RA, 16);
+ MD5_Update(&ctx, pack->buf + 20, pack->len - 20);
+ MD5_Update(&ctx, secret, strlen(secret));
+ MD5_Final(RA, &ctx);
+
+ return memcmp(RA, pack->buf + 4, 16);
+}
+
+static void dm_coa_set_RA(struct rad_packet_t *pack, const char *secret)
+{
+ MD5_CTX ctx;
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, pack->buf, pack->len);
+ MD5_Update(&ctx, secret, strlen(secret));
+ MD5_Final(pack->buf + 4, &ctx);
+}
+
+static int dm_coa_send_ack(int fd, struct rad_packet_t *req, struct sockaddr_in *addr)
+{
+ struct rad_packet_t *reply;
+ uint8_t RA[16];
+
+ memcpy(RA, req->buf + 4, sizeof(RA));
+
+ reply = rad_packet_alloc(req->code == CODE_COA_REQUEST ? CODE_COA_ACK : CODE_DISCONNECT_ACK);
+ if (!reply)
+ return -1;
+
+ reply->id = req->id;
+
+ if (rad_packet_build(reply, RA)) {
+ rad_packet_free(reply);
+ return -1;
+ }
+
+ dm_coa_set_RA(reply, conf_dm_coa_secret);
+
+ if (conf_verbose) {
+ log_ppp_info2("send ");
+ rad_packet_print(reply, log_ppp_info2);
+ }
+
+ rad_packet_send(reply, fd, addr);
+
+ rad_packet_free(reply);
+
+ return 0;
+}
+
+static int dm_coa_send_nak(int fd, struct rad_packet_t *req, struct sockaddr_in *addr, int err_code)
+{
+ struct rad_packet_t *reply;
+ uint8_t RA[16];
+
+ memcpy(RA, req->buf + 4, sizeof(RA));
+
+ reply = rad_packet_alloc(req->code == CODE_COA_REQUEST ? CODE_COA_NAK : CODE_DISCONNECT_NAK);
+ if (!reply)
+ return -1;
+
+ reply->id = req->id;
+
+ if (err_code)
+ rad_packet_add_int(reply, NULL, "Error-Cause", err_code);
+
+ if (rad_packet_build(reply, RA)) {
+ rad_packet_free(reply);
+ return -1;
+ }
+
+ dm_coa_set_RA(reply, conf_dm_coa_secret);
+
+ if (conf_verbose) {
+ log_ppp_info2("send ");
+ rad_packet_print(reply, log_ppp_info2);
+ }
+
+ rad_packet_send(reply, fd, addr);
+
+ rad_packet_free(reply);
+
+ return 0;
+}
+
+
+static void disconnect_request(struct radius_pd_t *rpd)
+{
+ if (conf_verbose) {
+ log_ppp_info2("recv ");
+ rad_packet_print(rpd->dm_coa_req, log_ppp_info2);
+ }
+
+ dm_coa_send_ack(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr);
+
+ rad_packet_free(rpd->dm_coa_req);
+
+ pthread_mutex_lock(&rpd->lock);
+ rpd->dm_coa_req = NULL;
+ pthread_mutex_unlock(&rpd->lock);
+
+ ppp_terminate(rpd->ppp, TERM_ADMIN_RESET, 0);
+}
+
+static void coa_request(struct radius_pd_t *rpd)
+{
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = rpd->dm_coa_req,
+ };
+
+ if (conf_verbose) {
+ log_ppp_info2("recv ");
+ rad_packet_print(rpd->dm_coa_req, log_ppp_info2);
+ }
+
+ triton_event_fire(EV_RADIUS_COA, &ev);
+
+ if (ev.res)
+ dm_coa_send_nak(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr, 0);
+ else
+ dm_coa_send_ack(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr);
+
+ rad_packet_free(rpd->dm_coa_req);
+
+ pthread_mutex_lock(&rpd->lock);
+ rpd->dm_coa_req = NULL;
+ pthread_mutex_unlock(&rpd->lock);
+}
+
+void dm_coa_cancel(struct radius_pd_t *rpd)
+{
+ triton_cancel_call(rpd->ppp->ctrl->ctx, (triton_event_func)disconnect_request);
+ triton_cancel_call(rpd->ppp->ctrl->ctx, (triton_event_func)coa_request);
+ rad_packet_free(rpd->dm_coa_req);
+}
+
+static int dm_coa_read(struct triton_md_handler_t *h)
+{
+ struct rad_packet_t *pack;
+ struct radius_pd_t *rpd;
+ int err_code;
+ struct sockaddr_in addr;
+
+ while (1) {
+ if (rad_packet_recv(h->fd, &pack, &addr))
+ return 0;
+
+ if (!pack)
+ continue;
+
+ if (pack->code != CODE_DISCONNECT_REQUEST && pack->code != CODE_COA_REQUEST) {
+ log_warn("radius:dm_coa: unexpected code (%i) received\n", pack->code);
+ goto out_err_no_reply;
+ }
+
+ if (dm_coa_check_RA(pack, conf_dm_coa_secret)) {
+ log_warn("radius:dm_coa: RA validation failed\n");
+ goto out_err_no_reply;
+ }
+
+ if (conf_verbose) {
+ log_debug("recv ");
+ rad_packet_print(pack, log_debug);
+ }
+
+ if (rad_check_nas_pack(pack)) {
+ log_warn("radius:dm_coa: NAS identification failed\n");
+ err_code = 403;
+ goto out_err;
+ }
+
+ rpd = rad_find_session_pack(pack);
+ if (!rpd) {
+ log_warn("radius:dm_coa: session not found\n");
+ err_code = 503;
+ goto out_err;
+ }
+
+ if (rpd->dm_coa_req) {
+ pthread_mutex_unlock(&rpd->lock);
+ goto out_err_no_reply;
+ }
+
+ rpd->dm_coa_req = pack;
+ memcpy(&rpd->dm_coa_addr, &addr, sizeof(addr));
+
+ if (pack->code == CODE_DISCONNECT_REQUEST)
+ triton_context_call(rpd->ppp->ctrl->ctx, (triton_event_func)disconnect_request, rpd);
+ else
+ triton_context_call(rpd->ppp->ctrl->ctx, (triton_event_func)coa_request, rpd);
+
+ pthread_mutex_unlock(&rpd->lock);
+
+ continue;
+
+ out_err:
+ dm_coa_send_nak(h->fd, pack, &addr, err_code);
+
+ out_err_no_reply:
+ rad_packet_free(pack);
+ }
+}
+
+static void dm_coa_close(struct triton_context_t *ctx)
+{
+ struct dm_coa_serv_t *serv = container_of(ctx, typeof(*serv), ctx);
+ triton_md_unregister_handler(&serv->hnd);
+ close(serv->hnd.fd);
+ triton_context_unregister(ctx);
+}
+
+static struct dm_coa_serv_t serv = {
+ .ctx.close = dm_coa_close,
+ .ctx.before_switch = log_switch,
+ .hnd.read = dm_coa_read,
+};
+
+static void __init init(void)
+{
+ struct sockaddr_in addr;
+
+ if (!conf_dm_coa_secret) {
+ log_emerg("radius: no dm_coa_secret specified, DM/CoA disabled...\n");
+ return;
+ }
+
+ serv.hnd.fd = socket (PF_INET, SOCK_DGRAM, 0);
+ if (serv.hnd.fd < 0) {
+ log_emerg("radius:dm_coa: socket: %s\n", strerror(errno));
+ return;
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (conf_dm_coa_port);
+ if (conf_dm_coa_server)
+ addr.sin_addr.s_addr = conf_dm_coa_server;
+ else
+ addr.sin_addr.s_addr = htonl (INADDR_ANY);
+ if (bind (serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
+ log_emerg("radius:dm_coa: bind: %s\n", strerror(errno));
+ close(serv.hnd.fd);
+ return;
+ }
+
+ if (fcntl(serv.hnd.fd, F_SETFL, O_NONBLOCK)) {
+ log_emerg("radius:dm_coa: failed to set nonblocking mode: %s\n", strerror(errno));
+ close(serv.hnd.fd);
+ return;
+ }
+
+ triton_context_register(&serv.ctx, NULL);
+ triton_md_register_handler(&serv.ctx, &serv.hnd);
+ triton_md_enable_handler(&serv.hnd, MD_MODE_READ);
+ triton_context_wakeup(&serv.ctx);
+}
diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c
new file mode 100644
index 00000000..4e24dedc
--- /dev/null
+++ b/accel-pppd/radius/packet.c
@@ -0,0 +1,644 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "log.h"
+#include "mempool.h"
+
+#include "radius_p.h"
+
+#include "memdebug.h"
+
+static mempool_t packet_pool;
+static mempool_t attr_pool;
+
+struct rad_packet_t *rad_packet_alloc(int code)
+{
+ struct rad_packet_t *pack;
+
+ pack = mempool_alloc(packet_pool);
+ if (!pack) {
+ log_emerg("radius:packet: out of memory\n");
+ return NULL;
+ }
+
+ memset(pack, 0, sizeof(*pack));
+ pack->code = code;
+ pack->len = 20;
+ pack->id = 1;
+ INIT_LIST_HEAD(&pack->attrs);
+
+ return pack;
+}
+
+void print_buf(uint8_t *buf,int size)
+{
+ int i;
+ for(i=0;i<size;i++)
+ printf("%x ",buf[i]);
+ printf("\n");
+}
+
+int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA)
+{
+ struct rad_attr_t *attr;
+ uint8_t *ptr;
+
+ if (pack->buf)
+ ptr = _realloc(pack->buf, pack->len);
+ else
+ ptr = _malloc(pack->len);
+
+ if (!ptr) {
+ log_emerg("radius:packet: out of memory\n");
+ return -1;
+ }
+
+ pack->buf = ptr;
+ *ptr = pack->code; ptr++;
+ *ptr = pack->id; ptr++;
+ *(uint16_t*)ptr = htons(pack->len); ptr+= 2;
+ memcpy(ptr, RA, 16); ptr+=16;
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ if (attr->vendor) {
+ *ptr = 26; ptr++;
+ *ptr = attr->len + 2 + 6; ptr++;
+ *(uint32_t *)ptr = htonl(attr->vendor->id); ptr+=4;
+ }
+ *ptr = attr->attr->id; ptr++;
+ *ptr = attr->len + 2; ptr++;
+ switch(attr->attr->type) {
+ case ATTR_TYPE_INTEGER:
+ *(uint32_t*)ptr = htonl(attr->val.integer);
+ break;
+ case ATTR_TYPE_OCTETS:
+ case ATTR_TYPE_STRING:
+ memcpy(ptr, attr->val.string, attr->len);
+ break;
+ case ATTR_TYPE_IPADDR:
+ *(in_addr_t*)ptr = attr->val.ipaddr;
+ break;
+ case ATTR_TYPE_DATE:
+ *(uint32_t*)ptr = htonl(attr->val.date);
+ break;
+ default:
+ log_emerg("radius:packet:BUG: unknown attribute type\n");
+ abort();
+ }
+ ptr += attr->len;
+ }
+
+ //print_buf(pack->buf, pack->len);
+ return 0;
+}
+
+int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr)
+{
+ struct rad_packet_t *pack;
+ struct rad_attr_t *attr;
+ struct rad_dict_attr_t *da;
+ struct rad_dict_vendor_t *vendor;
+ uint8_t *ptr;
+ int n, id, len, vendor_id;
+ socklen_t addr_len = sizeof(*addr);
+
+ *p = NULL;
+
+ pack = rad_packet_alloc(0);
+ if (!pack)
+ return 0;
+
+ pack->buf = _malloc(REQ_LENGTH_MAX);
+ if (!pack->buf) {
+ log_emerg("radius:packet: out of memory\n");
+ goto out_err;
+ }
+
+ while (1) {
+ if (addr)
+ n = recvfrom(fd, pack->buf, REQ_LENGTH_MAX, 0, addr, &addr_len);
+ else
+ n = read(fd, pack->buf, REQ_LENGTH_MAX);
+ if (n < 0) {
+ if (errno == EAGAIN) {
+ rad_packet_free(pack);
+ return -1;
+ }
+ if (errno != ECONNREFUSED)
+ log_ppp_error("radius:packet:read: %s\n", strerror(errno));
+ goto out_err;
+ }
+ break;
+ }
+
+ if (n < 20) {
+ log_ppp_warn("radius:packet: short packed received (%i)\n", n);
+ goto out_err;
+ }
+
+ ptr = (uint8_t *)pack->buf;
+
+ pack->code = *ptr; ptr++;
+ pack->id = *ptr; ptr++;
+ pack->len = ntohs(*(uint16_t*)ptr); ptr += 2;
+
+ if (pack->len > n) {
+ log_ppp_warn("radius:packet: short packet received %i, expected %i\n", pack->len, n);
+ goto out_err;
+ }
+
+ ptr += 16;
+ n -= 20;
+
+ while (n>0) {
+ id = *ptr; ptr++;
+ len = *ptr - 2; ptr++;
+ if (len < 0) {
+ log_ppp_warn("radius:packet short attribute len received\n");
+ goto out_err;
+ }
+ if (2 + len > n) {
+ log_ppp_warn("radius:packet: too long attribute received (%i, %i)\n", id, len);
+ goto out_err;
+ }
+ if (id == 26) {
+ vendor_id = ntohl(*(uint32_t *)ptr);
+ vendor = rad_dict_find_vendor_id(vendor_id);
+ if (vendor) {
+ ptr += 4;
+ id = *ptr; ptr++;
+ len = *ptr - 2; ptr++;
+ n -= 2 + 4;
+ } else
+ log_ppp_warn("radius:packet: vendor %i not found\n", id);
+ } else
+ vendor = NULL;
+ da = rad_dict_find_attr_id(vendor, id);
+ if (da) {
+ attr = mempool_alloc(attr_pool);
+ if (!attr) {
+ log_emerg("radius:packet: out of memory\n");
+ goto out_err;
+ }
+ memset(attr, 0, sizeof(*attr));
+ attr->vendor = vendor;
+ attr->attr = da;
+ attr->len = len;
+ switch (da->type) {
+ case ATTR_TYPE_STRING:
+ attr->val.string = _malloc(len+1);
+ if (!attr->val.string) {
+ log_emerg("radius:packet: out of memory\n");
+ _free(attr);
+ goto out_err;
+ }
+ memcpy(attr->val.string, ptr, len);
+ attr->val.string[len] = 0;
+ break;
+ case ATTR_TYPE_OCTETS:
+ attr->val.octets = _malloc(len);
+ if (!attr->val.octets) {
+ log_emerg("radius:packet: out of memory\n");
+ _free(attr);
+ goto out_err;
+ }
+ memcpy(attr->val.octets, ptr, len);
+ break;
+ case ATTR_TYPE_DATE:
+ case ATTR_TYPE_INTEGER:
+ attr->val.integer = ntohl(*(uint32_t*)ptr);
+ break;
+ case ATTR_TYPE_IPADDR:
+ attr->val.integer = *(uint32_t*)ptr;
+ break;
+ }
+ list_add_tail(&attr->entry, &pack->attrs);
+ } else
+ log_ppp_warn("radius:packet: unknown attribute received (%i,%i)\n", vendor ? vendor->id : 0, id);
+ ptr += len;
+ n -= 2 + len;
+ }
+
+ *p = pack;
+
+ return 0;
+
+out_err:
+ rad_packet_free(pack);
+ return 0;
+}
+
+void rad_packet_free(struct rad_packet_t *pack)
+{
+ struct rad_attr_t *attr;
+
+ if (pack->buf)
+ _free(pack->buf);
+
+ while(!list_empty(&pack->attrs)) {
+ attr = list_entry(pack->attrs.next, typeof(*attr), entry);
+ list_del(&attr->entry);
+ if (attr->attr->type == ATTR_TYPE_STRING || attr->attr->type == ATTR_TYPE_OCTETS)
+ _free(attr->val.string);
+ mempool_free(attr);
+ }
+
+ mempool_free(pack);
+}
+
+void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...))
+{
+ struct rad_attr_t *attr;
+ struct rad_dict_value_t *val;
+
+ print("[RADIUS ");
+ switch(pack->code) {
+ case CODE_ACCESS_REQUEST:
+ print("Access-Request");
+ break;
+ case CODE_ACCESS_CHALLENGE:
+ print("Access-Challenge");
+ break;
+ case CODE_ACCESS_ACCEPT:
+ print("Access-Accept");
+ break;
+ case CODE_ACCESS_REJECT:
+ print("Access-Reject");
+ break;
+ case CODE_ACCOUNTING_REQUEST:
+ print("Accounting-Request");
+ break;
+ case CODE_ACCOUNTING_RESPONSE:
+ print("Accounting-Response");
+ break;
+ case CODE_DISCONNECT_REQUEST:
+ print("Disconnect-Request");
+ break;
+ case CODE_DISCONNECT_ACK:
+ print("Disconnect-ACK");
+ break;
+ case CODE_DISCONNECT_NAK:
+ print("Disconnect-NAK");
+ break;
+ case CODE_COA_REQUEST:
+ print("CoA-Request");
+ break;
+ case CODE_COA_ACK:
+ print("CoA-ACK");
+ break;
+ case CODE_COA_NAK:
+ print("CoA-NAK");
+ break;
+ default:
+ print("Unknown (%i)", pack->code);
+ }
+ print(" id=%x", pack->id);
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ if (attr->vendor)
+ print("<%s %s ", attr->vendor->name, attr->attr->name);
+ else
+ print(" <%s ", attr->attr->name);
+ switch (attr->attr->type) {
+ case ATTR_TYPE_INTEGER:
+ val = rad_dict_find_val(attr->attr, attr->val);
+ if (val)
+ print("%s", val->name);
+ else
+ print("%u", attr->val.integer);
+ break;
+ case ATTR_TYPE_STRING:
+ print("\"%s\"", attr->val.string);
+ break;
+ case ATTR_TYPE_IPADDR:
+ print("%i.%i.%i.%i", attr->val.ipaddr & 0xff, (attr->val.ipaddr >> 8) & 0xff, (attr->val.ipaddr >> 16) & 0xff, (attr->val.ipaddr >> 24) & 0xff);
+ break;
+ }
+ print(">");
+ }
+ print("]\n");
+}
+
+int __export rad_packet_add_int(struct rad_packet_t *pack, const char *vendor_name, const char *name, int val)
+{
+ struct rad_attr_t *ra;
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_vendor_t *vendor;
+
+ if (pack->len + (vendor_name ? 8 : 2) + 4 >= REQ_LENGTH_MAX)
+ return -1;
+
+ if (vendor_name) {
+ vendor = rad_dict_find_vendor_name(vendor_name);
+ if (!vendor)
+ return -1;
+ attr = rad_dict_find_vendor_attr(vendor, name);
+ } else {
+ vendor = NULL;
+ attr = rad_dict_find_attr(name);
+ }
+
+ if (!attr)
+ return -1;
+
+ ra = mempool_alloc(attr_pool);
+ if (!ra)
+ return -1;
+
+ memset(ra, 0, sizeof(*ra));
+ ra->vendor = vendor;
+ ra->attr = attr;
+ ra->len = 4;
+ ra->val.integer = val;
+ list_add_tail(&ra->entry, &pack->attrs);
+ pack->len += (vendor_name ? 8 : 2) + 4;
+
+ return 0;
+}
+
+int __export rad_packet_change_int(struct rad_packet_t *pack, const char *vendor_name, const char *name, int val)
+{
+ struct rad_attr_t *ra;
+
+ ra = rad_packet_find_attr(pack, vendor_name, name);
+ if (!ra)
+ return -1;
+
+ ra->val.integer = val;
+
+ return 0;
+}
+
+int __export rad_packet_add_octets(struct rad_packet_t *pack, const char *vendor_name, const char *name, const uint8_t *val, int len)
+{
+ struct rad_attr_t *ra;
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_vendor_t *vendor;
+
+ if (pack->len + (vendor_name ? 8 : 2) + len >= REQ_LENGTH_MAX)
+ return -1;
+
+ if (vendor_name) {
+ vendor = rad_dict_find_vendor_name(vendor_name);
+ if (!vendor)
+ return -1;
+ attr = rad_dict_find_vendor_attr(vendor, name);
+ } else {
+ vendor = NULL;
+ attr = rad_dict_find_attr(name);
+ }
+
+ if (!attr)
+ return -1;
+
+ ra = mempool_alloc(attr_pool);
+ if (!ra) {
+ log_emerg("radius: out of memory\n");
+ return -1;
+ }
+
+ memset(ra, 0, sizeof(*ra));
+ ra->vendor = vendor;
+ ra->attr = attr;
+ ra->len = len;
+ ra->val.octets = _malloc(len);
+ if (!ra->val.octets) {
+ log_emerg("radius: out of memory\n");
+ _free(ra);
+ return -1;
+ }
+ memcpy(ra->val.octets, val, len);
+ list_add_tail(&ra->entry, &pack->attrs);
+ pack->len += (vendor_name ? 8 : 2) + len;
+
+ return 0;
+}
+
+int __export rad_packet_change_octets(struct rad_packet_t *pack, const char *vendor_name, const char *name, const uint8_t *val, int len)
+{
+ struct rad_attr_t *ra;
+
+ ra = rad_packet_find_attr(pack, vendor_name, name);
+ if (!ra)
+ return -1;
+
+ if (ra->len != len) {
+ if (pack->len - ra->len + len >= REQ_LENGTH_MAX)
+ return -1;
+
+ ra->val.octets = _realloc(ra->val.octets, len);
+ if (!ra->val.octets) {
+ log_emerg("radius: out of memory\n");
+ return -1;
+ }
+
+ pack->len += len - ra->len;
+ ra->len = len;
+ }
+
+ memcpy(ra->val.octets, val, len);
+
+ return 0;
+}
+
+
+int __export rad_packet_add_str(struct rad_packet_t *pack, const char *vendor_name, const char *name, const char *val)
+{
+ struct rad_attr_t *ra;
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_vendor_t *vendor;
+ int len = strlen(val);
+
+ if (pack->len + (vendor_name ? 8 : 2) + len >= REQ_LENGTH_MAX)
+ return -1;
+
+ if (vendor_name) {
+ vendor = rad_dict_find_vendor_name(vendor_name);
+ if (!vendor)
+ return -1;
+ attr = rad_dict_find_vendor_attr(vendor, name);
+ } else {
+ vendor = NULL;
+ attr = rad_dict_find_attr(name);
+ }
+
+ if (!attr)
+ return -1;
+
+ ra = mempool_alloc(attr_pool);
+ if (!ra) {
+ log_emerg("radius: out of memory\n");
+ return -1;
+ }
+
+ memset(ra, 0, sizeof(*ra));
+ ra->vendor = vendor;
+ ra->attr = attr;
+ ra->len = len;
+ ra->val.string = _malloc(len + 1);
+ if (!ra->val.string) {
+ log_emerg("radius: out of memory\n");
+ _free(ra);
+ return -1;
+ }
+ memcpy(ra->val.string, val, len);
+ ra->val.string[len] = 0;
+ list_add_tail(&ra->entry, &pack->attrs);
+ pack->len += (vendor_name ? 8 : 2) + len;
+
+ return 0;
+}
+
+int __export rad_packet_change_str(struct rad_packet_t *pack, const char *vendor_name, const char *name, const char *val, int len)
+{
+ struct rad_attr_t *ra;
+
+ ra = rad_packet_find_attr(pack, vendor_name, name);
+ if (!ra)
+ return -1;
+
+ if (ra->len != len) {
+ if (pack->len - ra->len + len >= REQ_LENGTH_MAX)
+ return -1;
+
+ ra->val.string = _realloc(ra->val.string, len + 1);
+ if (!ra->val.string) {
+ log_emerg("radius: out of memory\n");
+ return -1;
+ }
+
+ pack->len += len - ra->len;
+ ra->len = len;
+ }
+
+ memcpy(ra->val.string, val, len);
+ ra->val.string[len] = 0;
+
+ return 0;
+}
+
+int __export rad_packet_add_val(struct rad_packet_t *pack, const char *vendor_name, const char *name, const char *val)
+{
+ struct rad_attr_t *ra;
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_value_t *v;
+ struct rad_dict_vendor_t *vendor;
+
+ if (pack->len + (vendor_name ? 8 : 2) + 4 >= REQ_LENGTH_MAX)
+ return -1;
+
+ if (vendor_name) {
+ vendor = rad_dict_find_vendor_name(vendor_name);
+ if (!vendor)
+ return -1;
+ attr = rad_dict_find_vendor_attr(vendor, name);
+ } else {
+ vendor = NULL;
+ attr = rad_dict_find_attr(name);
+ }
+
+ if (!attr)
+ return -1;
+
+ v = rad_dict_find_val_name(attr, val);
+ if (!v)
+ return -1;
+
+ ra = mempool_alloc(attr_pool);
+ if (!ra)
+ return -1;
+
+ memset(ra, 0, sizeof(*ra));
+ ra->vendor = vendor;
+ ra->attr = attr;
+ ra->len = 4;
+ ra->val = v->val;
+ list_add_tail(&ra->entry, &pack->attrs);
+ pack->len += (vendor_name ? 8 : 2) + 4;
+
+ return 0;
+}
+
+int __export rad_packet_change_val(struct rad_packet_t *pack, const char *vendor_name, const char *name, const char *val)
+{
+ struct rad_attr_t *ra;
+ struct rad_dict_value_t *v;
+
+ ra = rad_packet_find_attr(pack, vendor_name, name);
+ if (!ra)
+ return -1;
+
+ v = rad_dict_find_val_name(ra->attr, val);
+ if (!v)
+ return -1;
+
+ ra->val = v->val;
+
+ return 0;
+}
+
+int __export rad_packet_add_ipaddr(struct rad_packet_t *pack, const char *vendor_name, const char *name, in_addr_t ipaddr)
+{
+ return rad_packet_add_int(pack, vendor_name, name, ipaddr);
+}
+
+
+struct rad_attr_t __export *rad_packet_find_attr(struct rad_packet_t *pack, const char *vendor_name, const char *name)
+{
+ struct rad_attr_t *ra;
+ struct rad_dict_vendor_t *vendor;
+
+ if (vendor_name) {
+ vendor = rad_dict_find_vendor_name(vendor_name);
+ if (!vendor)
+ return NULL;
+ } else
+ vendor = NULL;
+
+ list_for_each_entry(ra, &pack->attrs, entry) {
+ if (vendor && vendor != ra->vendor)
+ continue;
+
+ if (strcmp(ra->attr->name, name))
+ continue;
+
+ return ra;
+ }
+
+ return NULL;
+}
+
+int rad_packet_send(struct rad_packet_t *pack, int fd, struct sockaddr_in *addr)
+{
+ int n;
+
+ while (1) {
+ if (addr)
+ n = sendto(fd, pack->buf, pack->len, 0, addr, sizeof(*addr));
+ else
+ n = write(fd, pack->buf, pack->len);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ log_ppp_error("radius:write: %s\n", strerror(errno));
+ return -1;
+ } else if (n != pack->len) {
+ log_ppp_error("radius:write: short write %i, excpected %i\n", n, pack->len);
+ return -1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void __init init(void)
+{
+ attr_pool = mempool_create(sizeof(struct rad_attr_t));
+ packet_pool = mempool_create(sizeof(struct rad_packet_t));
+}
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
new file mode 100644
index 00000000..8976a330
--- /dev/null
+++ b/accel-pppd/radius/radius.c
@@ -0,0 +1,529 @@
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+#include "mempool.h"
+#include "events.h"
+#include "log.h"
+#include "ppp.h"
+#include "pwdb.h"
+#include "ipdb.h"
+#include "ppp_auth.h"
+#include "cli.h"
+
+#include "radius_p.h"
+#include "attr_defs.h"
+
+#include "memdebug.h"
+
+#define CHAP_MD5 5
+#define MSCHAP_V1 0x80
+#define MSCHAP_V2 0x81
+
+int conf_max_try = 3;
+int conf_timeout = 3;
+int conf_acct_timeout = 600;
+char *conf_nas_identifier;
+in_addr_t conf_nas_ip_address;
+in_addr_t conf_gw_ip_address;
+in_addr_t conf_bind;
+int conf_verbose;
+int conf_interim_verbose;
+
+in_addr_t conf_auth_server;
+int conf_auth_server_port = 1812;
+char *conf_auth_secret;
+
+in_addr_t conf_acct_server;
+int conf_acct_server_port = 1813;
+char *conf_acct_secret;
+
+in_addr_t conf_dm_coa_server;
+int conf_dm_coa_port = 3799;
+char *conf_dm_coa_secret;
+
+int conf_sid_in_auth;
+int conf_require_nas_ident;
+int conf_acct_interim_interval;
+
+unsigned long stat_auth_sent;
+unsigned long stat_auth_lost;
+unsigned long stat_acct_sent;
+unsigned long stat_acct_lost;
+unsigned long stat_interim_sent;
+unsigned long stat_interim_lost;
+
+static LIST_HEAD(sessions);
+static pthread_rwlock_t sessions_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+static void *pd_key;
+static struct ipdb_t ipdb;
+
+static mempool_t rpd_pool;
+
+int rad_proc_attrs(struct rad_req_t *req)
+{
+ struct rad_attr_t *attr;
+ int res = 0;
+
+ req->rpd->acct_interim_interval = conf_acct_interim_interval;
+
+ list_for_each_entry(attr, &req->reply->attrs, entry) {
+ if (attr->vendor)
+ continue;
+ switch(attr->attr->id) {
+ case Framed_IP_Address:
+ if (!conf_gw_ip_address)
+ log_ppp_warn("radius: gw-ip-address not specified, cann't assign IP address...\n");
+ else {
+ req->rpd->ipaddr.owner = &ipdb;
+ req->rpd->ipaddr.peer_addr = attr->val.ipaddr;
+ req->rpd->ipaddr.addr = conf_gw_ip_address;
+ }
+ break;
+ case Acct_Interim_Interval:
+ req->rpd->acct_interim_interval = attr->val.integer;
+ break;
+ case Session_Timeout:
+ req->rpd->session_timeout.period = attr->val.integer * 1000;
+ break;
+ case Class:
+ if (!req->rpd->attr_class)
+ req->rpd->attr_class = _malloc(attr->len);
+ else if (req->rpd->attr_class_len != attr->len)
+ req->rpd->attr_class = _realloc(req->rpd->attr_class, attr->len);
+ memcpy(req->rpd->attr_class, attr->val.octets, attr->len);
+ req->rpd->attr_class_len = attr->len;
+ break;
+ case State:
+ if (!req->rpd->attr_state)
+ req->rpd->attr_state = _malloc(attr->len);
+ else if (req->rpd->attr_state_len != attr->len)
+ req->rpd->attr_state = _realloc(req->rpd->attr_state, attr->len);
+ memcpy(req->rpd->attr_state, attr->val.octets, attr->len);
+ req->rpd->attr_state_len = attr->len;
+ break;
+ case Termination_Action:
+ req->rpd->termination_action = attr->val.integer;
+ break;
+ }
+ }
+
+ return res;
+}
+
+static int check(struct pwdb_t *pwdb, struct ppp_t *ppp, const char *username, int type, va_list _args)
+{
+ int r = PWDB_NO_IMPL;
+ va_list args;
+ int chap_type;
+ struct radius_pd_t *rpd = find_pd(ppp);
+
+ va_copy(args, _args);
+
+ switch(type) {
+ case PPP_PAP:
+ r = rad_auth_pap(rpd, username, args);
+ break;
+ case PPP_CHAP:
+ chap_type = va_arg(args, int);
+ switch(chap_type) {
+ case CHAP_MD5:
+ r = rad_auth_chap_md5(rpd, username, args);
+ break;
+ case MSCHAP_V1:
+ r = rad_auth_mschap_v1(rpd, username, args);
+ break;
+ case MSCHAP_V2:
+ r = rad_auth_mschap_v2(rpd, username, args);
+ break;
+ }
+ break;
+ }
+
+ va_end(args);
+
+ return r;
+}
+
+static struct ipdb_item_t *get_ip(struct ppp_t *ppp)
+{
+ struct radius_pd_t *rpd = find_pd(ppp);
+
+ if (rpd->ipaddr.peer_addr)
+ return &rpd->ipaddr;
+ return NULL;
+}
+
+static void session_timeout(struct triton_timer_t *t)
+{
+ struct radius_pd_t *rpd = container_of(t, typeof(*rpd), session_timeout);
+ log_ppp_msg("radius: session timed out\n");
+
+ if (rpd->ppp->stop_time)
+ return;
+
+ if (rpd->termination_action == Termination_Action_RADIUS_Request) {
+ if (ppp_auth_restart(rpd->ppp))
+ ppp_terminate(rpd->ppp, TERM_SESSION_TIMEOUT, 0);
+ } else
+ ppp_terminate(rpd->ppp, TERM_SESSION_TIMEOUT, 0);
+}
+
+static void ppp_starting(struct ppp_t *ppp)
+{
+ struct radius_pd_t *rpd = mempool_alloc(rpd_pool);
+
+ memset(rpd, 0, sizeof(*rpd));
+ rpd->pd.key = &pd_key;
+ rpd->ppp = ppp;
+ pthread_mutex_init(&rpd->lock, NULL);
+ INIT_LIST_HEAD(&rpd->plugin_list);
+ list_add_tail(&rpd->pd.entry, &ppp->pd_list);
+
+ pthread_rwlock_wrlock(&sessions_lock);
+ list_add_tail(&rpd->entry, &sessions);
+ pthread_rwlock_unlock(&sessions_lock);
+}
+
+static void ppp_acct_start(struct ppp_t *ppp)
+{
+ struct radius_pd_t *rpd = find_pd(ppp);
+
+ if (rad_acct_start(rpd)) {
+ ppp_terminate(rpd->ppp, TERM_NAS_ERROR, 0);
+ return;
+ }
+
+ if (rpd->session_timeout.period) {
+ rpd->session_timeout.expire = session_timeout;
+ triton_timer_add(ppp->ctrl->ctx, &rpd->session_timeout, 0);
+ }
+}
+static void ppp_finishing(struct ppp_t *ppp)
+{
+ struct radius_pd_t *rpd = find_pd(ppp);
+
+ rad_acct_stop(rpd);
+}
+static void ppp_finished(struct ppp_t *ppp)
+{
+ struct radius_pd_t *rpd = find_pd(ppp);
+
+ pthread_rwlock_wrlock(&sessions_lock);
+ pthread_mutex_lock(&rpd->lock);
+ list_del(&rpd->entry);
+ pthread_mutex_unlock(&rpd->lock);
+ pthread_rwlock_unlock(&sessions_lock);
+
+ if (rpd->auth_req)
+ rad_req_free(rpd->auth_req);
+
+ if (rpd->acct_req)
+ rad_req_free(rpd->acct_req);
+
+ if (rpd->dm_coa_req)
+ dm_coa_cancel(rpd);
+
+ if (rpd->session_timeout.tpd)
+ triton_timer_del(&rpd->session_timeout);
+
+ if (rpd->attr_class)
+ _free(rpd->attr_class);
+
+ if (rpd->attr_state)
+ _free(rpd->attr_state);
+
+ list_del(&rpd->pd.entry);
+
+ mempool_free(rpd);
+}
+
+struct radius_pd_t *find_pd(struct ppp_t *ppp)
+{
+ struct ppp_pd_t *pd;
+ struct radius_pd_t *rpd;
+
+ list_for_each_entry(pd, &ppp->pd_list, entry) {
+ if (pd->key == &pd_key) {
+ rpd = container_of(pd, typeof(*rpd), pd);
+ return rpd;
+ }
+ }
+ log_emerg("radius:BUG: rpd not found\n");
+ abort();
+}
+
+
+struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr, const char *csid)
+{
+ struct radius_pd_t *rpd;
+
+ pthread_rwlock_rdlock(&sessions_lock);
+ list_for_each_entry(rpd, &sessions, entry) {
+ if (!rpd->ppp->username)
+ continue;
+ if (sessionid && strcmp(sessionid, rpd->ppp->sessionid))
+ continue;
+ if (username && strcmp(username, rpd->ppp->username))
+ continue;
+ if (port_id >= 0 && port_id != rpd->ppp->unit_idx)
+ continue;
+ if (ipaddr && ipaddr != rpd->ppp->peer_ipaddr)
+ continue;
+ if (csid && rpd->ppp->ctrl->calling_station_id && strcmp(csid, rpd->ppp->ctrl->calling_station_id))
+ continue;
+ pthread_mutex_lock(&rpd->lock);
+ pthread_rwlock_unlock(&sessions_lock);
+ return rpd;
+ }
+ pthread_rwlock_unlock(&sessions_lock);
+ return NULL;
+}
+
+struct radius_pd_t *rad_find_session_pack(struct rad_packet_t *pack)
+{
+ struct rad_attr_t *attr;
+ const char *sessionid = NULL;
+ const char *username = NULL;
+ const char *csid = NULL;
+ int port_id = -1;
+ in_addr_t ipaddr = 0;
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ switch(attr->attr->id) {
+ case Acct_Session_Id:
+ sessionid = attr->val.string;
+ break;
+ case User_Name:
+ username = attr->val.string;
+ break;
+ case NAS_Port:
+ port_id = attr->val.integer;
+ break;
+ case Framed_IP_Address:
+ ipaddr = attr->val.ipaddr;
+ break;
+ case Calling_Station_Id:
+ csid = attr->val.string;
+ break;
+ }
+ }
+
+ if (!sessionid && !username && port_id == -1 && ipaddr == 0 && !csid)
+ return NULL;
+
+ if (username && !sessionid && port_id == -1 && ipaddr == 0)
+ return NULL;
+
+ return rad_find_session(sessionid, username, port_id, ipaddr, csid);
+}
+
+int rad_check_nas_pack(struct rad_packet_t *pack)
+{
+ struct rad_attr_t *attr;
+ const char *ident = NULL;
+ in_addr_t ipaddr = 0;
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ if (!strcmp(attr->attr->name, "NAS-Identifier"))
+ ident = attr->val.string;
+ else if (!strcmp(attr->attr->name, "NAS-IP-Address"))
+ ipaddr = attr->val.ipaddr;
+ }
+
+ if (conf_require_nas_ident && !ident && !ipaddr)
+ return -1;
+
+ if (conf_nas_identifier && ident && strcmp(conf_nas_identifier, ident))
+ return -1;
+
+ if (conf_nas_ip_address && ipaddr && conf_nas_ip_address != ipaddr)
+ return -1;
+
+ return 0;
+}
+
+static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client)
+{
+ cli_send(client, "radius:\r\n");
+ cli_sendv(client, " auth sent: %lu\r\n", stat_auth_sent);
+ cli_sendv(client, " auth lost: %lu\r\n", stat_auth_lost);
+ cli_sendv(client, " acct sent: %lu\r\n", stat_acct_sent);
+ cli_sendv(client, " acct lost: %lu\r\n", stat_acct_lost);
+ cli_sendv(client, " interim sent: %lu\r\n", stat_interim_sent);
+ cli_sendv(client, " interim lost: %lu\r\n", stat_interim_lost);
+ return CLI_CMD_OK;
+}
+
+void __export rad_register_plugin(struct ppp_t *ppp, struct rad_plugin_t *plugin)
+{
+ struct radius_pd_t *rpd = find_pd(ppp);
+
+ if (!rpd)
+ return;
+
+ list_add_tail(&plugin->entry, &rpd->plugin_list);
+}
+
+static struct ipdb_t ipdb = {
+ .get = get_ip,
+};
+
+static struct pwdb_t pwdb = {
+ .check = check,
+};
+
+static int parse_server(const char *opt, in_addr_t *addr, int *port, char **secret)
+{
+ char *str = _strdup(opt);
+ char *p1, *p2;
+
+ p1 = strstr(str, ":");
+ p2 = strstr(str, ",");
+
+ if (p1)
+ *p1 = 0;
+ if (p2)
+ *p2 = 0;
+ else
+ return -1;
+
+ *addr = inet_addr(str);
+
+ if (p1) {
+ *port = atoi(p1 + 1);
+ if (*port <=0 )
+ return -1;
+ }
+
+ p1 = _strdup(p2 + 1);
+ p2 = *secret;
+ *secret = p1;
+ if (p2)
+ _free(p2);
+
+ _free(str);
+
+ return 0;
+}
+
+static int load_config(void)
+{
+ char *opt;
+
+ opt = conf_get_opt("radius", "max-try");
+ if (opt && atoi(opt) > 0)
+ conf_max_try = atoi(opt);
+
+ opt = conf_get_opt("radius", "timeout");
+ if (opt && atoi(opt) > 0)
+ conf_timeout = atoi(opt);
+
+ opt = conf_get_opt("radius", "acct-timeout");
+ if (opt && atoi(opt) > 0)
+ conf_acct_timeout = atoi(opt);
+
+ opt = conf_get_opt("radius", "verbose");
+ if (opt && atoi(opt) > 0)
+ conf_verbose = 1;
+
+ opt = conf_get_opt("radius", "interim-verbose");
+ if (opt && atoi(opt) > 0)
+ conf_interim_verbose = 1;
+
+ opt = conf_get_opt("radius", "nas-ip-address");
+ if (opt)
+ conf_nas_ip_address = inet_addr(opt);
+
+ if (conf_nas_identifier)
+ _free(conf_nas_identifier);
+ opt = conf_get_opt("radius", "nas-identifier");
+ if (opt)
+ conf_nas_identifier = _strdup(opt);
+ else
+ conf_nas_identifier = NULL;
+
+ opt = conf_get_opt("radius", "gw-ip-address");
+ if (opt)
+ conf_gw_ip_address = inet_addr(opt);
+
+ opt = conf_get_opt("radius", "bind");
+ if (opt)
+ conf_bind = inet_addr(opt);
+ else if (conf_nas_ip_address)
+ conf_bind = conf_nas_ip_address;
+
+ opt = conf_get_opt("radius", "auth-server");
+ if (!opt)
+ opt = conf_get_opt("radius", "auth_server");
+ if (!opt) {
+ log_emerg("radius: auth-server not specified\n");
+ return -1;
+ } else if (parse_server(opt, &conf_auth_server, &conf_auth_server_port, &conf_auth_secret)) {
+ log_emerg("radius: failed to parse auth_server\n");
+ return -1;
+ }
+
+ opt = conf_get_opt("radius", "acct-server");
+ if (!opt)
+ opt = conf_get_opt("radius", "acct_server");
+ if (!opt)
+ log_emerg("radius: acct-server not specified\n");
+ if (opt && parse_server(opt, &conf_acct_server, &conf_acct_server_port, &conf_acct_secret)) {
+ log_emerg("radius: failed to parse acct_server\n");
+ return -1;
+ }
+
+ opt = conf_get_opt("radius", "dae-server");
+ if (opt && parse_server(opt, &conf_dm_coa_server, &conf_dm_coa_port, &conf_dm_coa_secret)) {
+ log_emerg("radius: failed to parse dae-server\n");
+ return -1;
+ }
+
+ opt = conf_get_opt("radius", "sid_in_auth");
+ if (opt && atoi(opt) > 0)
+ conf_sid_in_auth = 1;
+
+ opt = conf_get_opt("radius", "require-nas-identification");
+ if (opt && atoi(opt) > 0)
+ conf_require_nas_ident = 1;
+
+ opt = conf_get_opt("radius", "acct-interim-interval");
+ if (opt && atoi(opt) > 0)
+ conf_acct_interim_interval = atoi(opt);
+
+ return 0;
+}
+
+static void __init radius_init(void)
+{
+ char *opt;
+ char *dict = DICTIONARY;
+
+ rpd_pool = mempool_create(sizeof(struct radius_pd_t));
+
+ if (load_config())
+ _exit(EXIT_FAILURE);
+
+ opt = conf_get_opt("radius", "dictionary");
+ if (opt)
+ dict = opt;
+
+ if (rad_dict_load(dict))
+ _exit(EXIT_FAILURE);
+
+ pwdb_register(&pwdb);
+ ipdb_register(&ipdb);
+
+ triton_event_register_handler(EV_PPP_STARTING, (triton_event_func)ppp_starting);
+ triton_event_register_handler(EV_PPP_ACCT_START, (triton_event_func)ppp_acct_start);
+ triton_event_register_handler(EV_PPP_FINISHING, (triton_event_func)ppp_finishing);
+ triton_event_register_handler(EV_PPP_FINISHED, (triton_event_func)ppp_finished);
+ triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
+
+ cli_register_simple_cmd2(show_stat_exec, NULL, 2, "show", "stat");
+}
diff --git a/accel-pppd/radius/radius.h b/accel-pppd/radius/radius.h
new file mode 100644
index 00000000..ad229d22
--- /dev/null
+++ b/accel-pppd/radius/radius.h
@@ -0,0 +1,117 @@
+#ifndef __RADIUS_H
+#define __RADIUS_H
+
+#include <stdint.h>
+
+#define REQ_LENGTH_MAX 4096
+
+#define ATTR_TYPE_INTEGER 0
+#define ATTR_TYPE_STRING 1
+#define ATTR_TYPE_OCTETS 2
+#define ATTR_TYPE_DATE 3
+#define ATTR_TYPE_IPADDR 4
+
+#define CODE_ACCESS_REQUEST 1
+#define CODE_ACCESS_ACCEPT 2
+#define CODE_ACCESS_REJECT 3
+#define CODE_ACCESS_CHALLENGE 11
+
+#define CODE_ACCOUNTING_REQUEST 4
+#define CODE_ACCOUNTING_RESPONSE 5
+
+#define CODE_DISCONNECT_REQUEST 40
+#define CODE_DISCONNECT_ACK 41
+#define CODE_DISCONNECT_NAK 42
+#define CODE_COA_REQUEST 43
+#define CODE_COA_ACK 44
+#define CODE_COA_NAK 45
+
+typedef union
+{
+ int integer;
+ char *string;
+ uint8_t *octets;
+ time_t date;
+ in_addr_t ipaddr;
+} rad_value_t;
+
+struct rad_dict_t
+{
+ struct list_head items;
+ struct list_head vendors;
+};
+
+struct rad_dict_vendor_t
+{
+ struct list_head entry;
+ int id;
+ const char *name;
+ struct list_head items;
+};
+
+struct rad_dict_value_t
+{
+ struct list_head entry;
+ rad_value_t val;
+ const char *name;
+};
+
+struct rad_dict_attr_t
+{
+ struct list_head entry;
+ const char *name;
+ int id;
+ int type;
+ struct list_head values;
+};
+
+struct rad_attr_t
+{
+ struct list_head entry;
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_vendor_t *vendor;
+ //struct rad_dict_value_t *val;
+ rad_value_t val;
+ int len;
+};
+
+struct rad_packet_t
+{
+ int code;
+ uint8_t id;
+ int len;
+ struct list_head attrs;
+ void *buf;
+};
+
+struct rad_plugin_t
+{
+ struct list_head entry;
+ int (*send_access_request)(struct rad_plugin_t *, struct rad_packet_t *pack);
+ int (*send_accounting_request)(struct rad_plugin_t *, struct rad_packet_t *pack);
+};
+
+struct ppp_t;
+
+void rad_register_plugin(struct ppp_t *, struct rad_plugin_t *);
+
+struct rad_dict_attr_t *rad_dict_find_attr(const char *name);
+struct rad_dict_attr_t *rad_dict_find_attr_id(struct rad_dict_vendor_t *vendor, int type);
+struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *, const char *name);
+struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *, rad_value_t val);
+struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name);
+struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id);
+struct rad_dict_attr_t *rad_dict_find_vendor_attr(struct rad_dict_vendor_t *vendor, const char *name);
+
+struct rad_attr_t *rad_packet_find_attr(struct rad_packet_t *pack, const char *vendor, const char *name);
+int rad_packet_add_int(struct rad_packet_t *pack, const char *vendor, const char *name, int val);
+int rad_packet_add_val(struct rad_packet_t *pack, const char *vendor, const char *name, const char *val);
+int rad_packet_add_str(struct rad_packet_t *pack, const char *vendor, const char *name, const char *val);
+int rad_packet_add_octets(struct rad_packet_t *pack, const char *vendor, const char *name, const uint8_t *val, int len);
+int rad_packet_change_int(struct rad_packet_t *pack, const char *vendor, const char *name, int val);
+int rad_packet_change_val(struct rad_packet_t *pack, const char *vendor, const char *name, const char *val);
+int rad_packet_change_octets(struct rad_packet_t *pack, const char *vendor, const char *name, const uint8_t *val, int len);
+int rad_packet_add_ipaddr(struct rad_packet_t *pack, const char *vendor, const char *name, in_addr_t ipaddr);
+
+#endif
+
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
new file mode 100644
index 00000000..71c1a637
--- /dev/null
+++ b/accel-pppd/radius/radius_p.h
@@ -0,0 +1,122 @@
+#ifndef __RADIUS_P_H
+#define __RADIUS_P_H
+
+#include <netinet/in.h>
+#include <pthread.h>
+
+#include "triton.h"
+#include "radius.h"
+#include "ppp.h"
+#include "ipdb.h"
+
+struct radius_pd_t
+{
+ struct list_head entry;
+ struct ppp_pd_t pd;
+ struct ppp_t *ppp;
+ pthread_mutex_t lock;
+
+ struct rad_req_t *auth_req;
+ struct rad_req_t *acct_req;
+ struct triton_timer_t acct_interim_timer;
+ uint32_t acct_input_octets;
+ uint32_t acct_output_octets;
+ uint32_t acct_input_gigawords;
+ uint32_t acct_output_gigawords;
+
+ struct triton_timer_t session_timeout;
+
+ struct rad_packet_t *dm_coa_req;
+ struct sockaddr_in dm_coa_addr;
+
+ struct ipdb_item_t ipaddr;
+ int acct_interim_interval;
+ time_t acct_timestamp;
+
+ uint8_t *attr_class;
+ int attr_class_len;
+ uint8_t *attr_state;
+ int attr_state_len;
+ int termination_action;
+
+ struct list_head plugin_list;
+};
+
+struct rad_req_t
+{
+ struct triton_context_t ctx;
+ struct triton_md_handler_t hnd;
+ struct triton_timer_t timeout;
+ uint8_t RA[16];
+ struct rad_packet_t *pack;
+ struct rad_packet_t *reply;
+ in_addr_t server_addr;
+ int server_port;
+
+ struct radius_pd_t *rpd;
+};
+
+extern int conf_max_try;
+extern int conf_timeout;
+extern int conf_acct_timeout;
+extern int conf_verbose;
+extern int conf_interim_verbose;
+extern char *conf_nas_identifier;
+extern in_addr_t conf_nas_ip_address;
+extern in_addr_t conf_bind;
+extern in_addr_t conf_gw_ip_address;
+extern in_addr_t conf_auth_server;
+extern char *conf_auth_secret;
+extern int conf_auth_server_port;
+extern in_addr_t conf_acct_server;
+extern char *conf_acct_secret;
+extern int conf_acct_server_port;
+extern char *conf_dm_coa_secret;
+extern int conf_sid_in_auth;
+extern int conf_require_nas_ident;
+extern in_addr_t conf_dm_coa_server;
+extern int conf_dm_coa_port;
+extern int conf_acct_interim_interval;
+
+extern unsigned long stat_auth_sent;
+extern unsigned long stat_auth_lost;
+extern unsigned long stat_acct_sent;
+extern unsigned long stat_acct_lost;
+extern unsigned long stat_interim_sent;
+extern unsigned long stat_interim_lost;
+
+int rad_check_nas_pack(struct rad_packet_t *pack);
+struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr, const char *csid);
+struct radius_pd_t *rad_find_session_pack(struct rad_packet_t *pack);
+
+int rad_dict_load(const char *fname);
+void rad_dict_free(struct rad_dict_t *dict);
+
+struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username);
+int rad_req_acct_fill(struct rad_req_t *);
+void rad_req_free(struct rad_req_t *);
+int rad_req_send(struct rad_req_t *, int verbose);
+int rad_req_wait(struct rad_req_t *, int);
+
+struct radius_pd_t *find_pd(struct ppp_t *ppp);
+int rad_proc_attrs(struct rad_req_t *req);
+
+int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args);
+int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args);
+int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args);
+int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args);
+
+int rad_acct_start(struct radius_pd_t *rpd);
+void rad_acct_stop(struct radius_pd_t *rpd);
+
+struct rad_packet_t *rad_packet_alloc(int code);
+int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA);
+int rad_packet_recv(int fd, struct rad_packet_t **, struct sockaddr_in *addr);
+void rad_packet_free(struct rad_packet_t *);
+void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...));
+int rad_packet_send(struct rad_packet_t *pck, int fd, struct sockaddr_in *addr);
+
+void dm_coa_cancel(struct radius_pd_t *pd);
+
+#endif
+
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c
new file mode 100644
index 00000000..a384f236
--- /dev/null
+++ b/accel-pppd/radius/req.c
@@ -0,0 +1,277 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sched.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "log.h"
+#include "radius_p.h"
+
+#include "memdebug.h"
+
+static int urandom_fd;
+
+static int rad_req_read(struct triton_md_handler_t *h);
+static void rad_req_timeout(struct triton_timer_t *t);
+
+struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username)
+{
+ struct rad_plugin_t *plugin;
+ struct rad_req_t *req = _malloc(sizeof(*req));
+
+ if (!req)
+ return NULL;
+
+ memset(req, 0, sizeof(*req));
+ req->rpd = rpd;
+ req->hnd.fd = -1;
+ req->ctx.before_switch = log_switch;
+
+ req->server_addr = conf_auth_server;
+ req->server_port = conf_auth_server_port;
+
+ while (1) {
+ if (read(urandom_fd, req->RA, 16) != 16) {
+ if (errno == EINTR)
+ continue;
+ log_ppp_error("radius:req:read urandom: %s\n", strerror(errno));
+ goto out_err;
+ }
+ break;
+ }
+
+ req->pack = rad_packet_alloc(code);
+ if (!req->pack)
+ goto out_err;
+
+ if (rad_packet_add_str(req->pack, NULL, "User-Name", username))
+ goto out_err;
+ if (conf_nas_identifier)
+ if (rad_packet_add_str(req->pack, NULL, "NAS-Identifier", conf_nas_identifier))
+ goto out_err;
+ if (conf_nas_ip_address)
+ if (rad_packet_add_ipaddr(req->pack, NULL, "NAS-IP-Address", conf_nas_ip_address))
+ goto out_err;
+ if (rad_packet_add_int(req->pack, NULL, "NAS-Port", rpd->ppp->unit_idx))
+ goto out_err;
+ if (rad_packet_add_val(req->pack, NULL, "NAS-Port-Type", "Virtual"))
+ goto out_err;
+ if (rad_packet_add_val(req->pack, NULL, "Service-Type", "Framed-User"))
+ goto out_err;
+ if (rad_packet_add_val(req->pack, NULL, "Framed-Protocol", "PPP"))
+ goto out_err;
+ if (rpd->ppp->ctrl->calling_station_id)
+ if (rad_packet_add_str(req->pack, NULL, "Calling-Station-Id", rpd->ppp->ctrl->calling_station_id))
+ goto out_err;
+ if (rpd->ppp->ctrl->called_station_id)
+ if (rad_packet_add_str(req->pack, NULL, "Called-Station-Id", rpd->ppp->ctrl->called_station_id))
+ goto out_err;
+ if (rpd->attr_class)
+ if (rad_packet_add_octets(req->pack, NULL, "Class", rpd->attr_class, rpd->attr_class_len))
+ goto out_err;
+
+ list_for_each_entry(plugin, &req->rpd->plugin_list, entry) {
+ switch (code) {
+ case CODE_ACCESS_REQUEST:
+ if (plugin->send_access_request && plugin->send_access_request(plugin, req->pack))
+ goto out_err;
+ break;
+ case CODE_ACCOUNTING_REQUEST:
+ if (plugin->send_accounting_request && plugin->send_accounting_request(plugin, req->pack))
+ goto out_err;
+ break;
+ }
+ }
+
+ return req;
+
+out_err:
+ rad_req_free(req);
+ return NULL;
+}
+
+int rad_req_acct_fill(struct rad_req_t *req)
+{
+ req->server_addr = conf_acct_server;
+ req->server_port = conf_acct_server_port;
+
+ memset(req->RA, 0, sizeof(req->RA));
+
+ if (rad_packet_add_val(req->pack, NULL, "Acct-Status-Type", "Start"))
+ return -1;
+ if (rad_packet_add_val(req->pack, NULL, "Acct-Authentic", "RADIUS"))
+ return -1;
+ if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", req->rpd->ppp->sessionid))
+ return -1;
+ if (rad_packet_add_int(req->pack, NULL, "Acct-Session-Time", 0))
+ return -1;
+ if (rad_packet_add_int(req->pack, NULL, "Acct-Input-Octets", 0))
+ return -1;
+ if (rad_packet_add_int(req->pack, NULL, "Acct-Output-Octets", 0))
+ return -1;
+ if (rad_packet_add_int(req->pack, NULL, "Acct-Input-Packets", 0))
+ return -1;
+ if (rad_packet_add_int(req->pack, NULL, "Acct-Output-Packets", 0))
+ return -1;
+ if (rad_packet_add_int(req->pack, NULL, "Acct-Input-Gigawords", 0))
+ return -1;
+ if (rad_packet_add_int(req->pack, NULL, "Acct-Output-Gigawords", 0))
+ return -1;
+ if (rad_packet_add_int(req->pack, NULL, "Acct-Delay-Time", 0))
+ return -1;
+ if (rad_packet_add_ipaddr(req->pack, NULL, "Framed-IP-Address", req->rpd->ppp->peer_ipaddr))
+ return -1;
+
+ return 0;
+}
+
+void rad_req_free(struct rad_req_t *req)
+{
+ if (req->hnd.fd >= 0 )
+ close(req->hnd.fd);
+ if (req->pack)
+ rad_packet_free(req->pack);
+ if (req->reply)
+ rad_packet_free(req->reply);
+ _free(req);
+}
+
+static int make_socket(struct rad_req_t *req)
+{
+ struct sockaddr_in addr;
+
+ req->hnd.fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (req->hnd.fd < 0) {
+ log_ppp_error("radius:socket: %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+
+ if (conf_bind) {
+ addr.sin_addr.s_addr = conf_bind;
+ if (bind(req->hnd.fd, (struct sockaddr *) &addr, sizeof(addr))) {
+ log_ppp_error("radius:bind: %s\n", strerror(errno));
+ goto out_err;
+ }
+ }
+
+ addr.sin_addr.s_addr = req->server_addr;
+ addr.sin_port = htons(req->server_port);
+
+ if (connect(req->hnd.fd, (struct sockaddr *) &addr, sizeof(addr))) {
+ log_ppp_error("radius:connect: %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ if (fcntl(req->hnd.fd, F_SETFL, O_NONBLOCK)) {
+ log_ppp_error("radius: failed to set nonblocking mode: %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ close(req->hnd.fd);
+ req->hnd.fd = -1;
+ return -1;
+}
+
+int rad_req_send(struct rad_req_t *req, int verbose)
+{
+ if (req->hnd.fd == -1 && make_socket(req))
+ return -1;
+
+ if (!req->pack->buf && rad_packet_build(req->pack, req->RA))
+ goto out_err;
+
+ if (verbose) {
+ log_ppp_info1("send ");
+ rad_packet_print(req->pack, log_ppp_info1);
+ }
+
+ rad_packet_send(req->pack, req->hnd.fd, NULL);
+
+ return 0;
+
+out_err:
+ close(req->hnd.fd);
+ req->hnd.fd = -1;
+ return -1;
+}
+
+static void req_wakeup(struct rad_req_t *req)
+{
+ struct triton_context_t *ctx = req->rpd->ppp->ctrl->ctx;
+ triton_timer_del(&req->timeout);
+ triton_md_unregister_handler(&req->hnd);
+ triton_context_unregister(&req->ctx);
+ triton_context_wakeup(ctx);
+}
+static int rad_req_read(struct triton_md_handler_t *h)
+{
+ struct rad_req_t *req = container_of(h, typeof(*req), hnd);
+ struct rad_packet_t *pack;
+ int r;
+
+ while (1) {
+ r = rad_packet_recv(h->fd, &pack, NULL);
+
+ if (pack) {
+ if (req->reply)
+ rad_packet_free(req->reply);
+ req->reply = pack;
+ }
+
+ if (r)
+ break;
+ }
+
+ req_wakeup(req);
+
+ return 1;
+}
+static void rad_req_timeout(struct triton_timer_t *t)
+{
+ struct rad_req_t *req = container_of(t, typeof(*req), timeout);
+
+ req_wakeup(req);
+}
+
+int rad_req_wait(struct rad_req_t *req, int timeout)
+{
+ req->hnd.read = rad_req_read;
+ req->timeout.expire = rad_req_timeout;
+
+ triton_context_register(&req->ctx, req->rpd->ppp);
+ triton_md_register_handler(&req->ctx, &req->hnd);
+ triton_md_enable_handler(&req->hnd, MD_MODE_READ);
+
+ req->timeout.period = timeout * 1000;
+ triton_timer_add(&req->ctx, &req->timeout, 0);
+
+ triton_context_wakeup(&req->ctx);
+
+ triton_context_schedule();
+
+ if (conf_verbose && req->reply) {
+ log_ppp_info1("recv ");
+ rad_packet_print(req->reply, log_ppp_info1);
+ }
+ return 0;
+}
+
+void __init req_init(void)
+{
+ urandom_fd = open("/dev/urandom", O_RDONLY);
+ if (!urandom_fd) {
+ log_emerg("radius:req: open /dev/urandom: %s\n", strerror(errno));
+ _exit(EXIT_FAILURE);
+ }
+}