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; + }