diff -crN ppp-2.3.5.orig/pppd/Makefile.linux ppp-2.3.5/pppd/Makefile.linux
*** ppp-2.3.5.orig/pppd/Makefile.linux Tue Mar 30 13:10:49 1999
--- ppp-2.3.5/pppd/Makefile.linux Tue Mar 30 16:27:09 1999
***************
*** 24,34 ****
include .depend
endif
! # CC = gcc
#
COPTS = -O2 -pipe -Wall -g
VER = 2.3.5
LIBS =
ifneq ($(wildcard /usr/lib/libcrypt.*),)
LIBS += -lcrypt
--- 24,35 ----
include .depend
endif
! CC = gcc
#
COPTS = -O2 -pipe -Wall -g
VER = 2.3.5
LIBS =
+ # -lbsd
ifneq ($(wildcard /usr/lib/libcrypt.*),)
LIBS += -lcrypt
***************
*** 42,47 ****
--- 43,53 ----
HAVE_CRYPT_H=y
endif
+ #undef if you want RADIUS support.
+ #You also need the radclient package from
+ #
+ #
+ RADIUS = 1
HAS_SHADOW=y
#USE_PAM=y
***************
*** 66,71 ****
--- 72,88 ----
ifdef MSLANMAN
CFLAGS += -DMSLANMAN=1
endif
+ endif
+
+ ifdef RADIUS
+ CFLAGS += -DRADIUS -I/usr/include
+ CFLAGS += -D_PATH_ETC_RADIUSCLIENT_CONF=\"/etc/radiusclient/radiusclient.conf\"
+ LIBS += -L/usr/lib -lradiusclient
+ PPPDOBJS += radius.o
+ endif
+
+ ifdef OPTIONS_TTY_FIRST
+ CFLAGS += _DOPTIONS_TTY_FIRST
endif
ifdef HAS_SHADOW
diff -crN ppp-2.3.5.orig/pppd/auth.c ppp-2.3.5/pppd/auth.c
*** ppp-2.3.5.orig/pppd/auth.c Thu Mar 26 05:46:00 1998
--- ppp-2.3.5/pppd/auth.c Tue Mar 30 15:26:41 1999
***************
*** 32,40 ****
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
! #ifndef lint
static char rcsid[] = "$Id: auth.c,v 1.37 1998/03/26 04:46:03 paulus Exp $";
! #endif
#include
#include
--- 32,40 ----
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
! /*#ifndef lint
static char rcsid[] = "$Id: auth.c,v 1.37 1998/03/26 04:46:03 paulus Exp $";
! #endif*/
#include
#include
***************
*** 63,70 ****
#ifdef HAS_SHADOW
#include
#ifndef PW_PPP
- #define PW_PPP PW_LOGIN
#endif
#endif
#include "pppd.h"
--- 63,81 ----
#ifdef HAS_SHADOW
#include
#ifndef PW_PPP
#endif
+ #define PW_PPP 1
+ #ifndef PW_LOGIN
+ #define PW_LOGIN 1
+ #endif
+ #endif
+
+ #ifdef RADIUS
+ #include
+ int radius_upap_auth __P((char *, char *, char **, int *));
+ void radius_acct_stop __P((void));
+ extern int radius_in;
+ int radius_pap_auth (char *, char *, char **, int *);
#endif
#include "pppd.h"
***************
*** 165,170 ****
--- 176,185 ----
return;
if (logged_in)
plogout();
+ #ifdef RADIUS
+ if (radius_in)
+ radius_acct_stop();
+ #endif
phase = PHASE_DEAD;
syslog(LOG_NOTICE, "Connection terminated.");
}
***************
*** 529,536 ****
--- 544,560 ----
* Check whether we have appropriate secrets to use
* to authenticate the peer.
*/
+ #ifdef RADIUS
+ can_auth = wo->neg_upap && (uselogin || have_pap_secret() || useradius);
+ #else
can_auth = wo->neg_upap && (uselogin || have_pap_secret());
+ #endif
+
+ #ifdef RADIUS
+ if (!can_auth && !useradius && wo->neg_chap) {
+ #else
if (!can_auth && wo->neg_chap) {
+ #endif
remote = ipwo->accept_remote? 0: ipwo->hisaddr;
can_auth = have_chap_secret(remote_name, our_name, remote);
}
***************
*** 639,645 ****
--- 663,673 ----
addrs = NULL;
ret = UPAP_AUTHACK;
f = fopen(filename, "r");
+ #ifdef RADIUS
+ if (f == NULL && !useradius) {
+ #else
if (f == NULL) {
+ #endif
syslog(LOG_ERR, "Can't open PAP password file %s: %m", filename);
ret = UPAP_AUTHNAK;
***************
*** 656,667 ****
fclose(f);
}
if (uselogin && ret == UPAP_AUTHACK) {
ret = plogin(user, passwd, msg, msglen);
if (ret == UPAP_AUTHNAK) {
syslog(LOG_WARNING, "PAP login failure for %s", user);
}
! }
if (ret == UPAP_AUTHNAK) {
if (*msg == (char *) 0)
--- 684,733 ----
fclose(f);
}
+
if (uselogin && ret == UPAP_AUTHACK) {
+ #ifndef RADIUS
ret = plogin(user, passwd, msg, msglen);
if (ret == UPAP_AUTHNAK) {
syslog(LOG_WARNING, "PAP login failure for %s", user);
}
! #else
! /* Mark 1 */
! int auth_order = rc_conf_int("auth_order");
!
! if (ret == UPAP_AUTHACK)
! {
! if (uselogin && useradius)
! {
! if (auth_order & AUTH_LOCAL_FST)
! {
! ret = plogin(user, passwd, msg, msglen);
! if ((auth_order & AUTH_RADIUS_SND) && (ret == UPAP_AUTHNAK))
! ret = radius_pap_auth( user, passwd, msg, msglen );
! }
! else if (auth_order & AUTH_RADIUS_FST)
! {
! ret = radius_pap_auth( user, passwd, msg, msglen );
! if ((auth_order & AUTH_LOCAL_SND) && (ret == UPAP_AUTHNAK))
! ret = plogin(user, passwd, msg, msglen );
! }
! }
! else if (uselogin)
! {
! ret = plogin(user, passwd, msg, msglen);
! }
! else if (useradius)
! {
! ret = radius_pap_auth( user, passwd, msg, msglen);
! }
! }
!
! if (ret == UPAP_AUTHNAK)
! {
! syslog(LOG_WARNING, "PAP login failure for %s", user);
! }
! }
! #endif
if (ret == UPAP_AUTHNAK) {
if (*msg == (char *) 0)
diff -crN ppp-2.3.5.orig/pppd/chap.c ppp-2.3.5/pppd/chap.c
*** ppp-2.3.5.orig/pppd/chap.c Thu Nov 27 07:07:48 1997
--- ppp-2.3.5/pppd/chap.c Tue Mar 30 15:35:51 1999
***************
*** 33,41 ****
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
! #ifndef lint
static char rcsid[] = "$Id: chap.c,v 1.15 1997/11/27 06:07:48 paulus Exp $";
! #endif
/*
* TODO:
--- 33,41 ----
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
! /*#ifndef lint
static char rcsid[] = "$Id: chap.c,v 1.15 1997/11/27 06:07:48 paulus Exp $";
! #endif*/
/*
* TODO:
***************
*** 54,59 ****
--- 54,71 ----
#include "chap_ms.h"
#endif
+
+ #ifdef RADIUS
+ #ifndef RADIUSCLIENT_H
+ #include
+ #endif
+ int radius_upap_auth __P((char *, char *, char **, int *));
+ void radius_acct_stop __P((void));
+ extern int radius_in;
+ u_char *remmd;
+ int radius_chap_auth (char *, u_char *, chap_state *);
+ #endif
+
/*
* Protocol entry points.
*/
***************
*** 100,105 ****
--- 112,118 ----
extern double drand48 __P((void));
extern void srand48 __P((long));
+
/*
* ChapInit - Initialize a CHAP unit.
*/
***************
*** 116,121 ****
--- 129,136 ----
cstate->timeouttime = CHAP_DEFTIMEOUT;
cstate->max_transmits = CHAP_DEFTRANSMITS;
/* random number generator is initialized in magic_init */
+
+
}
***************
*** 384,389 ****
--- 399,405 ----
int id;
int len;
{
+ int code;
int rchallenge_len;
u_char *rchallenge;
int secret_len;
***************
*** 436,442 ****
--- 452,464 ----
secret_len = 0; /* assume null secret if can't find one */
syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s",
rhostname);
+ #ifdef RADIUS
}
+ if (radius_chap_auth(rhostname, remmd, cstate) == 0) {
+ code = CHAP_SUCCESS;
+ #else
+ } else {
+ #endif
/* cancel response send timeout if necessary */
if (cstate->clientstate == CHAPCS_RESPONSE)
***************
*** 468,473 ****
--- 490,498 ----
CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
return;
}
+ }
+
+ syslog(LOG_WARNING, "@@mla@@ Before ChapSendStatus");
BZERO(secret, sizeof(secret));
ChapSendResponse(cstate);
diff -crN ppp-2.3.5.orig/pppd/chap.h ppp-2.3.5/pppd/chap.h
*** ppp-2.3.5.orig/pppd/chap.h Wed Mar 12 05:09:10 1997
--- ppp-2.3.5/pppd/chap.h Tue Mar 30 14:15:57 1999
***************
*** 33,38 ****
--- 33,39 ----
* $Id: chap.h,v 1.7 1996/10/08 06:43:27 paulus Exp $
*/
+
#ifndef __CHAP_INCLUDE__
/* Code + ID + length */
diff -crN ppp-2.3.5.orig/pppd/main.c ppp-2.3.5/pppd/main.c
*** ppp-2.3.5.orig/pppd/main.c Tue May 5 07:24:17 1998
--- ppp-2.3.5/pppd/main.c Tue Mar 30 13:47:38 1999
***************
*** 211,224 ****
--- 211,239 ----
progname = *argv;
+ #ifdef OPTIONS_TTY_FIRST
+ if (!options_from_file(_PATH_SYSOPTIONS, REQ_SYSOPTIONS, 0) ||
+ !options_for_tty() ||
+ !options_from_user() ||
+ !parse_args(argc-1, argv+1))
+ #else
if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)
|| !options_from_user())
exit(1);
scan_args(argc-1, argv+1); /* look for tty name on command line */
if (!options_for_tty()
|| !parse_args(argc-1, argv+1))
+ #endif
exit(1);
+ #ifdef RADIUS
+ if (radius_init()< 0)
+ {
+ fprintf(stderr, "Cannot initialize RADIUS\n");
+ exit(1);
+ }
+ #endif
+
/*
* Check that we are running as root.
*/
***************
*** 318,324 ****
--- 333,341 ----
* Install a handler for other signals which would otherwise
* cause pppd to exit without cleaning up.
*/
+ #ifndef RADIUS
SIGNAL(SIGABRT, bad_signal);
+ #endif
SIGNAL(SIGALRM, bad_signal);
SIGNAL(SIGFPE, bad_signal);
SIGNAL(SIGILL, bad_signal);
diff -crN ppp-2.3.5.orig/pppd/options.c ppp-2.3.5/pppd/options.c
*** ppp-2.3.5.orig/pppd/options.c Thu Mar 26 05:46:07 1998
--- ppp-2.3.5/pppd/options.c Tue Mar 30 13:42:03 1999
***************
*** 96,101 ****
--- 96,104 ----
int auth_required = 0; /* Peer is required to authenticate */
int defaultroute = 0; /* assign default route through interface */
int proxyarp = 0; /* Set up proxy ARP entry for peer */
+ #ifdef RADIUS
+ int useradius = 0; /* Use RADIUS server checking PAP */
+ #endif
int persist = 0; /* Reopen link after it goes down */
int uselogin = 0; /* Use /etc/passwd for checking PAP */
int lcp_echo_interval = 0; /* Interval between LCP echo-requests */
***************
*** 191,196 ****
--- 194,202 ----
static int setpersist __P((char **));
static int setnopersist __P((char **));
static int setdologin __P((char **));
+ #ifdef RADIUS
+ static int setdoradius __P((void));
+ #endif
static int setusehostname __P((char **));
static int setnoipdflt __P((char **));
static int setlcptimeout __P((char **));
***************
*** 344,349 ****
--- 350,358 ----
{"nopersist", 0, setnopersist}, /* Turn off persist option */
{"demand", 0, setdemand}, /* Dial on demand */
{"login", 0, setdologin}, /* Use system password database for UPAP */
+ #ifdef RADIUS
+ {"radius", 0, setdoradius}, /* Use RADIUS server for UPAP */
+ #endif
{"noipdefault", 0, setnoipdflt}, /* Don't use name for default IP adrs */
{"lcp-echo-failure", 1, setlcpechofails}, /* consecutive echo failures */
{"lcp-echo-interval", 1, setlcpechointv}, /* time for lcp echo events */
***************
*** 2042,2047 ****
--- 2051,2065 ----
uselogin = 1;
return 1;
}
+
+
+ #ifdef RADIUS
+ setdoradius()
+ {
+ useradius = 1;
+ return 1;
+ }
+ #endif
/*
* Functions to set the echo interval for modem-less monitors
diff -crN ppp-2.3.5.orig/pppd/pppd.h ppp-2.3.5/pppd/pppd.h
*** ppp-2.3.5.orig/pppd/pppd.h Tue Mar 30 13:10:49 1999
--- ppp-2.3.5/pppd/pppd.h Tue Mar 30 13:38:10 1999
***************
*** 55,60 ****
--- 55,64 ----
* Global variables.
*/
+ #ifdef RADIUS
+ extern int useradius; /* Use RADIUS server for checking PAP */
+ #endif
+
extern int hungup; /* Physical layer has disconnected */
extern int ifunit; /* Interface unit number */
extern char ifname[]; /* Interface name */
diff -crN ppp-2.3.5.orig/pppd/radius.c ppp-2.3.5/pppd/radius.c
*** ppp-2.3.5.orig/pppd/radius.c Thu Jan 1 01:00:00 1970
--- ppp-2.3.5/pppd/radius.c Tue Mar 30 15:18:42 1999
***************
*** 0 ****
--- 1,593 ----
+ /*
+ * $Id: radius.c,v 1.1 1997/12/15 00:47:02 mla Exp $
+ *
+ * Copyright (C) 1996, Matjaz Godec
+ * Copyright (C) 1996, Lars Fenneberg
+ * Partly Copyright (C) 1997, Michael Lausch
+ */
+
+ #include
+ #include
+ #include
+ #include
+
+ #ifdef RADIUS
+ #ifndef RADIUSCLIENT_H
+ #include
+ #endif
+ #endif
+
+ #include "pppd.h"
+ #include "fsm.h"
+ #include "lcp.h"
+ #include "upap.h"
+ #include "chap.h"
+ #include "ipcp.h"
+ #include "ccp.h"
+ #include "pathnames.h"
+
+ extern int idle_time_limit;
+
+ char *ip_ntoa __P((u_int32_t));
+ int bad_ip_adrs __P((u_int32_t));
+
+ int radius_in = FALSE;
+ int session_time_limit = 0;
+
+ static char username[256];
+ static char session_id[32];
+ static UINT4 client_port;
+ static time_t start_time;
+ static int called_radius_init = 0;
+
+ static void radius_acct_start __P((void));
+
+ int radius_init()
+ {
+ if (called_radius_init)
+ return 0;
+ if (rc_read_config (_PATH_ETC_RADIUSCLIENT_CONF) != 0)
+ return (-1);
+
+ if (rc_read_dictionary (rc_conf_str ("dictionary")) != 0)
+ return (-1);
+
+ if (rc_read_mapfile (rc_conf_str ("mapfile")) != 0)
+ return (-1);
+
+ called_radius_init = 1;
+
+ return 0;
+ }
+
+ int radius_setparams(vp)
+ VALUE_PAIR *vp;
+ {
+ ipcp_options *wo = &ipcp_wantoptions[0];
+ u_int32_t remote = 0;
+
+ /*
+ * service type (if not framed then quit),
+ * new IP address (so RADIUS can define static IP for some users),
+ * new netmask (not used at present)
+ * idle time limit
+ * session time limit (not working at present)
+ */
+
+ while (vp)
+ {
+ switch (vp->attribute)
+ {
+ case PW_SERVICE_TYPE:
+
+ if (vp->lvalue != PW_FRAMED)
+ {
+ syslog (LOG_NOTICE, "RADIUS wrong service type %ld for %s",
+ vp->lvalue, username);
+ return (-1);
+ }
+ break;
+
+ case PW_FRAMED_PROTOCOL:
+
+ if (vp->lvalue != PW_PPP)
+ {
+ syslog (LOG_NOTICE, "RADIUS wrong framed protocol %ld for %s)",
+ vp->lvalue, username);
+ return (-1);
+ }
+ break;
+
+ case PW_FRAMED_IP_ADDRESS:
+
+ /* 0xfffffffe means NAS should select an ip address */
+ /* 0xffffffff means user should be allowed to select one */
+ /* the last case probably needs special handling ??? */
+ if ((remote != 0xfffffffe) && (remote != 0xffffffff))
+ {
+ remote = htonl(vp->lvalue);
+ if (bad_ip_adrs (remote))
+ {
+ syslog (LOG_ERR, "RADIUS bad remote IP address %s for %s",
+ ip_ntoa (remote), username);
+ return (-1);
+ }
+
+ wo->hisaddr = remote;
+ }
+ break;
+
+ case PW_FRAMED_IP_NETMASK:
+
+ netmask = htonl (vp->lvalue);
+ break;
+
+ case PW_FRAMED_MTU:
+
+ lcp_allowoptions[0].mru = vp->lvalue;
+ break;
+
+ case PW_IDLE_TIMEOUT:
+
+ idle_time_limit = vp->lvalue;
+ break;
+
+ /* doesn't work at the moment */
+ case PW_SESSION_TIMEOUT:
+
+ session_time_limit = vp->lvalue;
+ break;
+ }
+
+ vp = vp->next;
+
+ }
+ syslog(LOG_WARNING, "@@mla@@: radius_setparam left");
+ return 0;
+ }
+
+ /*
+ * rad_pap_auth - Check the user name and password against RADIUS server,
+ * and add accounting start record of the user if OK.
+ *
+ * Returns:
+ *
+ * UPAP_AUTHNAK: Login failed.
+ * UPAP_AUTHACK: Login succeeded.
+ *
+ * In either case, msg points to an appropriate message.
+ *
+ */
+
+ int
+ radius_pap_auth (user, passwd, msg, msglen)
+ char *user;
+ char *passwd;
+ char **msg;
+ int *msglen;
+ {
+ VALUE_PAIR *send, *received;
+ UINT4 av_type;
+ char username_realm[256];
+ static char radius_msg[4096];
+ int result;
+ char *default_realm;
+
+
+ send = NULL;
+
+ /* read in the config files if neccessary */
+ if(!called_radius_init && (radius_init() < 0))
+ return (UPAP_AUTHNAK);
+
+ /*
+ * then we define and map tty to port
+ */
+
+ client_port = rc_map2id (devnam);
+
+ /*
+ * now we define service type and framed protocol
+ */
+
+ av_type = PW_FRAMED;
+ rc_avpair_add (&send, PW_SERVICE_TYPE, &av_type, 0);
+
+ av_type = PW_PPP;
+ rc_avpair_add (&send, PW_FRAMED_PROTOCOL, &av_type, 0);
+
+ /*
+ * for RADIUS we login in as username@realm eventualy so
+ * here we add an @realm part of username if not already
+ * specified.
+ */
+
+ strncpy (username, user, sizeof(username));
+ strncpy (username_realm, user, sizeof (username_realm));
+
+ default_realm = rc_conf_str ("default_realm");
+
+ if ((strchr (username_realm, '@') == NULL) && default_realm &&
+ (*default_realm != '\0'))
+ {
+ strncat (username_realm, "@", sizeof (username_realm));
+ strncat (username_realm, default_realm, sizeof (username_realm));
+ }
+
+ /*
+ * we are sending username and password to RADIUS
+ */
+
+ rc_avpair_add (&send, PW_USER_NAME, username_realm, 0);
+ rc_avpair_add (&send, PW_USER_PASSWORD, passwd, 0);
+
+ /*
+ * make authentication with RADIUS server
+ */
+
+ result = rc_auth (client_port, send, &received, radius_msg);
+
+ if (result == OK_RC) {
+ if (radius_setparams(received) < 0)
+ result = ERROR_RC;
+ else {
+ radius_in = TRUE;
+ radius_acct_start();
+ }
+
+ rc_avpair_free(received);
+ }
+
+ /* free value pairs */
+ rc_avpair_free (send);
+
+ *msg = radius_msg;
+ *msglen = strlen(radius_msg);
+
+ return (result == OK_RC)?UPAP_AUTHACK:UPAP_AUTHNAK;
+ }
+
+ int
+ radius_chap_auth (user, remmd, cstate)
+ char *user;
+ u_char *remmd;
+ chap_state *cstate;
+ {
+ VALUE_PAIR *send, *received;
+ UINT4 av_type;
+ char username_realm[256];
+ static char radius_msg[4096];
+ int result;
+ char *default_realm;
+ u_char cpassword[MD5_SIGNATURE_SIZE+1];
+
+ /* we handle md5 digest at the moment */
+ if (cstate->chal_type != CHAP_DIGEST_MD5)
+ return(-1);
+ syslog(LOG_WARNING,"@@mla@@ radius_chap_auth called(<%s>, <%s>, cstat)", user, remmd);
+
+ send = NULL;
+
+ /* read in the config files if neccessary */
+ if(!called_radius_init && (radius_init() < 0))
+ return (-1);
+
+ /*
+ * then we define and map tty to port
+ */
+
+ client_port = rc_map2id (devnam);
+ syslog(LOG_WARNING, "@@mla@@ client_port = %d", client_port);
+ /*
+ * now we define service type and framed protocol
+ */
+
+ av_type = PW_FRAMED;
+ rc_avpair_add (&send, PW_SERVICE_TYPE, &av_type, 0);
+
+ av_type = PW_PPP;
+ rc_avpair_add (&send, PW_FRAMED_PROTOCOL, &av_type, 0);
+
+ /*
+ * for RADIUS we login in as username@realm eventualy so
+ * here we add an @realm part of username if not already
+ * specified.
+ */
+
+ strncpy (username, user, sizeof(username));
+ strncpy (username_realm, user, sizeof (username_realm));
+
+ default_realm = rc_conf_str ("default_realm");
+
+ if ((strchr (username_realm, '@') == NULL) && default_realm &&
+ (*default_realm != '\0'))
+ {
+ strncat (username_realm, "@", sizeof (username_realm));
+ strncat (username_realm, default_realm, sizeof (username_realm));
+ }
+
+ /*
+ * we are sending username and password to RADIUS
+ */
+ syslog(LOG_WARNING, "@@mla@@ username_realm= <%s>", username_realm);
+ rc_avpair_add (&send, PW_USER_NAME, username_realm, 0);
+
+ /*
+ * add the CHAP-Password and CHAP-Challenge fields
+ */
+
+ cpassword[0] = cstate->chal_id;
+ memcpy(&cpassword[1], remmd, MD5_SIGNATURE_SIZE);
+
+ syslog(LOG_WARNING, "@@mla@@ cpassword= <%s>", &cpassword[1]);
+ rc_avpair_add(&send, PW_CHAP_PASSWORD, cpassword, MD5_SIGNATURE_SIZE + 1);
+ rc_avpair_add(&send, PW_CHAP_CHALLENGE, cstate->challenge, cstate->chal_len);
+
+
+ /*
+ * make authentication with RADIUS server
+ */
+
+ result = rc_auth (client_port, send, &received, radius_msg);
+ syslog(LOG_WARNING, "@@mla@@ radius_auth result = %d", result);
+
+ if (result == OK_RC) {
+
+ if (radius_setparams(received) < 0)
+ result = ERROR_RC;
+ else {
+ radius_in = TRUE;
+ radius_acct_start();
+ }
+ syslog(LOG_WARNING, "@@mla@@ radius_auth: before freeing receveid");
+ rc_avpair_free(received);
+ syslog(LOG_WARNING, "@@mla@@ radius_auth: after freeing receveid");
+ }
+
+ /* free value pairs */
+ syslog(LOG_WARNING, "@@mla@@ radius_auth: before freeing send");
+ rc_avpair_free (send);
+ syslog(LOG_WARNING, "@@mla@@ radius_auth: after freeing send");
+
+ return (result == OK_RC)?0:(-1);
+ }
+
+
+
+ struct ifstats {
+ long rx_bytes;
+ long rx_packets;
+ long rx_errors;
+ long rx_dropped;
+ long rx_fifo_errors;
+ long rx_frame_errors;
+
+ long tx_bytes;
+ long tx_packets;
+ long tx_errors;
+ long tx_dropped;
+ long tx_fifo_errors;
+ long collisions;
+ long tx_carrier_errors;
+ };
+
+ static int __inline__ isspace(unsigned char c)
+ {
+ return c == ' ' || c == '\t' || c == '\n';
+ }
+
+
+ static void if_getipacct(char* ifname, struct ifstats* ifs)
+ {
+ FILE* f = fopen("/proc/net/ip_acct","r");
+ char buf[256];
+ char acctif[128];
+ long dummy;
+ long direction;
+ long packets;
+ long bytes;
+ int rc;
+
+ fprintf(stderr,"if_getipacct called\n");
+ if (!f){
+ perror("Cannot open /proc/net/ip_acct");
+ return;
+ }
+ fgets(buf, sizeof(buf), f);
+ acctif[0] = '\0';
+ while (1){
+ rc = fscanf(f, "%ld/%ld->%ld/%ld %s %ld %ld %ld %ld %ld %ld", &dummy,&dummy,&dummy,&dummy,acctif,&dummy, &direction, &dummy, &dummy, &packets, &bytes);
+ fgets(buf, sizeof(buf), f);
+ fprintf(stderr,"fscanf returns %d\n", rc);
+ fprintf(stderr,"Interface <%s>\n", acctif);
+ if (rc == EOF){
+ break;
+ }
+ if (rc != 11){
+ break;
+ }
+ if (strcmp(ifname, acctif) == 0) {
+ fprintf(stderr,"Interface <%s> found\n",ifname);
+ if (direction == 1000) { /* incoming bytes */
+ fprintf(stderr,"Incoming bytes/packets = %ld/%ld\n", bytes, packets);
+ ifs->rx_bytes = bytes;
+ ifs->rx_packets = packets;
+ } else {
+ fprintf(stderr,"Outgoing bytes/packets = %ld/%ld\n", bytes, packets);
+ ifs->tx_bytes = bytes;
+ ifs->tx_packets = packets;
+ }
+ }
+ }
+ fclose(f);
+ }
+
+ static void if_getstats(char *ifname, struct ifstats *ife)
+ {
+ FILE *f = fopen("/proc/net/dev", "r");
+ char buf[256];
+ int have_byte_counters = 0;
+ char *bp;
+
+ fprintf(stderr,"@mla@: Reading statistics for interface <%s>\n", ifname);
+ if (f==NULL)
+ return;
+ fgets(buf, 255, f); /* throw away first line of header */
+ fgets(buf, 255, f);
+ if (strstr(buf, "bytes")) have_byte_counters=1;
+ while(fgets(buf,255,f)) {
+ bp=buf;
+ while(*bp&&isspace(*bp))
+ bp++;
+ if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':') {
+ bp=strchr(bp,':');
+ bp++;
+ if (have_byte_counters) {
+ sscanf(bp,"%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+ &ife->rx_bytes,
+ &ife->rx_packets,
+ &ife->rx_errors,
+ &ife->rx_dropped,
+ &ife->rx_fifo_errors,
+ &ife->rx_frame_errors,
+ &ife->tx_bytes,
+ &ife->tx_packets,
+ &ife->tx_errors,
+ &ife->tx_dropped,
+ &ife->tx_fifo_errors,
+ &ife->collisions,
+ &ife->tx_carrier_errors
+ );
+ } else {
+ sscanf(bp,"%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+ &ife->rx_packets,
+ &ife->rx_errors,
+ &ife->rx_dropped,
+ &ife->rx_fifo_errors,
+ &ife->rx_frame_errors,
+ &ife->tx_packets,
+ &ife->tx_errors,
+ &ife->tx_dropped,
+ &ife->tx_fifo_errors,
+ &ife->collisions,
+
+ &ife->tx_carrier_errors
+ );
+ ife->rx_bytes = 0;
+ ife->tx_bytes = 0;
+ }
+ break;
+ }
+ }
+ fclose(f);
+ }
+
+ static struct ifstats start_stats;
+
+
+ static void
+ radius_acct_start()
+ {
+ UINT4 av_type;
+ int result;
+ VALUE_PAIR *send = NULL;
+
+ start_time = time (NULL);
+ if_getstats(ifname, &start_stats);
+ if (start_stats.rx_bytes == -1)
+ {
+ /* fall back to ip accounting */
+ if_getipacct(ifname, &start_stats);
+ if (start_stats.rx_bytes == -1)
+ {
+ start_stats.rx_bytes = 0;
+ start_stats.tx_bytes = 0;
+ }
+ }
+
+ /* generate an id for this session */
+ strncpy (session_id, rc_mksid (), sizeof (session_id));
+ rc_avpair_add (&send, PW_ACCT_SESSION_ID, session_id, 0);
+
+ rc_avpair_add (&send, PW_USER_NAME, username, 0);
+
+ av_type = PW_STATUS_START;
+ rc_avpair_add (&send, PW_ACCT_STATUS_TYPE, &av_type, 0);
+
+ av_type = PW_FRAMED;
+ rc_avpair_add (&send, PW_SERVICE_TYPE, &av_type, 0);
+
+ av_type = PW_PPP;
+ rc_avpair_add (&send, PW_FRAMED_PROTOCOL, &av_type, 0);
+
+ av_type = PW_RADIUS;
+ rc_avpair_add (&send, PW_ACCT_AUTHENTIC, &av_type, 0);
+
+ result = rc_acct (client_port, send);
+
+ rc_avpair_free(send);
+
+ if (result != OK_RC) {
+ /* RADIUS server could be down so make this a warning */
+ syslog (LOG_WARNING, "RADIUS accounting START failed for %s", username);
+ }
+ }
+
+ void
+ radius_acct_stop ()
+ {
+ UINT4 av_type;
+ int result;
+ VALUE_PAIR *send = NULL;
+ struct ifstats stop_stats;
+
+ if_getstats(ifname, &stop_stats);
+ if (stop_stats.rx_bytes == -1)
+ {
+ /* fall back to ip accounting */
+ if_getipacct(ifname, &stop_stats);
+ if (stop_stats.rx_bytes == -1)
+ {
+ stop_stats.rx_bytes = 0;
+ stop_stats.tx_bytes = 0;
+ }
+ }
+
+ rc_avpair_add (&send, PW_ACCT_SESSION_ID, session_id, 0);
+
+ rc_avpair_add (&send, PW_USER_NAME, username, 0);
+
+ av_type = PW_STATUS_STOP;
+ rc_avpair_add (&send, PW_ACCT_STATUS_TYPE, &av_type, 0);
+
+ av_type = PW_FRAMED;
+ rc_avpair_add (&send, PW_SERVICE_TYPE, &av_type, 0);
+
+ av_type = PW_PPP;
+ rc_avpair_add (&send, PW_FRAMED_PROTOCOL, &av_type, 0);
+
+ av_type = PW_RADIUS;
+ rc_avpair_add (&send, PW_ACCT_AUTHENTIC, &av_type, 0);
+
+ av_type = time (NULL) - start_time;
+ rc_avpair_add (&send, PW_ACCT_SESSION_TIME, &av_type, 0);
+
+ av_type = stop_stats.tx_bytes - start_stats.tx_bytes;
+ rc_avpair_add(&send, PW_ACCT_OUTPUT_OCTETS, &av_type, 0);
+
+ av_type = stop_stats.rx_bytes - start_stats.rx_bytes;
+ rc_avpair_add(&send, PW_ACCT_INPUT_OCTETS, &av_type, 0);
+
+
+ result = rc_acct (client_port, send);
+
+ rc_avpair_free(send);
+
+ if (result != OK_RC)
+ {
+ syslog(LOG_ERR, "RADIUS accounting STOP failed (%s)", username);
+ }
+
+ /* mark RADIUS as down */
+ radius_in = FALSE;
+ }