X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fplugins%2Fradius%2Fradius.c;h=27243b15b7c155f55973c5968d44a237004e105d;hp=389dff9152bc5510332e5c5bd760daffcdbce6a4;hb=2d0e1b1b8bc0587fb9e777b0c9f0019e60cc7194;hpb=59a3d197fdf9d15d0d78a794257f23b1faafaf36 diff --git a/pppd/plugins/radius/radius.c b/pppd/plugins/radius/radius.c index 389dff9..27243b1 100644 --- a/pppd/plugins/radius/radius.c +++ b/pppd/plugins/radius/radius.c @@ -24,7 +24,7 @@ * ***********************************************************************/ static char const RCSID[] = -"$Id: radius.c,v 1.11 2002/07/15 11:04:18 kad Exp $"; +"$Id: radius.c,v 1.15 2002/09/12 05:41:49 fcusack Exp $"; #include "pppd.h" #include "chap.h" @@ -40,6 +40,7 @@ static char const RCSID[] = #include #include #include +#include #define BUF_LEN 1024 @@ -70,6 +71,7 @@ static void radius_choose_ip(u_int32_t *addrp); static int radius_init(char *msg); static int get_client_port(char *ifname); static int radius_allowed_address(u_int32_t addr); +static void radius_acct_interim(void *); #ifdef MPPE static int radius_setmppekeys(VALUE_PAIR *vp, REQUEST_INFO *req_info, chap_state *); @@ -80,6 +82,10 @@ static int radius_setmppekeys2(VALUE_PAIR *vp, REQUEST_INFO *req_info); #define MAXSESSIONID 32 #endif +#ifndef MAXCLASSLEN +#define MAXCLASSLEN 500 +#endif + struct radius_state { int accounting_started; int initialized; @@ -92,8 +98,11 @@ struct radius_state { char config_file[MAXPATHLEN]; char session_id[MAXSESSIONID + 1]; time_t start_time; + int acct_interim_interval; SERVER *authserver; /* Authentication server to use */ SERVER *acctserver; /* Accounting server to use */ + int class_len; + char class[MAXCLASSLEN]; }; void (*radius_attributes_hook)(VALUE_PAIR *) = NULL; @@ -511,9 +520,19 @@ radius_setparams(chap_state *cstate, VALUE_PAIR *vp, char *msg, break; case PW_OCTETS_DIRECTION: /* Session traffic limit direction check */ - maxoctets_dir = ( vp->lvalue > 4 ) 0 : vp->lvalue ; + maxoctets_dir = ( vp->lvalue > 4 ) ? 0 : vp->lvalue ; + break; +#endif + case PW_ACCT_INTERIM_INTERVAL: + /* Send accounting updates every few seconds */ + rstate.acct_interim_interval = vp->lvalue; + /* RFC says it MUST NOT be less than 60 seconds */ + /* We use "0" to signify not sending updates */ + if (rstate.acct_interim_interval && + rstate.acct_interim_interval < 60) { + rstate.acct_interim_interval = 60; + } break; -#endif case PW_FRAMED_IP_ADDRESS: /* seting up remote IP addresses */ remote = vp->lvalue; @@ -532,7 +551,16 @@ radius_setparams(chap_state *cstate, VALUE_PAIR *vp, char *msg, rstate.ip_addr = remote; } break; + case PW_CLASS: + /* Save Class attribute to pass it in accounting request */ + if (vp->lvalue <= MAXCLASSLEN) { + rstate.class_len=vp->lvalue; + memcpy(rstate.class, vp->strvalue, rstate.class_len); + } /* else too big for our buffer - ignore it */ + break; } + + #ifdef CHAPMS } else if (vp->vendorcode == VENDOR_MICROSOFT) { switch (vp->attribute) { @@ -744,6 +772,10 @@ radius_acct_start(void) rc_avpair_add(&send, PW_USER_NAME, rstate.user, 0, VENDOR_NONE); + if (rstate.class_len > 0) + rc_avpair_add(&send, PW_CLASS, + rstate.class, rstate.class_len, VENDOR_NONE); + av_type = PW_STATUS_START; rc_avpair_add(&send, PW_ACCT_STATUS_TYPE, &av_type, 0, VENDOR_NONE); @@ -784,6 +816,10 @@ radius_acct_start(void) "Accounting START failed for %s", rstate.user); } else { rstate.accounting_started = 1; + /* Kick off periodic accounting reports */ + if (rstate.acct_interim_interval) { + TIMEOUT(radius_acct_interim, NULL, rstate.acct_interim_interval); + } } } @@ -876,6 +912,101 @@ radius_acct_stop(void) rc_avpair_free(send); } +/********************************************************************** +* %FUNCTION: radius_acct_interim +* %ARGUMENTS: +* None +* %RETURNS: +* Nothing +* %DESCRIPTION: +* Sends an interim accounting message to the RADIUS server +***********************************************************************/ +static void +radius_acct_interim(void *ignored) +{ + UINT4 av_type; + VALUE_PAIR *send = NULL; + ipcp_options *ho = &ipcp_hisoptions[0]; + u_int32_t hisaddr; + int result; + + if (!rstate.initialized) { + return; + } + + if (!rstate.accounting_started) { + return; + } + + rc_avpair_add(&send, PW_ACCT_SESSION_ID, rstate.session_id, + 0, VENDOR_NONE); + + rc_avpair_add(&send, PW_USER_NAME, rstate.user, 0, VENDOR_NONE); + + av_type = PW_STATUS_ALIVE; + rc_avpair_add(&send, PW_ACCT_STATUS_TYPE, &av_type, 0, VENDOR_NONE); + + av_type = PW_FRAMED; + rc_avpair_add(&send, PW_SERVICE_TYPE, &av_type, 0, VENDOR_NONE); + + av_type = PW_PPP; + rc_avpair_add(&send, PW_FRAMED_PROTOCOL, &av_type, 0, VENDOR_NONE); + + av_type = PW_RADIUS; + rc_avpair_add(&send, PW_ACCT_AUTHENTIC, &av_type, 0, VENDOR_NONE); + + /* Update link stats */ + update_link_stats(0); + + if (link_stats_valid) { + link_stats_valid = 0; /* Force later code to update */ + + av_type = link_connect_time; + rc_avpair_add(&send, PW_ACCT_SESSION_TIME, &av_type, 0, VENDOR_NONE); + + av_type = link_stats.bytes_out; + rc_avpair_add(&send, PW_ACCT_OUTPUT_OCTETS, &av_type, 0, VENDOR_NONE); + + av_type = link_stats.bytes_in; + rc_avpair_add(&send, PW_ACCT_INPUT_OCTETS, &av_type, 0, VENDOR_NONE); + + av_type = link_stats.pkts_out; + rc_avpair_add(&send, PW_ACCT_OUTPUT_PACKETS, &av_type, 0, VENDOR_NONE); + + av_type = link_stats.pkts_in; + rc_avpair_add(&send, PW_ACCT_INPUT_PACKETS, &av_type, 0, VENDOR_NONE); + } + + if (*remote_number) { + rc_avpair_add(&send, PW_CALLING_STATION_ID, + remote_number, 0, VENDOR_NONE); + } + + av_type = PW_ASYNC; + rc_avpair_add(&send, PW_NAS_PORT_TYPE, &av_type, 0, VENDOR_NONE); + + hisaddr = ho->hisaddr; + av_type = htonl(hisaddr); + rc_avpair_add(&send, PW_FRAMED_IP_ADDRESS , &av_type , 0, VENDOR_NONE); + + if (rstate.acctserver) { + result = rc_acct_using_server(rstate.acctserver, + rstate.client_port, send); + } else { + result = rc_acct(rstate.client_port, send); + } + + if (result != OK_RC) { + /* RADIUS server could be down so make this a warning */ + syslog(LOG_WARNING, + "Interim accounting failed for %s", rstate.user); + } + rc_avpair_free(send); + + /* Schedule another one */ + TIMEOUT(radius_acct_interim, NULL, rstate.acct_interim_interval); +} + /********************************************************************** * %FUNCTION: radius_ip_up * %ARGUMENTS: