diff options
author | Scott Ullrich <sullrich@pfsense.org> | 2006-08-24 17:01:26 +0000 |
---|---|---|
committer | Scott Ullrich <sullrich@pfsense.org> | 2006-08-24 17:01:26 +0000 |
commit | 36254e4a000239342d2acbac8dd4fbca7dc54bd5 (patch) | |
tree | e9ac8416013731e832a55c8eb37f84fc29af9655 | |
parent | 4f652345020ae228ff7a29ee777c7b2290e994f7 (diff) | |
download | pfsense-36254e4a000239342d2acbac8dd4fbca7dc54bd5.zip pfsense-36254e4a000239342d2acbac8dd4fbca7dc54bd5.tar.gz |
Carefully sync captive portal against m0n0wall 1.22
-rw-r--r-- | etc/inc/captiveportal.inc | 917 |
1 files changed, 504 insertions, 413 deletions
diff --git a/etc/inc/captiveportal.inc b/etc/inc/captiveportal.inc index 28af59f..2e56b64 100644 --- a/etc/inc/captiveportal.inc +++ b/etc/inc/captiveportal.inc @@ -2,20 +2,20 @@ /* captiveportal.inc part of m0n0wall (http://m0n0.ch/wall) - + Copyright (C) 2003-2006 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 @@ -33,7 +33,7 @@ added rules which may have been created by other per-user code (index.php, etc). These changes are (c) 2004 Keycom PLC. */ - + /* include all configuration functions */ require_once("functions.inc"); require_once("radius_authentication.inc"); @@ -43,27 +43,27 @@ $lockfile = "{$g['varrun_path']}/captiveportal.lock"; function captiveportal_configure() { global $config, $g; - + if (isset($config['captiveportal']['enable']) && (($config['captiveportal']['interface'] == "lan") || isset($config['interfaces'][$config['captiveportal']['interface']]['enable']))) { - + if ($g['booting']) echo "Starting captive portal... "; - + /* kill any running mini_httpd */ killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid"); killbypid("{$g['varrun_path']}/lighty-CaptivePortal-SSL.pid"); - + /* kill any running minicron */ killbypid("{$g['varrun_path']}/minicron.pid"); - + /* generate ipfw rules */ $cprules = captiveportal_rules_generate(); - + /* make sure ipfw is loaded */ mwexec("/sbin/kldload ipfw"); - + /* stop accounting on all clients */ captiveportal_radius_stop_all(); @@ -74,12 +74,11 @@ function captiveportal_configure() { if ((!is_numeric($croninterval)) || ($croninterval < 10)) { $croninterval = 60; } /* remove old information */ - unlink_if_exists("{$g['vardb_path']}/captiveportal.nextrule"); - unlink_if_exists("{$g['vardb_path']}/captiveportal.db"); - unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db"); - unlink_if_exists("{$g['vardb_path']}/captiveportal_ip.db"); - unlink_if_exists("{$g['vardb_path']}/captiveportal_radius.db"); - + unlink_if_exists("{$g['vardb_path']}/captiveportal.db"); + unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db"); + unlink_if_exists("{$g['vardb_path']}/captiveportal_ip.db"); + unlink_if_exists("{$g['vardb_path']}/captiveportal_radius.db"); + /* write portal page */ if ($config['captiveportal']['page']['htmltext']) $htmltext = base64_decode($config['captiveportal']['page']['htmltext']); @@ -120,9 +119,9 @@ EOD; $fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w"); if ($fd) { fwrite($fd, $htmltext); - fclose($fd); + fclose($fd); } - + /* write error page */ if ($config['captiveportal']['page']['errtext']) $errtext = base64_decode($config['captiveportal']['page']['errtext']); @@ -149,9 +148,9 @@ EOD; $fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w"); if ($fd) { fwrite($fd, $errtext); - fclose($fd); + fclose($fd); } - + /* write elements */ captiveportal_write_elements(); @@ -159,7 +158,7 @@ EOD; mwexec("/sbin/ipfw -f delete set 1"); mwexec("/sbin/ipfw -f delete set 2"); mwexec("/sbin/ipfw -f delete set 3"); - + /* ipfw cannot accept rules directly on stdin, so we have to write them to a temporary file first */ $fd = @fopen("{$g['tmp_path']}/ipfw.cp.rules", "w"); @@ -167,19 +166,19 @@ EOD; printf("Cannot open ipfw.cp.rules in captiveportal_configure()\n"); return 1; } - + fwrite($fd, $cprules); fclose($fd); - + mwexec("/sbin/ipfw {$g['tmp_path']}/ipfw.cp.rules"); - + unlink("{$g['tmp_path']}/ipfw.cp.rules"); - + /* filter on layer2 as well so we can check MAC addresses */ mwexec("/sbin/sysctl net.link.ether.ipfw=1"); - + chdir($g['captiveportal_path']); - + /* TEMPORARY! FAST_CGI reports _FALSE_ client ip * addresses. */ @@ -189,7 +188,7 @@ EOD; $maxproc = $config['captiveportal']['maxproc']; else $maxproc = 16; - + if(isset($config['captiveportal']['httpslogin'])) { $cert = base64_decode($config['captiveportal']['certificate']); $key = base64_decode($config['captiveportal']['private-key']); @@ -198,68 +197,68 @@ EOD; $cert, $key, "lighty-CaptivePortal-ssl.pid", "8001", "/usr/local/captiveportal/", "cert-portal.pem", "1", $maxproc, $use_fastcgi, true); } - + /* generate lighttpd configuration */ system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal.conf", "", "", "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/", "cert-portal.pem", "1", $maxproc, $use_fastcgi, true); - + /* attempt to start lighttpd */ $res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal.conf"); - + /* fire up https instance */ if(isset($config['captiveportal']['httpslogin'])) $res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal-SSL.conf"); - + /* start pruning process (interval defaults to 60 seconds) */ mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/minicron.pid " . "/etc/rc.prunecaptiveportal"); - + /* generate passthru mac database */ captiveportal_passthrumac_configure(); /* create allowed ip database and insert ipfw rules to make it so */ captiveportal_allowedip_configure(); - - /* generate radius server database */ - if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) || - ($config['captiveportal']['auth_method'] == "radius"))) { - $radiusip = $config['captiveportal']['radiusip']; - $radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null; - - if ($config['captiveportal']['radiusport']) - $radiusport = $config['captiveportal']['radiusport']; - else - $radiusport = 1812; - - if ($config['captiveportal']['radiusacctport']) - $radiusacctport = $config['captiveportal']['radiusacctport']; - else - $radiusacctport = 1813; - - if ($config['captiveportal']['radiusport2']) - $radiusport2 = $config['captiveportal']['radiusport2']; - else - $radiusport2 = 1812; - - $radiuskey = $config['captiveportal']['radiuskey']; - $radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null; - - $fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w"); - if (!$fd) { - printf("Error: cannot open radius DB file in captiveportal_configure().\n"); - return 1; - } else if (isset($radiusip2, $radiuskey2)) { - fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n" - . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2); - } else { - fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey); - } - fclose($fd); - } - if ($g['booting']) - echo "done\n"; - + /* generate radius server database */ + if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) || + ($config['captiveportal']['auth_method'] == "radius"))) { + $radiusip = $config['captiveportal']['radiusip']; + $radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null; + + if ($config['captiveportal']['radiusport']) + $radiusport = $config['captiveportal']['radiusport']; + else + $radiusport = 1812; + + if ($config['captiveportal']['radiusacctport']) + $radiusacctport = $config['captiveportal']['radiusacctport']; + else + $radiusacctport = 1813; + + if ($config['captiveportal']['radiusport2']) + $radiusport2 = $config['captiveportal']['radiusport2']; + else + $radiusport2 = 1812; + + $radiuskey = $config['captiveportal']['radiuskey']; + $radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null; + + $fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w"); + if (!$fd) { + printf("Error: cannot open radius DB file in captiveportal_configure().\n"); + return 1; + } else if (isset($radiusip2, $radiuskey2)) { + fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n" + . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2); + } else { + fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey); + } + fclose($fd); + } + + if ($g['booting']) + echo "done\n"; + } else { killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid"); killbypid("{$g['varrun_path']}/minicron.pid"); @@ -278,13 +277,13 @@ EOD; mwexec("/sbin/ipfw -f delete set 3"); } } - + return 0; } function captiveportal_rules_generate() { global $config, $g; - + $cpifn = $config['captiveportal']['interface']; $cpif = $config['interfaces'][$cpifn]['if']; $cpip = $config['interfaces'][$cpifn]['ipaddr']; @@ -299,15 +298,15 @@ function captiveportal_rules_generate() { */ $iflist = array("lan" => "LAN", "wan" => "WAN"); $captive_portal_interface = strtoupper($cpifn); - for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) - $iflist['opt' . $i] = "OPT{$i}"; + for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) + $iflist['opt' . $i] = "OPT{$i}"; foreach ($iflist as $ifent => $ifname) { if($captive_portal_interface == strtoupper($ifname)) continue; $int = convert_friendly_interface_to_real_interface_name($ifname); $cprules .= "add 30 set 1 skipto 50000 all from any to any in via {$int} keep-state\n"; } - + /* captive portal on LAN interface? */ if ($cpifn == "lan") { /* add anti-lockout rules */ @@ -329,7 +328,7 @@ add 1100 set 1 pass layer2 mac-type arp # pfsense requires for WPA add 1100 set 1 pass layer2 mac-type 0x888e -# PPP Over Ethernet Discovery Stage +# PPP Over Ethernet Discovery Stage add 1100 set 1 pass layer2 mac-type 0x8863 # PPP Over Ethernet Session Stage add 1100 set 1 pass layer2 mac-type 0x8864 @@ -363,7 +362,7 @@ add 1305 set 1 pass tcp from $cpip 8001 to any out EOD; } - + $cprules .= <<<EOD # ... 10000-19899: rules per authenticated client go here... @@ -396,265 +395,265 @@ EOD; } /* remove clients that have been around for longer than the specified amount of time */ -/* db file structure: +/* db file structure: timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time */ /* (password is in Base64 and only saved when reauthentication is enabled) */ function captiveportal_prune_old() { - - global $g, $config; - - /* check for expired entries */ - if ($config['captiveportal']['timeout']) - $timeout = $config['captiveportal']['timeout'] * 60; - else - $timeout = 0; - - if ($config['captiveportal']['idletimeout']) - $idletimeout = $config['captiveportal']['idletimeout'] * 60; - else - $idletimeout = 0; - - if (!$timeout && !$idletimeout && !isset($config['captiveportal']['reauthenticate'])) - return; - - captiveportal_lock(); - - /* read database */ - $cpdb = captiveportal_read_db(); - - $radiusservers = captiveportal_get_radius_servers(); - - for ($i = 0; $i < count($cpdb); $i++) { - - $timedout = false; - $term_cause = 1; - - /* hard timeout? */ - if ($timeout) { - if ((time() - $cpdb[$i][0]) >= $timeout) { - $timedout = true; - $term_cause = 5; // Session-Timeout - } - } - /* Session-Terminate-Time */ - if (!$timedout && !empty($cpdb[$i][9])) { - if (time() >= $cpdb[$i][9]) { - $timedout = true; - $term_cause = 5; // Session-Timeout - } - } - - /* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */ - $idletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout; - /* if an idle timeout is specified, get last activity timestamp from ipfw */ - if (!$timedout && $idletimeout) { - $lastact = captiveportal_get_last_activity($cpdb[$i][1]); - if ($lastact && ((time() - $lastact) >= $idletimeout)) { - $timedout = true; - $term_cause = 4; // Idle-Timeout - $stop_time = $lastact; // Entry added to comply with WISPr - } - } + global $g, $config; - /* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */ - if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpdb[$i][7])) { - if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) { - $timedout = true; - $term_cause = 5; // Session-Timeout - } - } - - if ($timedout) { - captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time); - captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "TIMEOUT"); - unset($cpdb[$i]); - } - - /* do periodic RADIUS reauthentication? */ - if (!$timedout && isset($config['captiveportal']['reauthenticate']) && - ($radiusservers !== false)) { - - if (isset($config['captiveportal']['radacct_enable'])) { - if ($config['captiveportal']['reauthenticateacct'] == "stopstart") { - /* stop and restart accounting */ - 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'], - $cpdb[$i][2], // clientip - $cpdb[$i][3], // clientmac - 10); // NAS Request - exec("/sbin/ipfw zero {$cpdb[$i][1]}"); - RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno - $cpdb[$i][4], // username - $cpdb[$i][5], // sessionid - $radiusservers[0]['ipaddr'], - $radiusservers[0]['acctport'], - $radiusservers[0]['key'], - $cpdb[$i][2], // clientip - $cpdb[$i][3]); // clientmac - } else if ($config['captiveportal']['reauthenticateacct'] == "interimupdate") { - 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'], - $cpdb[$i][2], // clientip - $cpdb[$i][3], // clientmac - 10, // NAS Request - true); // Interim Updates - } - } - - /* check this user against RADIUS again */ - $auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username - base64_decode($cpdb[$i][6]), // password - $radiusservers, - $cpdb[$i][2], // clientip - $cpdb[$i][3], // clientmac - $cpdb[$i][1]); // ruleno - - if ($auth_list['auth_val'] == 3) { - captiveportal_disconnect($cpdb[$i], $radiusservers, 17); - captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT", $auth_list['reply_message']); - unset($cpdb[$i]); - } - } - } - - /* write database */ - captiveportal_write_db($cpdb); - - captiveportal_unlock(); + /* check for expired entries */ + if ($config['captiveportal']['timeout']) + $timeout = $config['captiveportal']['timeout'] * 60; + else + $timeout = 0; + + if ($config['captiveportal']['idletimeout']) + $idletimeout = $config['captiveportal']['idletimeout'] * 60; + else + $idletimeout = 0; + + if (!$timeout && !$idletimeout && !isset($config['captiveportal']['reauthenticate']) && !isset($config['captiveportal']['radiussession_timeout'])) + return; + + captiveportal_lock(); + + /* read database */ + $cpdb = captiveportal_read_db(); + + $radiusservers = captiveportal_get_radius_servers(); + + for ($i = 0; $i < count($cpdb); $i++) { + + $timedout = false; + $term_cause = 1; + + /* hard timeout? */ + if ($timeout) { + if ((time() - $cpdb[$i][0]) >= $timeout) { + $timedout = true; + $term_cause = 5; // Session-Timeout + } + } + + /* Session-Terminate-Time */ + if (!$timedout && !empty($cpdb[$i][9])) { + if (time() >= $cpdb[$i][9]) { + $timedout = true; + $term_cause = 5; // Session-Timeout + } + } + + /* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */ + $idletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout; + /* if an idle timeout is specified, get last activity timestamp from ipfw */ + if (!$timedout && $idletimeout) { + $lastact = captiveportal_get_last_activity($cpdb[$i][1]); + if ($lastact && ((time() - $lastact) >= $idletimeout)) { + $timedout = true; + $term_cause = 4; // Idle-Timeout + $stop_time = $lastact; // Entry added to comply with WISPr + } + } + + /* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */ + if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpdb[$i][7])) { + if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) { + $timedout = true; + $term_cause = 5; // Session-Timeout + } + } + + if ($timedout) { + captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time); + captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "TIMEOUT"); + unset($cpdb[$i]); + } + + /* do periodic RADIUS reauthentication? */ + if (!$timedout && isset($config['captiveportal']['reauthenticate']) && + ($radiusservers !== false)) { + + if (isset($config['captiveportal']['radacct_enable'])) { + if ($config['captiveportal']['reauthenticateacct'] == "stopstart") { + /* stop and restart accounting */ + 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'], + $cpdb[$i][2], // clientip + $cpdb[$i][3], // clientmac + 10); // NAS Request + exec("/sbin/ipfw zero {$cpdb[$i][1]}"); + RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno + $cpdb[$i][4], // username + $cpdb[$i][5], // sessionid + $radiusservers[0]['ipaddr'], + $radiusservers[0]['acctport'], + $radiusservers[0]['key'], + $cpdb[$i][2], // clientip + $cpdb[$i][3]); // clientmac + } else if ($config['captiveportal']['reauthenticateacct'] == "interimupdate") { + 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'], + $cpdb[$i][2], // clientip + $cpdb[$i][3], // clientmac + 10, // NAS Request + true); // Interim Updates + } + } + + /* check this user against RADIUS again */ + $auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username + base64_decode($cpdb[$i][6]), // password + $radiusservers, + $cpdb[$i][2], // clientip + $cpdb[$i][3], // clientmac + $cpdb[$i][1]); // ruleno + + if ($auth_list['auth_val'] == 3) { + captiveportal_disconnect($cpdb[$i], $radiusservers, 17); + captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT", $auth_list['reply_message']); + unset($cpdb[$i]); + } + } + } + + /* write database */ + captiveportal_write_db($cpdb); + + captiveportal_unlock(); } /* remove a single client according to the DB entry */ function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_time = null) { - - global $g, $config; - - $stop_time = (empty($stop_time)) ? time() : $stop_time; - - /* this client needs to be deleted - remove ipfw rules */ - if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) { - RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno - $dbent[4], // username - $dbent[5], // sessionid - $dbent[0], // start time - $radiusservers[0]['ipaddr'], - $radiusservers[0]['acctport'], - $radiusservers[0]['key'], - $dbent[2], // clientip - $dbent[3], // clientmac - $term_cause, // Acct-Terminate-Cause - false, - $stop_time); - } - - mwexec("/sbin/ipfw delete " . $dbent[1] . " " . ($dbent[1]+10000)); - - //KEYCOM: we need to delete +40500 and +45500 as well... - //these are the rule numbers we use to control traffic shaping for each logged in user via captive portal - //we only need to remove our rules if peruserbw is turned on. - if (isset($config['captiveportal']['peruserbw'])) { - mwexec("/sbin/ipfw delete " . ($dbent[1]+40500)); - mwexec("/sbin/ipfw delete " . ($dbent[1]+45500)); - } + + global $g, $config; + + $stop_time = (empty($stop_time)) ? time() : $stop_time; + + /* this client needs to be deleted - remove ipfw rules */ + if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) { + RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno + $dbent[4], // username + $dbent[5], // sessionid + $dbent[0], // start time + $radiusservers[0]['ipaddr'], + $radiusservers[0]['acctport'], + $radiusservers[0]['key'], + $dbent[2], // clientip + $dbent[3], // clientmac + $term_cause, // Acct-Terminate-Cause + false, + $stop_time); + } + + mwexec("/sbin/ipfw delete " . $dbent[1] . " " . ($dbent[1]+10000)); + + //KEYCOM: we need to delete +40500 and +45500 as well... + //these are the rule numbers we use to control traffic shaping for each logged in user via captive portal + //we only need to remove our rules if peruserbw is turned on. + if (isset($config['captiveportal']['peruserbw'])) { + mwexec("/sbin/ipfw delete " . ($dbent[1]+40500)); + mwexec("/sbin/ipfw delete " . ($dbent[1]+45500)); + } } /* remove a single client by ipfw rule number */ function captiveportal_disconnect_client($id,$term_cause = 1) { - - global $g, $config; - - captiveportal_lock(); - - /* read database */ - $cpdb = captiveportal_read_db(); - $radiusservers = captiveportal_get_radius_servers(); - - /* find entry */ - for ($i = 0; $i < count($cpdb); $i++) { - if ($cpdb[$i][1] == $id) { - captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause); - captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT"); - unset($cpdb[$i]); - break; - } - } - - /* write database */ - captiveportal_write_db($cpdb); - - captiveportal_unlock(); + + global $g, $config; + + captiveportal_lock(); + + /* read database */ + $cpdb = captiveportal_read_db(); + $radiusservers = captiveportal_get_radius_servers(); + + /* find entry */ + for ($i = 0; $i < count($cpdb); $i++) { + if ($cpdb[$i][1] == $id) { + captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause); + captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT"); + unset($cpdb[$i]); + break; + } + } + + /* write database */ + captiveportal_write_db($cpdb); + + captiveportal_unlock(); } /* send RADIUS acct stop for all current clients */ function captiveportal_radius_stop_all() { - global $g, $config; - - if (!isset($config['captiveportal']['radacct_enable'])) - return; - - captiveportal_lock(); - $cpdb = captiveportal_read_db(); - - $radiusservers = captiveportal_get_radius_servers(); - - if (isset($radiusservers[0])) { - for ($i = 0; $i < count($cpdb); $i++) { - 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'], - $cpdb[$i][2], // clientip - $cpdb[$i][3], // clientmac - 7); // Admin Reboot - } - } - captiveportal_unlock(); + global $g, $config; + + if (!isset($config['captiveportal']['radacct_enable'])) + return; + + captiveportal_lock(); + $cpdb = captiveportal_read_db(); + + $radiusservers = captiveportal_get_radius_servers(); + + if (isset($radiusservers[0])) { + for ($i = 0; $i < count($cpdb); $i++) { + 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'], + $cpdb[$i][2], // clientip + $cpdb[$i][3], // clientmac + 7); // Admin Reboot + } + } + captiveportal_unlock(); } function captiveportal_passthrumac_configure() { global $config, $g; - + captiveportal_lock(); - + /* clear out passthru macs, if necessary */ unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db"); - + if (is_array($config['captiveportal']['passthrumac'])) { - + $fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db", "w"); if (!$fd) { printf("Error: cannot open passthru mac DB file in captiveportal_passthrumac_configure().\n"); captiveportal_unlock(); - return 1; + return 1; } - + foreach ($config['captiveportal']['passthrumac'] as $macent) { /* record passthru mac so it can be recognized and let thru */ fwrite($fd, $macent['mac'] . "\n"); } - - fclose($fd); + + fclose($fd); } /* pass through mac entries should always exist. the reason * for this is because we do not have native mac address filtering * mechanisms. this allows us to filter by mac address easily * and get around this limitation. I consider this a bug in - * m0n0wall and pfSense as m0n0wall does not have native mac + * m0n0wall and pfSense as m0n0wall does not have native mac * filtering mechanisms as well. -Scott Ullrich */ if (is_array($config['captiveportal']['passthrumac'])) { @@ -668,13 +667,13 @@ function captiveportal_passthrumac_configure() { } captiveportal_unlock(); - + return 0; } function captiveportal_allowedip_configure() { global $config, $g; - + captiveportal_lock(); /* clear out existing allowed ips, if necessary */ @@ -686,7 +685,7 @@ function captiveportal_allowedip_configure() { if ($line) { list($ip,$rule) = explode(",",$line); mwexec("/sbin/ipfw delete $rule"); - } + } } } fclose($fd); @@ -698,21 +697,21 @@ function captiveportal_allowedip_configure() { $ruleno = trim(file_get_contents("{$g['vardb_path']}/captiveportal.nextrule")); if (!$ruleno) $ruleno = 10000; /* first rule number */ - + if (is_array($config['captiveportal']['allowedip'])) { - + $fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "w"); if (!$fd) { printf("Error: cannot open allowed ip DB file in captiveportal_allowedip_configure().\n"); captiveportal_unlock(); - return 1; + return 1; } - + foreach ($config['captiveportal']['allowedip'] as $ipent) { - + /* record allowed ip so it can be recognized and removed later */ fwrite($fd, $ipent['ip'] . "," . $ruleno ."\n"); - + /* insert ipfw rule to allow ip thru */ if ($ipent['dir'] == "from") { mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from " . $ipent['ip'] . " to any in"); @@ -721,13 +720,13 @@ function captiveportal_allowedip_configure() { mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to " . $ipent['ip'] . " in"); mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from " . $ipent['ip'] . " to any out"); } - + $ruleno++; if ($ruleno > 19899) $ruleno = 10000; } - - fclose($fd); + + fclose($fd); /* write next rule number */ $fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w"); @@ -736,26 +735,24 @@ function captiveportal_allowedip_configure() { fclose($fd); } } - + captiveportal_unlock(); return 0; } /* get last activity timestamp given ipfw rule number */ function captiveportal_get_last_activity($ruleno) { - - $ipfwoutput = ""; - - exec("/sbin/ipfw -T list {$ruleno} 2>/dev/null", $ipfwoutput); - - /* in */ - if ($ipfwoutput[0]) { - $ri = explode(" ", $ipfwoutput[0]); - if ($ri[1]) - return $ri[1]; - } - - return 0; + + exec("/sbin/ipfw -T list {$ruleno} 2>/dev/null", $ipfwoutput); + + /* in */ + if ($ipfwoutput[0]) { + $ri = explode(" ", $ipfwoutput[0]); + if ($ri[1]) + return $ri[1]; + } + + return 0; } /* read RADIUS servers into array */ @@ -817,57 +814,63 @@ function captiveportal_unlock() { /* log successful captive portal authentication to syslog */ /* part of this code from php.net */ function captiveportal_logportalauth($user,$mac,$ip,$status, $message = null) { - define_syslog_variables(); - $message = trim($message); - openlog("logportalauth", LOG_PID, LOG_LOCAL4); - // Log it - if (!$message) - syslog(LOG_INFO, "$status: $user, $mac, $ip"); - else - syslog(LOG_INFO, "$status: $user, $mac, $ip, $message"); - closelog(); + define_syslog_variables(); + $message = trim($message); + openlog("logportalauth", LOG_PID, LOG_LOCAL4); + // Log it + if (!$message) + syslog(LOG_INFO, "$status: $user, $mac, $ip"); + else + syslog(LOG_INFO, "$status: $user, $mac, $ip, $message"); + closelog(); } function radius($username,$password,$clientip,$clientmac,$type) { - global $g, $config; - - $next_ruleno = get_next_ipfw_ruleno(); - $radiusservers = captiveportal_get_radius_servers(); - $radacct_enable = isset($config['captiveportal']['radacct_enable']); - - $auth_list = RADIUS_AUTHENTICATION($username, - $password, - $radiusservers, - $clientip, - $clientmac, - $next_ruleno); - - if ($auth_list['auth_val'] == 2) { - captiveportal_logportalauth($username,$clientmac,$clientip,$type); - $sessionid = portal_allow($clientip, - $clientmac, - $username, - $password, - $auth_list['session_timeout'], - $auth_list['idle_timeout'], - $auth_list['url_redirection'], - $auth_list['session_terminate_time']); - - if ($radacct_enable) { - $auth_list['acct_val'] = RADIUS_ACCOUNTING_START($next_ruleno, - $username, - $sessionid, - $radiusservers[0]['ipaddr'], - $radiusservers[0]['acctport'], - $radiusservers[0]['key'], - $clientip, - $clientmac); - if ($auth_list['acct_val'] == 1) - captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED"); - } - } + global $g, $config; + + $ruleno = captiveportal_get_next_ipfw_ruleno(); + + /* if the pool is empty, return apprioriate message and fail authentication */ + if (is_null($ruleno)) { + $auth_list = array(); + $auth_list['auth_val'] = 1; + $auth_list['error'] = "System reached maximum login capacity"; + return $auth_list; + } + + $radiusservers = captiveportal_get_radius_servers(); + $radacct_enable = isset($config['captiveportal']['radacct_enable']); + + $auth_list = RADIUS_AUTHENTICATION($username, + $password, + $radiusservers, + $clientip, + $clientmac, + $ruleno); + + if ($auth_list['auth_val'] == 2) { + captiveportal_logportalauth($username,$clientmac,$clientip,$type); + $sessionid = portal_allow($clientip, + $clientmac, + $username, + $password, + $auth_list); + + if ($radacct_enable) { + $auth_list['acct_val'] = RADIUS_ACCOUNTING_START($ruleno, + $username, + $sessionid, + $radiusservers[0]['ipaddr'], + $radiusservers[0]['acctport'], + $radiusservers[0]['key'], + $clientip, + $clientmac); + if ($auth_list['acct_val'] == 1) + captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED"); + } + } - return $auth_list; + return $auth_list; } @@ -892,52 +895,140 @@ function captiveportal_read_db() { /* write captive portal DB */ function captiveportal_write_db($cpdb) { - + global $g; - + $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w"); - if ($fd) { + if ($fd) { foreach ($cpdb as $cpent) { fwrite($fd, join(",", $cpent) . "\n"); - } + } fclose($fd); - } + } } function captiveportal_write_elements() { - global $g, $config; - - /* delete any existing elements */ - if (is_dir($g['captiveportal_element_path'])) { - $dh = opendir($g['captiveportal_element_path']); - while (($file = readdir($dh)) !== false) { - if ($file != "." && $file != "..") - unlink($g['captiveportal_element_path'] . "/" . $file); - } - closedir($dh); - } else { - mkdir($g['captiveportal_element_path']); - } - - if (is_array($config['captiveportal']['element'])) { - conf_mount_rw(); - foreach ($config['captiveportal']['element'] as $data) { - $fd = @fopen($g['captiveportal_element_path'] . '/' . $data['name'], "wb"); - if (!$fd) { - printf("Error: cannot open '{$data['name']}' in captiveportal_write_elements().\n"); - return 1; - } - $decoded = base64_decode($data['content']); - fwrite($fd,$decoded); - fclose($fd); - unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}"); - unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}"); - mwexec("cd {$g['captiveportal_path']}/ && ln -s {$g['captiveportal_element_path']}/{$data['name']} {$data['name']}"); - } - conf_mount_ro(); - } - - return 0; + global $g, $config; + + /* delete any existing elements */ + if (is_dir($g['captiveportal_element_path'])) { + $dh = opendir($g['captiveportal_element_path']); + while (($file = readdir($dh)) !== false) { + if ($file != "." && $file != "..") + unlink($g['captiveportal_element_path'] . "/" . $file); + } + closedir($dh); + } else { + mkdir($g['captiveportal_element_path']); + } + + if (is_array($config['captiveportal']['element'])) { + + foreach ($config['captiveportal']['element'] as $data) { + $fd = @fopen($g['captiveportal_element_path'] . '/' . $data['name'], "wb"); + if (!$fd) { + printf("Error: cannot open '{$data['name']}' in captiveportal_write_elements().\n"); + return 1; + } + $decoded = base64_decode($data['content']); + fwrite($fd,$decoded); + fclose($fd); + } + } + + return 0; +} + +/** + * This function will calculate the lowest free firewall ruleno + * within the range specified based on the actual installed rules + * + */ + +function captiveportal_get_next_ipfw_ruleno($rulenos_start = 10000, $rulenos_range_max = 9899) { + $fwrules = ""; + exec("/sbin/ipfw show", $fwrules); + foreach ($fwrules as $fwrule) { + preg_match("/^(\d+)\s+/", $fwrule, $matches); + $rulenos_used[] = $matches[1]; + } + $rulenos_used = array_unique($rulenos_used); + $rulenos_range = count($rulenos_used); + if ($rulenos_range > $rulenos_range_max) { + return NULL; + } + $rulenos_pool = range($rulenos_start, ($rulenos_start + $rulenos_range)); + $rulenos_free = array_diff($rulenos_pool, $rulenos_used); + $ruleno = array_shift($rulenos_free); + + return $ruleno; +} + + +/** + * This function will calculate the traffic produced by a client + * based on its firewall rule + * + * Point of view: NAS + * + * Input means: from the client + * Output means: to the client + * + */ + +function getVolume($ruleno) { + + $volume = array(); + + // Initialize vars properly, since we don't want NULL vars + $volume['input_pkts'] = $volume['input_bytes'] = $volume['output_pkts'] = $volume['output_bytes'] = 0 ; + + // Ingress + $ipfw = ""; + exec("/sbin/ipfw show {$ruleno}", $ipfw); + preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[0], $matches); + $volume['input_pkts'] = $matches[2]; + $volume['input_bytes'] = $matches[3]; + + // Flush internal buffer + unset($matches); + + // Outgress + preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[1], $matches); + $volume['output_pkts'] = $matches[2]; + $volume['output_bytes'] = $matches[3]; + + return $volume; +} + +/** + * Get the NAS-Identifier + * + * We will use our local hostname to make up the nas_id + */ + +function getNasID() +{ + $nasId = ""; + exec("/bin/hostname", $nasId); + if(!$nasId[0]) + $nasId[0] = "m0n0wall"; + return $nasId[0]; +} + +/** + * Get the NAS-IP-Address based on the current wan address + * + * Use functions in interfaces.inc to find this out + * + */ + +function getNasIP() +{ + $nasIp = get_current_wan_address(); + if(!$nasIp) + $nasIp = "0.0.0.0"; + return $nasIp; } -?> +?>
\ No newline at end of file |