[Printable]
Share

Trial Period on Chillispot

Posted: Sat 23rd May 2009 in WiFi

Chillispot is a Captive Portal or Splash screen system for wifi hotspots and the like, we (PierToPier.net) OK mostly me have been hacking around with it for a while. Here's how to allow limited guest access by hacking around with the Login Page. There are 2 bits to this page, Limited "Registration" period, and Quotas, or Fair Use Policy.

Before we start...

Assumptions

  1. Your using the PHP version of the login page.(I can't do perl)
  2. You're RADIUS server is on the same server as the splash (UAM) server.
  3. Radius is using MySQL to store usernames etc.

Out sytem works like this, its free BUT:

Now thats a problem, cos how can they confirm there e-mail before they log in.

Limited "Registration" Period

How it works:

In basic it goes something like this:

just a reminder:
UAM and Radius are on same server,
radius is using MySQL to store usernames etc.

  • Customized splash screen reads the mac=ADDRESS attribute that chili helpfully sends it.
  • Then it looks for that mac address as a username in the Radius users
  • If its not there it creates a radius user with name of ADDRESS.

Now there is a unique "Guest" account specific to that computer.

  • If the MAC is already in there then it looks that MAC (also a username in radius) up in the Radius Accounting table. If its been used more than reasonable to retrieve and email. It moves it to a different radius group, which is no longer allowed to log in.
  • The splash screen has an extra form, identical to the normal login one, except the username field is hidden and preset to the MAC address of the PC.

Viola, free access, with Identifiable users with no pre-registration required. There's a list of radius groups used by the system futher down

Here are some scripts you can embed in the loginform bit of hotspotlogin.php -Sorry I can supply the whole file mine was chopped up and re-written years ago.

 //Guest Mac handling.
 //Look for a user based on mac
 //database settings first
 	$hostname_p2p = "localhost"; /MySQL hostname
	$database_rad = "radius"; //name of radius database
	$username_p2p = "#######"; //MySQL userame
	$password_p2p = "#######"; //MySQL password
 //now connect
$p2p = mysql_pconnect($hostname_p2p, $username_p2p, $password_p2p) or
 trigger_error(mysql_error(),E_USER_ERROR);
mysql_select_db($database_rad, $p2p);
//query radius with the mac address chilli sends us as a get var.
$query_Guest = ("SELECT UserName FROM radcheck WHERE UserName='".$_GET['mac']."'");
$Guest = mysql_query($query_Guest, $p2p) or die(mysql_error());
$row_Guest = mysql_fetch_assoc($Guest);
$totalRows_Guest = mysql_num_rows($Guest);
// If new MAC address create a radius user for them.
if($totalRows_Guest=="0") { 
							//insert into RadCheck Table
	$InsRadius = "INSERT INTO radcheck SET Username='".$_GET['mac']."',
 Attribute='User-Password', op='==', Value='guest'";
	if (@mysql_query($InsRadius)) { //ok debug message was here 
	;} else { $mess=($mess."oops something nasty happened updating the Radius Server"); };
		;$InsRadiusGroup = "INSERT INTO usergroup SET UserName='".$_GET['mac']."', 
GroupName='guest'";
	if (@mysql_query($InsRadiusGroup)) { // ok messge was here
	} else { $mess=($mess. "Oops, something nasty happened updating the Radius
 Server Group membership"); };
	} else {
// Got a returning Guest see If we should block 'em chack accounting data.
	$query_gStat = ("SELECT count(RadAcctId) as logins, sum(AcctInputOctets) as 
ind, sum(AcctOutputOctets)
 as outd, sum(AcctSessionTime) as timeon
FROM `radacct`
where UserName ='".$_GET['mac']."'
AND AcctStartTime>'2009-04-29 18:30:00'");
	$gStat = mysql_query($query_gStat, $p2p) or die(mysql_error());
	$row_gStat = mysql_fetch_assoc($gStat);
	$totalRows_gStat = mysql_num_rows($gStat);
	$freeLoader=0;
	if($totalRows_gStat!=0); { //got data
		if($row_gStat['logins']>5) $freeLoader=1; //more than 5 time logged in
		if($row_gStat['timeon']>3600) $freeLoader=1; //been on for a whole HOUR
		if($row_gStat['ind']>50000000) $freeLoader=1; //octets in
		if($row_gStat['outd']>50000000) $freeLoader=1; //octets out
		if($freeLoader==1) { //got our self a scumbag
			$moveGroup = "update usergroup SET GroupName='expGuest' WHERE UserName='        
            ".$_GET['mac']."'";
			if (@mysql_query($moveGroup)) { 
			// ok messge was here
			} else { $mess=($mess. "Oops, something nasty happened updating the 
            Radius Server Group membership"); 
			};
		} //end freeloader
	} //end got stats
} //end of original codes else
// format any messages for HTML display latter.
if($mess!="") {$mess = ("

" . $mess . "

\n");};

Somewhere further down the page you might want to place the following - will display the messages from the above script. The above scripts take care of detecting new MAC addresses and shuffling them around the radius database. Next wee need the cusomised form. firstly to make totaly sure the dumb users get the message, we'll use a javascript dialog box on the tempoary registration login button. for that find hte bit of hotspotlogin.php that writes the head of the HTML docs. function called header If i remember rightly. add the following:

<script type="text/javascript">
<!--
function MM_popupMsg(msg) { //v1.0
alert(msg);
}
//-->
</script>
Then its just a matter of replacing the login form with this one. Sorry 'bout the 'orrid table. Will CSS it at some point.
<table width="100%"  border="0" cellspacing="2" cellpadding="2">
<tr>
<td width="50%" valign="top"><div align="center">
<form name="userForm" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?> ?res=doLogin"><fieldset>
<legend>USER LOGIN </legend>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td><div align="right">User Name</div></td>
<td><input name="UserName" type="text"></td>
</tr>
<tr>
<td><div align="right">Password</div></td>
<td><input name="Password" type="password"></td>
</tr>
</table>
<br />
<INPUT TYPE="HIDDEN" NAME="chal" VALUE="<?php echo $_GET['challenge']; ?>">
<INPUT TYPE="HIDDEN" NAME="uamip" VALUE="<?php echo $_GET['uamip']; ?>">
<INPUT TYPE="HIDDEN" NAME="uamport" VALUE="<?php echo $_GET['uamport']; ?>">
<INPUT TYPE="HIDDEN" NAME="userurl" VALUE="<?php echo $_GET['userurl']; ?>">
<input name="login" type="submit" id="login" value="login">
<a href="<?php echo $regUrl; ?>?mac=<?php echo $_GET['mac']; ?>">register </a>
</fieldset>
</form>
</div></td>
<td width="50%" valign="top"><div align="center">
<form name="guestForm" method="post" action="<?php $_SERVER['PHP_SELF']; ?> ?res=doLogin">
<fieldset>
<legend>TEMPORARY ACCESS</legend>
<p>This gives you 20 minutes internet access to complete registration <br />
<INPUT TYPE="HIDDEN" NAME="chal" VALUE="<?php echo $_GET['challenge']; ?>">
<INPUT TYPE="HIDDEN" NAME="uamip" VALUE="<?php echo $_GET['uamip']; ?>">
<input TYPE="HIDDEN" name="uamport" id="uamport" value="<?php echo $_GET['uamport']; ?>">
<INPUT TYPE="HIDDEN" NAME="userurl" VALUE="<?php echo $_GET['userurl']; ?>">
<INPUT TYPE="HIDDEN" NAME="UserName" VALUE="<?php echo $_GET['mac']; ?>">
<INPUT TYPE="HIDDEN" NAME="Password" VALUE="guest">
<input name="login" type="submit" id="login" onClick="MM_popupMsg('You have 20 minutes to complete the registration process before this button is disabled!')" value="login">
<br />
you need to <a href="<?php echo $regUrl; ?>?mac=<?php echo $_GET['mac']; ?>"> register</a> first </p>
</fieldset>
</form>
</div></td>
</tr>
</table>

Job's a gooden, the second form differs from the standard chilli one in 3 ways.

  1. the user name is hidden and php writes the mac addresss as the username
  2. the password field is hidden and the password set to guest encrypted.
  3. bit of javsacript on the button to pop up the warning dialog.

Fair usage.

This one's script is easier, this is a PHP script I run off cron every hour. Punishes people who download too much stay online too long, or upload to much. Works by moving group membership around.

Put simply there's an extra group with no login allowed, called "punish" if the radius accounting table says they've been on too much they get moved in there for a while till they drop back to acceptable levels.

Here's a table of the radius groups used by PierToPier.net:

 id   GroupName   Attribute   op   Value   coments
1  device      Auth-Type   :=   Local   Macauthed devices
2  user        Auth-Type   :=   Local   "normal" users
3  guest       Auth-Type   :=   Local   limited registration period
4  expGuest    Auth-Type   :=   Reject  expired registration period devices
5  mates       Auth-Type   :=   Local   my mates (extra prvialeges
6  punish      Auth-Type   :=   Reject  people over their quota.

 

My Group Reply Table also restricts the various groups login time bandwidth etc.
BIG FAT WARNING, unless its been changed default hotspotlogin.php's reply feature is broken, unless "register globals" is on. Somewhere it says $reply when it should say $_GET['reply'].

anyway here's the table:

 id   GroupName   Attribute  op   Value  prio 
1  guest  WISPr-Bandwidth-Max-Down  :=  512000 0
2  guest  WISPr-Bandwidth-Max-Up  :=  128000 0
3  guest  Session-Timeout  :=  1800 0
4  user  WISPr-Bandwidth-Max-Down  :=  512000 0
5  user  WISPr-Bandwidth-Max-Up  :=  128000 0
6  user  Session-Timeout  :=  7200 0
7  guest  Reply-Message  :=   This is a GUEST login - you have 20 minutes to register! before this is permantly disabled. WE ARE NOT KIDDING! It will stop working VERY SOON! 0
12  punish  Reply-Message  :=   You've over used one of our our quotas. Either by downloading or uploading to much or staying online too long. Wait a while and your access will be restored. The PierToPier.net Team. 0
11  expGuest  Reply-Message  :=   Your Guest Access has expired. You need to register. Since you're going to need to confrim your email, your going to have to get some internet somewhere else! Register Now, reply to the confirm email latter!  0


anyway heres the code

#!/usr/bin/php -q
<?php
$hostname = "localhost";
$database = "radius";
$username = "userName";//MySQL username
$password = "password";//MySQL password

// LIMITS of aceptability
$timeOn=21600; //minutes 6 hours = 21600
$inData=1000000000; //bytes
$outData=500000000; //bytes
// Punishament Adjusters.
$timePen=7200; //don't re-enable till ther'es 2 hours in hand
$inPen=100000000; //make a 10 percent leway
$out=50000000; //make a 10 percent leway
$p2pdb = mysql_pconnect($hostname, $username, $password) or die(mysql_error());
mysql_select_db($database, $p2pdb);
$query_day = "SELECT radacct.UserName, SUM(acctSessionTime) as timeOn, 
SUM(AcctInputOctets) AS inData, SUM(AcctOutputOctets) AS outData, NOW() as now
FROM radacct LEFT JOIN usergroup ON radacct.UserName=usergroup.UserName
WHERE AcctStopTime >= DATE_SUB(NOW(),INTERVAL 1 DAY) AND GroupName='user'
GROUP BY UserName";
$day = mysql_query($query_day, $p2pdb) or die(mysql_error());
$row_day = mysql_fetch_assoc($day);
$totalRows_day = mysql_num_rows($day);
$flag=0;
echo "Normal Users's on last 24 hours, looking for evildoers\n";
do{
        echo $row_day['UserName']."\tTime: ".round($row_day['timeOn']/3600,3)."\tIn:
 ".round($row_day['inData']/1000000)."Meg\tOut: ".round($row_day['outData']/1000000)
."Meg\n";
        if($row_day['timeOn']>=$timeOn) {$flag=1; echo "Time On Flagged\n";}
        if($row_day['inData']>=$inData) {$flag=1; echo "data In  Flagged\n";}
        if($row_day['outData']>=$outData) {$flag=1; echo "data Out Flagged\n";}
        if($flag==1) { //got our self a scumbag
                $moveGroup = "update usergroup SET GroupName='punish' WHERE 
UserName='".$row_day['UserName']."'";
                if (@mysql_query($moveGroup)) {
                        echo "Moved ".$row_day['UserName']." to punishment cell\n";
                } else { $mess=($mess. "Oops, something nasty happened updating 
the Radius Server Group membership");
                }
        }
} while ($row_day = mysql_fetch_assoc($day));
$flag=0; //Re-set flag
// put them back if they've droped below the levels
$query_ret = "SELECT radacct.UserName, SUM(acctSessionTime) as timeOn, 
SUM(AcctInputOctets) AS inData, SUM(AcctOutputOctets) AS outData
FROM radacct LEFT JOIN usergroup ON radacct.UserName=usergroup.UserName
WHERE AcctStopTime >= DATE_SUB(NOW(),INTERVAL 1 DAY) AND GroupName='punish'
GROUP BY UserName";
$ret = mysql_query($query_ret, $p2pdb) or die(mysql_error());
$row_ret = mysql_fetch_assoc($ret);
$totalRows_ret = mysql_num_rows($ret);
//re caulcuate for re-enable
$timeOn=$timeOn-$timePen;
$inData=$inData-$inPen;
$outData=$outData-$outPen;
echo "\n";
echo "      Looking for people to move back\n";
do{
        echo "Time: ".round($row_ret['timeOn']/3600,3)."\tIn: 
".round($row_ret['inData']/1000000)."Meg\tOut: ".round($row_ret['outData']/1000000)."Meg";
        if($row_ret['timeOn']<=$timeOn && $row_ret['inData']<=$inData &&
 $row_ret['outData']<=$outData) {
                $moveGroup = "update usergroup SET GroupName='user' WHERE 
UserName='".$row_ret['UserName']."'";
                if (@mysql_query($moveGroup)) {
                        echo "\tMoving ".$row_ret['UserName']." back to the General
 Population\n";
                } else { $mess=($mess. "Oops, something nasty happened updating the
 Radius Server Group membership");
                }
        } else { echo "\tLeaving ".$row_ret['UserName']." in punish\n"; }
} while ($row_ret = mysql_fetch_assoc($ret));
?>

you will need command line php to run this one.

[Printable]
Share

Trial Period on Chillispot

Posted: Sat 23rd May 2009 in WiFi

Chillispot is a Captive Portal or Splash screen system for wifi hotspots and the like, we (PierToPier.net) OK mostly me have been hacking around with it for a while. Here's how to allow limited guest access by hacking around with the Login Page. There are 2 bits to this page, Limited "Registration" period, and Quotas, or Fair Use Policy.

Before we start...

Assumptions

  1. Your using the PHP version of the login page.(I can't do perl)
  2. You're RADIUS server is on the same server as the splash (UAM) server.
  3. Radius is using MySQL to store usernames etc.

Out sytem works like this, its free BUT:

Now thats a problem, cos how can they confirm there e-mail before they log in.

Limited "Registration" Period

How it works:

In basic it goes something like this:

just a reminder:
UAM and Radius are on same server,
radius is using MySQL to store usernames etc.

  • Customized splash screen reads the mac=ADDRESS attribute that chili helpfully sends it.
  • Then it looks for that mac address as a username in the Radius users
  • If its not there it creates a radius user with name of ADDRESS.

Now there is a unique "Guest" account specific to that computer.

  • If the MAC is already in there then it looks that MAC (also a username in radius) up in the Radius Accounting table. If its been used more than reasonable to retrieve and email. It moves it to a different radius group, which is no longer allowed to log in.
  • The splash screen has an extra form, identical to the normal login one, except the username field is hidden and preset to the MAC address of the PC.

Viola, free access, with Identifiable users with no pre-registration required. There's a list of radius groups used by the system futher down

Here are some scripts you can embed in the loginform bit of hotspotlogin.php -Sorry I can supply the whole file mine was chopped up and re-written years ago.

 //Guest Mac handling.
 //Look for a user based on mac
 //database settings first
 	$hostname_p2p = "localhost"; /MySQL hostname
	$database_rad = "radius"; //name of radius database
	$username_p2p = "#######"; //MySQL userame
	$password_p2p = "#######"; //MySQL password
 //now connect
$p2p = mysql_pconnect($hostname_p2p, $username_p2p, $password_p2p) or
 trigger_error(mysql_error(),E_USER_ERROR);
mysql_select_db($database_rad, $p2p);
//query radius with the mac address chilli sends us as a get var.
$query_Guest = ("SELECT UserName FROM radcheck WHERE UserName='".$_GET['mac']."'");
$Guest = mysql_query($query_Guest, $p2p) or die(mysql_error());
$row_Guest = mysql_fetch_assoc($Guest);
$totalRows_Guest = mysql_num_rows($Guest);
// If new MAC address create a radius user for them.
if($totalRows_Guest=="0") { 
							//insert into RadCheck Table
	$InsRadius = "INSERT INTO radcheck SET Username='".$_GET['mac']."',
 Attribute='User-Password', op='==', Value='guest'";
	if (@mysql_query($InsRadius)) { //ok debug message was here 
	;} else { $mess=($mess."oops something nasty happened updating the Radius Server"); };
		;$InsRadiusGroup = "INSERT INTO usergroup SET UserName='".$_GET['mac']."', 
GroupName='guest'";
	if (@mysql_query($InsRadiusGroup)) { // ok messge was here
	} else { $mess=($mess. "Oops, something nasty happened updating the Radius
 Server Group membership"); };
	} else {
// Got a returning Guest see If we should block 'em chack accounting data.
	$query_gStat = ("SELECT count(RadAcctId) as logins, sum(AcctInputOctets) as 
ind, sum(AcctOutputOctets)
 as outd, sum(AcctSessionTime) as timeon
FROM `radacct`
where UserName ='".$_GET['mac']."'
AND AcctStartTime>'2009-04-29 18:30:00'");
	$gStat = mysql_query($query_gStat, $p2p) or die(mysql_error());
	$row_gStat = mysql_fetch_assoc($gStat);
	$totalRows_gStat = mysql_num_rows($gStat);
	$freeLoader=0;
	if($totalRows_gStat!=0); { //got data
		if($row_gStat['logins']>5) $freeLoader=1; //more than 5 time logged in
		if($row_gStat['timeon']>3600) $freeLoader=1; //been on for a whole HOUR
		if($row_gStat['ind']>50000000) $freeLoader=1; //octets in
		if($row_gStat['outd']>50000000) $freeLoader=1; //octets out
		if($freeLoader==1) { //got our self a scumbag
			$moveGroup = "update usergroup SET GroupName='expGuest' WHERE UserName='        
            ".$_GET['mac']."'";
			if (@mysql_query($moveGroup)) { 
			// ok messge was here
			} else { $mess=($mess. "Oops, something nasty happened updating the 
            Radius Server Group membership"); 
			};
		} //end freeloader
	} //end got stats
} //end of original codes else
// format any messages for HTML display latter.
if($mess!="") {$mess = ("

" . $mess . "

\n");};

Somewhere further down the page you might want to place the following - will display the messages from the above script. The above scripts take care of detecting new MAC addresses and shuffling them around the radius database. Next wee need the cusomised form. firstly to make totaly sure the dumb users get the message, we'll use a javascript dialog box on the tempoary registration login button. for that find hte bit of hotspotlogin.php that writes the head of the HTML docs. function called header If i remember rightly. add the following:

<script type="text/javascript">
<!--
function MM_popupMsg(msg) { //v1.0
alert(msg);
}
//-->
</script>
Then its just a matter of replacing the login form with this one. Sorry 'bout the 'orrid table. Will CSS it at some point.
<table width="100%"  border="0" cellspacing="2" cellpadding="2">
<tr>
<td width="50%" valign="top"><div align="center">
<form name="userForm" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?> ?res=doLogin"><fieldset>
<legend>USER LOGIN </legend>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td><div align="right">User Name</div></td>
<td><input name="UserName" type="text"></td>
</tr>
<tr>
<td><div align="right">Password</div></td>
<td><input name="Password" type="password"></td>
</tr>
</table>
<br />
<INPUT TYPE="HIDDEN" NAME="chal" VALUE="<?php echo $_GET['challenge']; ?>">
<INPUT TYPE="HIDDEN" NAME="uamip" VALUE="<?php echo $_GET['uamip']; ?>">
<INPUT TYPE="HIDDEN" NAME="uamport" VALUE="<?php echo $_GET['uamport']; ?>">
<INPUT TYPE="HIDDEN" NAME="userurl" VALUE="<?php echo $_GET['userurl']; ?>">
<input name="login" type="submit" id="login" value="login">
<a href="<?php echo $regUrl; ?>?mac=<?php echo $_GET['mac']; ?>">register </a>
</fieldset>
</form>
</div></td>
<td width="50%" valign="top"><div align="center">
<form name="guestForm" method="post" action="<?php $_SERVER['PHP_SELF']; ?> ?res=doLogin">
<fieldset>
<legend>TEMPORARY ACCESS</legend>
<p>This gives you 20 minutes internet access to complete registration <br />
<INPUT TYPE="HIDDEN" NAME="chal" VALUE="<?php echo $_GET['challenge']; ?>">
<INPUT TYPE="HIDDEN" NAME="uamip" VALUE="<?php echo $_GET['uamip']; ?>">
<input TYPE="HIDDEN" name="uamport" id="uamport" value="<?php echo $_GET['uamport']; ?>">
<INPUT TYPE="HIDDEN" NAME="userurl" VALUE="<?php echo $_GET['userurl']; ?>">
<INPUT TYPE="HIDDEN" NAME="UserName" VALUE="<?php echo $_GET['mac']; ?>">
<INPUT TYPE="HIDDEN" NAME="Password" VALUE="guest">
<input name="login" type="submit" id="login" onClick="MM_popupMsg('You have 20 minutes to complete the registration process before this button is disabled!')" value="login">
<br />
you need to <a href="<?php echo $regUrl; ?>?mac=<?php echo $_GET['mac']; ?>"> register</a> first </p>
</fieldset>
</form>
</div></td>
</tr>
</table>

Job's a gooden, the second form differs from the standard chilli one in 3 ways.

  1. the user name is hidden and php writes the mac addresss as the username
  2. the password field is hidden and the password set to guest encrypted.
  3. bit of javsacript on the button to pop up the warning dialog.

Fair usage.

This one's script is easier, this is a PHP script I run off cron every hour. Punishes people who download too much stay online too long, or upload to much. Works by moving group membership around.

Put simply there's an extra group with no login allowed, called "punish" if the radius accounting table says they've been on too much they get moved in there for a while till they drop back to acceptable levels.

Here's a table of the radius groups used by PierToPier.net:

 id   GroupName   Attribute   op   Value   coments
1  device      Auth-Type   :=   Local   Macauthed devices
2  user        Auth-Type   :=   Local   "normal" users
3  guest       Auth-Type   :=   Local   limited registration period
4  expGuest    Auth-Type   :=   Reject  expired registration period devices
5  mates       Auth-Type   :=   Local   my mates (extra prvialeges
6  punish      Auth-Type   :=   Reject  people over their quota.

 

My Group Reply Table also restricts the various groups login time bandwidth etc.
BIG FAT WARNING, unless its been changed default hotspotlogin.php's reply feature is broken, unless "register globals" is on. Somewhere it says $reply when it should say $_GET['reply'].

anyway here's the table:

 id   GroupName   Attribute  op   Value  prio 
1  guest  WISPr-Bandwidth-Max-Down  :=  512000 0
2  guest  WISPr-Bandwidth-Max-Up  :=  128000 0
3  guest  Session-Timeout  :=  1800 0
4  user  WISPr-Bandwidth-Max-Down  :=  512000 0
5  user  WISPr-Bandwidth-Max-Up  :=  128000 0
6  user  Session-Timeout  :=  7200 0
7  guest  Reply-Message  :=   This is a GUEST login - you have 20 minutes to register! before this is permantly disabled. WE ARE NOT KIDDING! It will stop working VERY SOON! 0
12  punish  Reply-Message  :=   You've over used one of our our quotas. Either by downloading or uploading to much or staying online too long. Wait a while and your access will be restored. The PierToPier.net Team. 0
11  expGuest  Reply-Message  :=   Your Guest Access has expired. You need to register. Since you're going to need to confrim your email, your going to have to get some internet somewhere else! Register Now, reply to the confirm email latter!  0


anyway heres the code

#!/usr/bin/php -q
<?php
$hostname = "localhost";
$database = "radius";
$username = "userName";//MySQL username
$password = "password";//MySQL password

// LIMITS of aceptability
$timeOn=21600; //minutes 6 hours = 21600
$inData=1000000000; //bytes
$outData=500000000; //bytes
// Punishament Adjusters.
$timePen=7200; //don't re-enable till ther'es 2 hours in hand
$inPen=100000000; //make a 10 percent leway
$out=50000000; //make a 10 percent leway
$p2pdb = mysql_pconnect($hostname, $username, $password) or die(mysql_error());
mysql_select_db($database, $p2pdb);
$query_day = "SELECT radacct.UserName, SUM(acctSessionTime) as timeOn, 
SUM(AcctInputOctets) AS inData, SUM(AcctOutputOctets) AS outData, NOW() as now
FROM radacct LEFT JOIN usergroup ON radacct.UserName=usergroup.UserName
WHERE AcctStopTime >= DATE_SUB(NOW(),INTERVAL 1 DAY) AND GroupName='user'
GROUP BY UserName";
$day = mysql_query($query_day, $p2pdb) or die(mysql_error());
$row_day = mysql_fetch_assoc($day);
$totalRows_day = mysql_num_rows($day);
$flag=0;
echo "Normal Users's on last 24 hours, looking for evildoers\n";
do{
        echo $row_day['UserName']."\tTime: ".round($row_day['timeOn']/3600,3)."\tIn:
 ".round($row_day['inData']/1000000)."Meg\tOut: ".round($row_day['outData']/1000000)
."Meg\n";
        if($row_day['timeOn']>=$timeOn) {$flag=1; echo "Time On Flagged\n";}
        if($row_day['inData']>=$inData) {$flag=1; echo "data In  Flagged\n";}
        if($row_day['outData']>=$outData) {$flag=1; echo "data Out Flagged\n";}
        if($flag==1) { //got our self a scumbag
                $moveGroup = "update usergroup SET GroupName='punish' WHERE 
UserName='".$row_day['UserName']."'";
                if (@mysql_query($moveGroup)) {
                        echo "Moved ".$row_day['UserName']." to punishment cell\n";
                } else { $mess=($mess. "Oops, something nasty happened updating 
the Radius Server Group membership");
                }
        }
} while ($row_day = mysql_fetch_assoc($day));
$flag=0; //Re-set flag
// put them back if they've droped below the levels
$query_ret = "SELECT radacct.UserName, SUM(acctSessionTime) as timeOn, 
SUM(AcctInputOctets) AS inData, SUM(AcctOutputOctets) AS outData
FROM radacct LEFT JOIN usergroup ON radacct.UserName=usergroup.UserName
WHERE AcctStopTime >= DATE_SUB(NOW(),INTERVAL 1 DAY) AND GroupName='punish'
GROUP BY UserName";
$ret = mysql_query($query_ret, $p2pdb) or die(mysql_error());
$row_ret = mysql_fetch_assoc($ret);
$totalRows_ret = mysql_num_rows($ret);
//re caulcuate for re-enable
$timeOn=$timeOn-$timePen;
$inData=$inData-$inPen;
$outData=$outData-$outPen;
echo "\n";
echo "      Looking for people to move back\n";
do{
        echo "Time: ".round($row_ret['timeOn']/3600,3)."\tIn: 
".round($row_ret['inData']/1000000)."Meg\tOut: ".round($row_ret['outData']/1000000)."Meg";
        if($row_ret['timeOn']<=$timeOn && $row_ret['inData']<=$inData &&
 $row_ret['outData']<=$outData) {
                $moveGroup = "update usergroup SET GroupName='user' WHERE 
UserName='".$row_ret['UserName']."'";
                if (@mysql_query($moveGroup)) {
                        echo "\tMoving ".$row_ret['UserName']." back to the General
 Population\n";
                } else { $mess=($mess. "Oops, something nasty happened updating the
 Radius Server Group membership");
                }
        } else { echo "\tLeaving ".$row_ret['UserName']." in punish\n"; }
} while ($row_ret = mysql_fetch_assoc($ret));
?>

you will need command line php to run this one.