Trial Period on Chillispot
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
- Your using the PHP version of the login page.(I can't do perl)
- You're RADIUS server is on the same server as the splash (UAM) server.
- Radius is using MySQL to store usernames etc.
Out sytem works like this, its free BUT:
- Users must register to use the system.
- Users must confrim their email address
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>
<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.
- the user name is hidden and php writes the mac addresss as the username
- the password field is hidden and the password set to guest encrypted.
- 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.
 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.