summaryrefslogtreecommitdiffstats
path: root/usr/local/captiveportal
diff options
context:
space:
mode:
Diffstat (limited to 'usr/local/captiveportal')
-rwxr-xr-xusr/local/captiveportal/index.php407
-rw-r--r--usr/local/captiveportal/radius_accounting.inc241
-rw-r--r--usr/local/captiveportal/radius_authentication.inc128
3 files changed, 776 insertions, 0 deletions
diff --git a/usr/local/captiveportal/index.php b/usr/local/captiveportal/index.php
new file mode 100755
index 0000000..c264625
--- /dev/null
+++ b/usr/local/captiveportal/index.php
@@ -0,0 +1,407 @@
+#!/usr/local/bin/php
+<?php
+/*
+ index.php
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require("globals.inc");
+require("util.inc");
+require("config.inc");
+require("radius_authentication.inc") ;
+require("radius_accounting.inc") ;
+
+header("Expires: 0");
+header("Cache-Control: no-store, no-cache, must-revalidate");
+header("Cache-Control: post-check=0, pre-check=0", false);
+header("Pragma: no-cache");
+
+$orig_host = $_ENV['HTTP_HOST'];
+$orig_request = $_ENV['CAPTIVE_REQPATH'];
+$lockfile = "{$g['varrun_path']}/captiveportal.lock";
+$clientip = $_ENV['REMOTE_ADDR'];
+
+if (!$clientip) {
+ /* not good - bail out */
+ exit;
+}
+
+/* find MAC address for client */
+$clientmac = arp_get_mac_by_ip($clientip);
+if (!$clientmac && !isset($config['captiveportal']['nomacfilter'])) {
+ /* unable to find MAC address - shouldn't happen! - bail out */
+ exit;
+}
+
+if ($clientmac && portal_mac_fixed($clientmac)) {
+ /* punch hole in ipfw for pass thru mac addresses */
+ portal_allow($clientip, $clientmac, "unauthenticated");
+
+} else if ($_POST['accept'] && file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
+
+ /* authenticate against radius server */
+ $radiusservers = captiveportal_get_radius_servers();
+
+ if ($_POST['auth_user'] && $_POST['auth_pass']) {
+ $auth_val = RADIUS_AUTHENTICATION($_POST['auth_user'],
+ $_POST['auth_pass'],
+ $radiusservers[0]['ipaddr'],
+ $radiusservers[0]['port'],
+ $radiusservers[0]['key']);
+ if ($auth_val == 2) {
+ $sessionid = portal_allow($clientip, $clientmac, $_POST['auth_user']);
+ if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
+ $auth_val = RADIUS_ACCOUNTING_START($_POST['auth_user'],
+ $sessionid,
+ $radiusservers[0]['ipaddr'],
+ $radiusservers[0]['acctport'],
+ $radiusservers[0]['key']);
+ }
+ } else {
+ readfile("{$g['varetc_path']}/captiveportal-error.html");
+ }
+ } else {
+ readfile("{$g['varetc_path']}/captiveportal-error.html");
+ }
+
+} else if ($_POST['accept'] && $clientip) {
+ portal_allow($clientip, $clientmac, "unauthenticated");
+} else if ($_POST['logout_id']) {
+ disconnect_client($_POST['logout_id']);
+ echo <<<EOD
+<HTML>
+<HEAD><TITLE>Disconnecting...</TITLE></HEAD>
+<BODY BGCOLOR="#435370">
+<SPAN STYLE="color: #ffffff; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">
+<B>You've been disconnected.</B>
+</SPAN>
+<SCRIPT LANGUAGE="JavaScript">
+<!--
+setTimeout('window.close();',5000) ;
+-->
+</SCRIPT>
+</BODY>
+</HTML>
+
+EOD;
+} else if (($_ENV['SERVER_PORT'] != 8001) && isset($config['captiveportal']['httpslogin'])) {
+ /* redirect to HTTPS login page */
+ header("Location: https://{$config['captiveportal']['httpsname']}:8001/?redirurl=" . urlencode("http://{$orig_host}{$orig_request}"));
+} else {
+ /* display captive portal page */
+ $htmltext = file_get_contents("{$g['varetc_path']}/captiveportal.html");
+
+ /* substitute variables */
+ if (isset($config['captiveportal']['httpslogin']))
+ $htmltext = str_replace("\$PORTAL_ACTION\$", "https://{$config['captiveportal']['httpsname']}:8001/", $htmltext);
+ else
+ $htmltext = str_replace("\$PORTAL_ACTION\$", "", $htmltext);
+
+ if (preg_match("/redirurl=(.*)/", $orig_request, $matches))
+ $redirurl = urldecode($matches[1]);
+ else
+ $redirurl = "http://{$orig_host}{$orig_request}";
+ $htmltext = str_replace("\$PORTAL_REDIRURL\$", htmlspecialchars($redirurl), $htmltext);
+
+ echo $htmltext;
+}
+
+exit;
+
+function portal_mac_fixed($clientmac) {
+ global $g ;
+
+ /* open captive portal mac db */
+ if (file_exists("{$g['vardb_path']}/captiveportal_mac.db")) {
+ $fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db","r") ;
+ if (!$fd) {
+ return FALSE;
+ }
+ while (!feof($fd)) {
+ $mac = trim(fgets($fd)) ;
+ if(strcasecmp($clientmac, $mac) == 0) {
+ fclose($fd) ;
+ return TRUE ;
+ }
+ }
+ fclose($fd) ;
+ }
+ return FALSE ;
+}
+
+function portal_allow($clientip,$clientmac,$clientuser) {
+
+ global $orig_host, $orig_request, $g, $config;
+
+ /* user has accepted AUP - let him in */
+ portal_lock();
+
+ /* get next ipfw rule number */
+ if (file_exists("{$g['vardb_path']}/captiveportal.nextrule"))
+ $ruleno = trim(file_get_contents("{$g['vardb_path']}/captiveportal.nextrule"));
+ if (!$ruleno)
+ $ruleno = 10000; /* first rule number */
+
+ $saved_ruleno = $ruleno;
+
+ /* generate unique session ID */
+ $tod = gettimeofday();
+ $sessionid = substr(md5(mt_rand() . $tod['sec'] . $tod['usec'] . $clientip . $clientmac), 0, 16);
+
+ /* add ipfw rules for layer 3 */
+ exec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from $clientip to any in");
+ exec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to $clientip out");
+
+ /* add ipfw rules for layer 2 */
+ if (!isset($config['captiveportal']['nomacfilter'])) {
+ $l2ruleno = $ruleno + 10000;
+ exec("/sbin/ipfw add $l2ruleno set 3 deny all from $clientip to any not MAC any $clientmac layer2 in");
+ exec("/sbin/ipfw add $l2ruleno set 3 deny all from any to $clientip not MAC $clientmac any layer2 out");
+ }
+
+ /* read in client database */
+ $cpdb = array();
+
+ $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
+ if ($fd) {
+ while (!feof($fd)) {
+ $line = trim(fgets($fd)) ;
+ if($line) {
+ $cpdb[] = explode(",",$line);
+ }
+ }
+ fclose($fd);
+ }
+
+ $radiusservers = captiveportal_get_radius_servers();
+
+ /* find an existing entry and delete it */
+ for ($i = 0; $i < count($cpdb); $i++) {
+ if(!strcasecmp($cpdb[$i][2],$clientip)) {
+ if(isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
+ RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
+ $cpdb[$i][4], // username
+ $cpdb[$i][5], // sessionid
+ $cpdb[$i][0], // start time
+ $radiusservers[0]['ipaddr'],
+ $radiusservers[0]['acctport'],
+ $radiusservers[0]['key']);
+ }
+ mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
+ unset($cpdb[$i]);
+ break;
+ }
+ }
+
+ /* rewrite information to database */
+ $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
+ if ($fd) {
+ foreach ($cpdb as $cpent) {
+ fwrite($fd, join(",", $cpent) . "\n");
+ }
+ /* write in this new entry */
+ fwrite($fd, time().",{$ruleno},{$clientip},{$clientmac},{$clientuser},{$sessionid}\n") ;
+ fclose($fd);
+ }
+
+ /* write next rule number */
+ $fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w");
+ if ($fd) {
+ $ruleno++;
+ if ($ruleno > 19899)
+ $ruleno = 10000; /* wrap around */
+ fwrite($fd, $ruleno);
+ fclose($fd);
+ }
+
+ portal_unlock();
+
+ /* redirect user to desired destination */
+ if ($config['captiveportal']['redirurl'])
+ $redirurl = $config['captiveportal']['redirurl'];
+ else if ($_POST['redirurl'])
+ $redirurl = $_POST['redirurl'];
+ else
+ $redirurl = "http://{$orig_host}{$orig_request}";
+
+ if(isset($config['captiveportal']['logoutwin_enable'])) {
+
+ if (isset($config['captiveportal']['httpslogin']))
+ $logouturl = "https://{$config['captiveportal']['httpsname']}:8001/";
+ else
+ $logouturl = "http://{$config['interfaces'][$config['captiveportal']['interface']]['ipaddr']}:8000/";
+
+ echo <<<EOD
+<HTML>
+<HEAD><TITLE>Redirecting...</TITLE></HEAD>
+<BODY>
+<SPAN STYLE="font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">
+<B>Redirecting to <A HREF="{$redirurl}">{$redirurl}</A>...</B>
+</SPAN>
+<SCRIPT LANGUAGE="JavaScript">
+<!--
+LogoutWin = window.open('', 'Logout', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=256,height=64');
+if (LogoutWin) {
+ LogoutWin.document.write('<HTML>');
+ LogoutWin.document.write('<HEAD><TITLE>Logout</TITLE></HEAD>') ;
+ LogoutWin.document.write('<BODY BGCOLOR="#435370">');
+ LogoutWin.document.write('<DIV ALIGN="center" STYLE="color: #ffffff; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">') ;
+ LogoutWin.document.write('<B>Click the button below to disconnect</B><P>');
+ LogoutWin.document.write('<FORM METHOD="POST" ACTION="{$logouturl}">');
+ LogoutWin.document.write('<INPUT NAME="logout_id" TYPE="hidden" VALUE="{$sessionid}">');
+ LogoutWin.document.write('<INPUT NAME="logout" TYPE="submit" VALUE="Logout">');
+ LogoutWin.document.write('</FORM>');
+ LogoutWin.document.write('</DIV></BODY>');
+ LogoutWin.document.write('</HTML>');
+ LogoutWin.document.close();
+}
+
+document.location.href="{$redirurl}";
+-->
+</SCRIPT>
+</BODY>
+</HTML>
+
+EOD;
+ } else {
+ header("Location: " . $redirurl);
+ }
+
+ return $sessionid;
+}
+
+/* read RADIUS servers into array */
+function captiveportal_get_radius_servers() {
+
+ global $g;
+
+ if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
+ $fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db","r");
+ if ($fd) {
+ $radiusservers = array();
+ while (!feof($fd)) {
+ $line = trim(fgets($fd));
+ if ($line) {
+ $radsrv = array();
+ list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
+ $radiusservers[] = $radsrv;
+ }
+ }
+ fclose($fd);
+
+ return $radiusservers;
+ }
+ }
+
+ return false;
+}
+
+/* lock captive portal information, decide that the lock file is stale after
+ 10 seconds */
+function portal_lock() {
+
+ global $lockfile;
+
+ $n = 0;
+ while ($n < 10) {
+ /* open the lock file in append mode to avoid race condition */
+ if ($fd = @fopen($lockfile, "x")) {
+ /* succeeded */
+ fclose($fd);
+ return;
+ } else {
+ /* file locked, wait and try again */
+ sleep(1);
+ $n++;
+ }
+ }
+}
+
+/* unlock captive portal information file */
+function portal_unlock() {
+
+ global $lockfile;
+
+ if (file_exists($lockfile))
+ unlink($lockfile);
+}
+
+/* remove a single client by session ID
+ by Dinesh Nair
+ */
+function disconnect_client($sessionid) {
+
+ global $g, $config;
+
+ portal_lock();
+
+ /* read database */
+ $cpdb = array() ;
+ $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
+ if ($fd) {
+ while (!feof($fd)) {
+ $line = trim(fgets($fd)) ;
+ if($line) {
+ $cpdb[] = explode(",",$line);
+ }
+ }
+ fclose($fd);
+ }
+
+ $radiusservers = captiveportal_get_radius_servers();
+
+ /* find entry */
+ for ($i = 0; $i < count($cpdb); $i++) {
+ if ($cpdb[$i][5] == $sessionid) {
+ /* this client needs to be deleted - remove ipfw rules */
+ if(isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
+ RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
+ $cpdb[$i][4], // username
+ $cpdb[$i][5], // sessionid
+ $cpdb[$i][0], // start time
+ $radiusservers[0]['ipaddr'],
+ $radiusservers[0]['acctport'],
+ $radiusservers[0]['key']);
+ }
+ mwexec("/sbin/ipfw delete " . $cpdb[$i][1] . " " . ($cpdb[$i][1]+10000));
+ unset($cpdb[$i]);
+ break;
+ }
+ }
+
+ /* rewrite information to database */
+ $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
+ if ($fd) {
+ foreach ($cpdb as $cpent) {
+ fwrite($fd, join(",", $cpent) . "\n");
+ }
+ fclose($fd);
+ }
+
+ portal_unlock();
+}
+?>
diff --git a/usr/local/captiveportal/radius_accounting.inc b/usr/local/captiveportal/radius_accounting.inc
new file mode 100644
index 0000000..7004971
--- /dev/null
+++ b/usr/local/captiveportal/radius_accounting.inc
@@ -0,0 +1,241 @@
+<?php
+/*
+ radius_accounting.inc
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2004 Dinesh Nair <dinesh@alphaque.com>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+function RADIUS_ACCOUNTING_START($username,$sessionid,$radiusip,$radiusport,$radiuskey) {
+ $sharedsecret=$radiuskey ;
+ # $debug = 1 ;
+
+ exec("/bin/hostname", $nasHostname) ;
+ if(!$nasHostname[0])
+ $nasHostname[0] = "m0n0wall" ;
+
+ $fd = @fsockopen("udp://$radiusip",$radiusport,$errno,$errstr,3) ;
+ if(!$fd)
+ return 1 ; /* error return */
+
+ /* set 5 second timeout on socket i/o */
+ stream_set_timeout($fd, 5) ;
+
+ if ($debug)
+ echo "<br>radius-port: $radiusport<br>radius-host: $radiusip<br>username: $username<hr>\n";
+
+ $thisidentifier=rand()%256;
+
+ $length=4+ // header
+ 16+ // auth code
+ 6+ // service type
+ 2+strlen($username)+ // username
+ 2+strlen($nasHostname[0])+ // nasIdentifier
+ 6+ // nasPort
+ 6+ // nasPortType
+ 6+ // Acct Status Type
+ 6+ // Acct RADIUS Authenticated
+ 2+strlen($sessionid); // Acct SessionID
+
+ // v v v v v v v v v 1 v
+ // Line # 1 2 3 4 5 6 7 8 9 0 E
+ $data=pack("CCCCNNNNCCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*",
+ 4,$thisidentifier,$length/256,$length%256, // header
+ 0,0,0,0, // authcode
+ 6,6,0,0,0,1, // service type
+ 1,2+strlen($username),$username, // username
+ 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier
+ 5,6,0,0,0,0, // nasPort
+ 61,6,0,0,0,15, // nasPortType = Ethernet
+ 40,6,0,0,0,1, // Acct Status Type = Start
+ 45,6,0,0,0,1, // Acct RADIUS Authenticated
+ 44,2+strlen($sessionid),$sessionid // Acct Session ID
+ );
+
+ /* Generate Accounting Request Authenticator */
+ $RA = md5($data.$radiuskey) ;
+
+ // v v v v v v v v v 1 v
+ // Line # 1 2 3 4 5 6 7 8 9 0 E
+ $data=pack("CCCCH*CCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*",
+ 4,$thisidentifier,$length/256,$length%256, // header
+ $RA, // authcode
+ 6,6,0,0,0,1, // service type
+ 1,2+strlen($username),$username, // username
+ 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier
+ 5,6,0,0,0,0, // nasPort
+ 61,6,0,0,0,15, // nasPortType = Ethernet
+ 40,6,0,0,0,1, // Acct Status Type = Start
+ 45,6,0,0,0,1, // Acct RADIUS Authenticated
+ 44,2+strlen($sessionid),$sessionid // Acct Session ID
+ );
+
+ if($debug) {
+ echo "username is $username with len " . strlen($username) ."\n" ;
+ echo "nasHostname is {$nasHostname[0]} with len " . strlen($nasHostname[0]) ."\n" ;
+ }
+
+ $ret = fwrite($fd,$data) ;
+ if( !$ret || ($ret != $length) )
+ return 1; /* error return */
+
+ if ($debug)
+ echo "<br>writing $length bytes<hr>\n";
+
+ $readdata = fgets($fd,2) ; /* read 1 byte */
+ $status = socket_get_status($fd) ;
+ fclose($fd) ;
+
+ if($status['timed_out'])
+ $retvalue = 1 ;
+ else
+ $retvalue = ord($readdata) ;
+
+ return $retvalue ;
+ // 5 -> Accounting-Response
+ // See RFC2866 for this.
+}
+
+function RADIUS_ACCOUNTING_STOP($ruleno,$username,$sessionid,$start_time,$radiusip,$radiusport,$radiuskey) {
+ $sharedsecret=$radiuskey ;
+ # $debug = 1 ;
+
+ exec("/bin/hostname", $nasHostname) ;
+ if(!$nasHostname[0])
+ $nasHostname[0] = "quewall" ;
+
+ $input_pkts = $input_bytes = $output_pkts = $output_bytes = 0 ;
+
+ exec("/sbin/ipfw show {$ruleno}", $ipfw) ;
+ preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[0], $matches) ;
+ $output_pkts = $matches[2] ;
+ $output_bytes = $matches[3] ;
+
+ unset($matches) ;
+ preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[1], $matches) ;
+ $input_pkts = $matches[2] ;
+ $input_bytes = $matches[3] ;
+
+ $fd = @fsockopen("udp://$radiusip",$radiusport,$errno,$errstr,3) ;
+ if(!$fd)
+ return 1 ; /* error return */
+
+ /* set 5 second timeout on socket i/o */
+ stream_set_timeout($fd, 5) ;
+
+ if ($debug)
+ echo "<br>radius-port: $radiusport<br>radius-host: $radiusip<br>username: $username<hr>\n";
+
+ $thisidentifier=rand()%256;
+
+ $length=4+ // header
+ 16+ // auth code
+ 6+ // service type
+ 2+strlen($username)+ // username
+ 2+strlen($nasHostname[0])+ // nasIdentifier
+ 6+ // nasPort
+ 6+ // nasPortType
+ 6+ // Acct Status Type
+ 6+ // Acct RADIUS Authenticated
+ 2+strlen($sessionid)+ // Acct SessionID
+ 6+ // Acct terminate
+ 6+ // Session time
+ 6+ // input bytes
+ 6+ // input packets
+ 6+ // output bytes
+ 6; // output packets
+
+ // v v v v v v v v v 1 1 1 1 1 1 1 v
+ // Line # 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 E
+ $data=pack("CCCCNNNNCCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCNCCNCCNCCNCCNCCN",
+ 4,$thisidentifier,$length/256,$length%256, // header
+ 0,0,0,0, // authcode
+ 6,6,0,0,0,1, // service type
+ 1,2+strlen($username),$username, // username
+ 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier
+ 5,6,0,0,0,0, // nasPort
+ 61,6,0,0,0,15, // nasPortType = Ethernet
+ 40,6,0,0,0,2, // Acct Status Type = Stop
+ 45,6,0,0,0,1, // Acct RADIUS Authenticated
+ 44,2+strlen($sessionid),$sessionid, // Acct Session ID
+ 49,6,1, // Acct Terminate = User Request
+ 46,6,time() - $start_time, // Session Time
+ 42,6,$input_bytes, // Input Octets
+ 47,6,$input_pkts, // Input Packets
+ 43,6,$output_bytes, // Output Octets
+ 48,6,$output_pkts // Output Packets
+ );
+
+ /* Generate Accounting Request Authenticator */
+ $RA = md5($data.$radiuskey) ;
+
+ // v v v v v v v v v 1 1 1 1 1 1 1 v
+ // Line # 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 E
+ $data=pack("CCCCH*CCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCNCCNCCNCCNCCNCCN",
+ 4,$thisidentifier,$length/256,$length%256, // header
+ $RA, // authcode
+ 6,6,0,0,0,1, // service type
+ 1,2+strlen($username),$username, // username
+ 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier
+ 5,6,0,0,0,0, // nasPort
+ 61,6,0,0,0,15, // nasPortType = Ethernet
+ 40,6,0,0,0,2, // Acct Status Type = Stop
+ 45,6,0,0,0,1, // Acct RADIUS Authenticated
+ 44,2+strlen($sessionid),$sessionid, // Acct Session ID
+ 49,6,1, // Acct Terminate = User Request
+ 46,6,time() - $start_time, // Session Time
+ 42,6,$input_bytes, // Input Octets
+ 47,6,$input_pkts, // Input Packets
+ 43,6,$output_bytes, // Output Octets
+ 48,6,$output_pkts // Output Packets
+ );
+
+ if($debug) {
+ echo "username is $username with len " . strlen($username) ."\n" ;
+ echo "nasHostname is {$nasHostname[0]} with len " . strlen($nasHostname[0]) ."\n" ;
+ }
+
+ $ret = fwrite($fd,$data) ;
+ if( !$ret || ($ret != $length) )
+ return 1; /* error return */
+
+ if ($debug)
+ echo "<br>writing $length bytes<hr>\n";
+
+ $readdata = fgets($fd,2) ; /* read 1 byte */
+ $status = socket_get_status($fd) ;
+ fclose($fd) ;
+
+ if($status['timed_out'])
+ $retvalue = 1 ;
+ else
+ $retvalue = ord($readdata) ;
+
+ return $retvalue ;
+ // 5 -> Accounting-Response
+ // See RFC2866 for this.
+}
+?>
diff --git a/usr/local/captiveportal/radius_authentication.inc b/usr/local/captiveportal/radius_authentication.inc
new file mode 100644
index 0000000..c106da3
--- /dev/null
+++ b/usr/local/captiveportal/radius_authentication.inc
@@ -0,0 +1,128 @@
+<?php
+ //
+ // $Id$
+ //
+ // radius authentication v1.0 by Edwin Groothuis (edwin@mavetju.org)
+ //
+ // If you didn't get this file via http://www.mavetju.org, please
+ // check for the availability of newer versions.
+ //
+ // See LICENSE for distribution issues. If this file isn't in
+ // the distribution, please inform me about it.
+ //
+ // If you want to use this script, fill in the configuration in
+ // radius_authentication.conf and call the function
+ // RADIUS_AUTHENTICATION() with the username and password
+ // provided by the user. If it returns a 2, the authentication
+ // was successfull!
+
+ // If you want to use this, make sure that you have raw sockets
+ // enabled during compile-time: "./configure --enable-sockets".
+
+ // This version has been modified by Dinesh Nair <dinesh@alphaque.com>
+ // for use in the m0n0wall distribution http://m0n0.ch/wall/
+ //
+ // Changes include moving from raw sockets to fsockopen
+ // and the removal of dependency on external conf file
+ // An existing bug which resulted in a malformed RADIUS packet
+ // was also fixed and patches submitted to Edwin. This bug would
+ // have caused authentication to fail on every access.
+
+function RADIUS_AUTHENTICATION($username,$password,$radiusip,$radiusport,$radiuskey) {
+ $sharedsecret=$radiuskey ;
+ # $debug = 1 ;
+
+ exec("/bin/hostname", $nasHostname) ;
+ if(!$nasHostname[0])
+ $nasHostname[0] = "m0n0wall" ;
+
+ $fd = @fsockopen("udp://$radiusip",$radiusport,$errno,$errstr,3) ;
+ if(!$fd)
+ return 1 ; /* error return */
+
+ /* set 5 second timeout on socket i/o */
+ stream_set_timeout($fd, 5) ;
+
+ if ($debug)
+ echo "<br>radius-port: $radiusport<br>radius-host: $radiusip<br>username: $username<hr>\n";
+
+ $RA=pack("CCCCCCCCCCCCCCCC", // auth code
+ 1+rand()%255, 1+rand()%255, 1+rand()%255, 1+rand()%255,
+ 1+rand()%255, 1+rand()%255, 1+rand()%255, 1+rand()%255,
+ 1+rand()%255, 1+rand()%255, 1+rand()%255, 1+rand()%255,
+ 1+rand()%255, 1+rand()%255, 1+rand()%255, 1+rand()%255);
+
+ $encryptedpassword=Encrypt($password,$sharedsecret,$RA);
+
+ $length=4+ // header
+ 16+ // auth code
+ 6+ // service type
+ 2+strlen($username)+ // username
+ 2+strlen($encryptedpassword)+ // userpassword
+ 2+strlen($nasHostname[0])+ // nasIdentifier
+ 6+ // nasPort
+ 6; // nasPortType
+
+ $thisidentifier=rand()%256;
+ // v v v v v v v v v
+ // Line # 1 2 3 4 5 6 7 8 E
+ $data=pack("CCCCa*CCCCCCCCa*CCa*CCa*CCCCCCCCCCCC",
+ 1,$thisidentifier,$length/256,$length%256, // header
+ $RA, // authcode
+ 6,6,0,0,0,1, // service type
+ 1,2+strlen($username),$username, // username
+ 2,2+strlen($encryptedpassword),$encryptedpassword, // userpassword
+ 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier
+ 5,6,0,0,0,0, // nasPort
+ 61,6,0,0,0,15 // nasPortType = Ethernet
+ );
+
+ if($debug) {
+ echo "username is $username with len " . strlen($username) ."\n" ;
+ echo "encryptedpassword is $encryptedpassword with len " . strlen($encryptedpassword) ."\n" ;
+ echo "nasHostname is {$nasHostname[0]} with len " . strlen($nasHostname[0]) ."\n" ;
+ }
+
+ $ret = fwrite($fd,$data) ;
+ if( !$ret || ($ret != $length) )
+ return 1; /* error return */
+
+ if ($debug)
+ echo "<br>writing $length bytes<hr>\n";
+
+ $readdata = fgets($fd,2) ; /* read 1 byte */
+ $status = socket_get_status($fd) ;
+ fclose($fd) ;
+
+ if($status['timed_out'])
+ $retvalue = 1 ;
+ else
+ $retvalue = ord($readdata) ;
+
+ return $retvalue ;
+ // 2 -> Access-Accept
+ // 3 -> Access-Reject
+ // See RFC2865 for this.
+}
+
+function Encrypt($password,$key,$RA) {
+ global $debug;
+
+ $keyRA=$key.$RA;
+
+ if ($debug)
+ echo "<br>key: $key<br>password: $password<hr>\n";
+
+ $md5checksum=md5($keyRA);
+ $output="";
+
+ for ($i=0;$i<=15;$i++) {
+ if (2*$i>strlen($md5checksum)) $m=0; else $m=hexdec(substr($md5checksum,2*$i,2));
+ if ($i>strlen($keyRA)) $k=0; else $k=ord(substr($keyRA,$i,1));
+ if ($i>strlen($password)) $p=0; else $p=ord(substr($password,$i,1));
+ $c=$m^$p;
+ $output.=chr($c);
+ }
+ return $output;
+}
+?>
OpenPOWER on IntegriCloud