summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/inc/captiveportal.inc405
-rw-r--r--etc/inc/radius.inc1094
-rwxr-xr-xusr/local/www/services_captiveportal.php328
-rwxr-xr-xusr/local/www/services_captiveportal_filemanager.php168
-rwxr-xr-xusr/local/www/services_captiveportal_ip.php23
-rwxr-xr-xusr/local/www/services_captiveportal_ip_edit.php8
-rwxr-xr-xusr/local/www/services_captiveportal_mac.php15
-rwxr-xr-xusr/local/www/services_captiveportal_mac_edit.php10
-rwxr-xr-xusr/local/www/services_captiveportal_users.php24
-rwxr-xr-xusr/local/www/services_captiveportal_users_edit.php23
10 files changed, 1799 insertions, 299 deletions
diff --git a/etc/inc/captiveportal.inc b/etc/inc/captiveportal.inc
index c8f5a6a..fa11554 100644
--- a/etc/inc/captiveportal.inc
+++ b/etc/inc/captiveportal.inc
@@ -3,7 +3,7 @@
captiveportal.inc
part of m0n0wall (http://m0n0.ch/wall)
- Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
+ Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -37,7 +37,9 @@
/* include all configuration functions */
require_once("functions.inc");
require_once("radius_authentication.inc");
-require_once("radius_accounting.inc") ;
+require_once("radius_accounting.inc");
+
+$lockfile = "{$g['varrun_path']}/captiveportal.lock";
function captiveportal_configure() {
global $config, $g;
@@ -65,6 +67,12 @@ function captiveportal_configure() {
/* stop accounting on all clients */
captiveportal_radius_stop_all();
+ /* initialize minicron interval value */
+ $croninterval = $config['captiveportal']['croninterval'] ? $config['captiveportal']['croninterval'] : 60;
+
+ /* double check if the $croninterval is numeric and at least 10 seconds. If not we set it to 60 to avoid problems */
+ 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");
@@ -95,7 +103,7 @@ Welcome to the pfSense Captive Portal! This is the default page since a custom
<tr><td>&nbsp;</td></tr>
<tr>
<td colspan="2">
- <center><input name="accept" type="submit" value="Continue"></center>
+ <center><input name="accept" type="submit" value="Continue"></center>
</td>
</tr>
</table>
@@ -104,6 +112,8 @@ Welcome to the pfSense Captive Portal! This is the default page since a custom
</body>
</html>
+
+
EOD;
}
@@ -141,6 +151,9 @@ EOD;
fwrite($fd, $errtext);
fclose($fd);
}
+
+ /* write elements */
+ captiveportal_write_elements();
/* load rules */
mwexec("/sbin/ipfw -f delete set 1");
@@ -166,26 +179,6 @@ EOD;
mwexec("/sbin/sysctl net.link.ether.ipfw=1");
chdir($g['captiveportal_path']);
-
- $memory = get_memory();
- $avail = $memory[0];
- if($avail > 0 and $avail < 60) {
- $procs = 16;
- } else if($avail > 60 and $avail < 120) {
- $procs = 24;
- } else if($avail > 120 and $avail < 160) {
- $procs = 32;
- } else if($avail > 160 and $avail < 250) {
- $procs = 48;
- } else if($avail > 250 and $avail < 380) {
- $procs = 56;
- } else if($avail > 380 and $avail < 500) {
- $procs = 72;
- } else if($avail > 500 and $avail < 680) {
- $procs = 80;
- } else {
- $procs = 16;
- }
/* TEMPORARY! FAST_CGI reports _FALSE_ client ip
* addresses.
@@ -196,28 +189,34 @@ EOD;
$cert = base64_decode($config['captiveportal']['certificate']);
$key = base64_decode($config['captiveportal']['private-key']);
}
+
+ if ($config['captiveportal']['maxproc'])
+ $maxproc = $config['captiveportal']['maxproc'];
+ else
+ $maxproc = 16;
/* generate lighttpd configuration */
system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal.conf",
$cert, $key, "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/",
"cert-portal.pem", "1", $procs, $use_fastcgi, true);
-
+
/* attempt to start lighttpd */
$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal.conf");
-
- /* start pruning process (interval = 60 seconds) */
- mwexec("/usr/local/bin/minicron 60 {$g['varrun_path']}/minicron.pid " .
+
+ /* 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'];
@@ -229,12 +228,21 @@ EOD;
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);
}
@@ -292,12 +300,12 @@ function captiveportal_rules_generate() {
$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 */
$cprules .= <<<EOD
-add 500 pass all from $cpip to any out via $cpif
+add 500 set 1 pass all from $cpip to any out via $cpif
add 501 set 1 pass all from any to $cpip in via $cpif
EOD;
@@ -363,12 +371,14 @@ EOD;
}
/* remove clients that have been around for longer than the specified amount of time */
-/* db file structure: timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password */
+/* 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;
@@ -393,22 +403,46 @@ function captiveportal_prune_old() {
for ($i = 0; $i < count($cpdb); $i++) {
$timedout = false;
+ $term_cause = 1;
/* hard timeout? */
if ($timeout) {
- if ((time() - $cpdb[$i][0]) >= $timeout)
- $timedout = true;
+ 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))
+ 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);
+ captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time);
captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "TIMEOUT");
unset($cpdb[$i]);
}
@@ -427,14 +461,18 @@ function captiveportal_prune_old() {
$radiusservers[0]['ipaddr'],
$radiusservers[0]['acctport'],
$radiusservers[0]['key'],
- $cpdb[$i][2]); //clientip
+ $cpdb[$i][2], // clientip
+ $cpdb[$i][3], // clientmac
+ 10); // NAS Request
exec("/sbin/ipfw zero {$cpdb[$i][1]}");
- RADIUS_ACCOUNTING_START($cpdb[$i][4],
- $cpdb[$i][5],
+ 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]);
+ $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
@@ -443,21 +481,24 @@ function captiveportal_prune_old() {
$radiusservers[0]['ipaddr'],
$radiusservers[0]['acctport'],
$radiusservers[0]['key'],
- $cpdb[$i][2], //clientip
- true);
+ $cpdb[$i][2], // clientip
+ $cpdb[$i][3], // clientmac
+ 10, // NAS Request
+ true); // Interim Updates
}
}
/* check this user against RADIUS again */
- $auth_val = RADIUS_AUTHENTICATION($cpdb[$i][4],
- base64_decode($cpdb[$i][6]),
- $radiusservers[0]['ipaddr'],
- $radiusservers[0]['port'],
- $radiusservers[0]['key']);
+ $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_val == 3) {
- captiveportal_disconnect($cpdb[$i], $radiusservers);
- captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT");
+ 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]);
}
}
@@ -470,9 +511,11 @@ function captiveportal_prune_old() {
}
/* remove a single client according to the DB entry */
-function captiveportal_disconnect($dbent, $radiusservers) {
+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])) {
@@ -483,7 +526,11 @@ function captiveportal_disconnect($dbent, $radiusservers) {
$radiusservers[0]['ipaddr'],
$radiusservers[0]['acctport'],
$radiusservers[0]['key'],
- $dbent[2]); //clientip
+ $dbent[2], // clientip
+ $dbent[3], // clientmac
+ $term_cause, // Acct-Terminate-Cause
+ false,
+ $stop_time);
}
mwexec("/sbin/ipfw delete " . $dbent[1] . " " . ($dbent[1]+10000));
@@ -498,7 +545,7 @@ function captiveportal_disconnect($dbent, $radiusservers) {
}
/* remove a single client by ipfw rule number */
-function captiveportal_disconnect_client($id) {
+function captiveportal_disconnect_client($id,$term_cause = 1) {
global $g, $config;
@@ -511,7 +558,7 @@ function captiveportal_disconnect_client($id) {
/* find entry */
for ($i = 0; $i < count($cpdb); $i++) {
if ($cpdb[$i][1] == $id) {
- captiveportal_disconnect($cpdb[$i], $radiusservers);
+ captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause);
captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT");
unset($cpdb[$i]);
break;
@@ -527,6 +574,9 @@ function captiveportal_disconnect_client($id) {
/* 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();
@@ -542,7 +592,9 @@ function captiveportal_radius_stop_all() {
$radiusservers[0]['ipaddr'],
$radiusservers[0]['acctport'],
$radiusservers[0]['key'],
- $cpdb[$i][2]); //clientip
+ $cpdb[$i][2], // clientip
+ $cpdb[$i][3], // clientmac
+ 7); // Admin Reboot
}
}
captiveportal_unlock();
@@ -572,7 +624,7 @@ function captiveportal_passthrumac_configure() {
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
@@ -589,7 +641,7 @@ function captiveportal_passthrumac_configure() {
mwexec("/sbin/ipfw add 50 skipto 29900 ip from any to any MAC any {$ptm['mac']} keep-state");
}
}
-
+
captiveportal_unlock();
return 0;
@@ -679,107 +731,182 @@ function captiveportal_get_last_activity($ruleno) {
return 0;
}
-/* read captive portal DB into array */
-function captiveportal_read_db() {
-
- global $g;
-
- $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);
- }
- return $cpdb;
-}
-
-/* write captive portal DB */
-function captiveportal_write_db($cpdb) {
-
- global $g;
-
- $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
- if ($fd) {
- foreach ($cpdb as $cpent) {
- fwrite($fd, join(",", $cpent) . "\n");
- }
- fclose($fd);
- }
-}
-
/* 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;
+
+ 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 captiveportal_lock() {
-
- global $g;
-
- $lockfile = "{$g['varrun_path']}/captiveportal.lock";
-
- $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++;
- }
- }
+
+ 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 configuration file */
+/* unlock captive portal information file */
function captiveportal_unlock() {
-
- global $g;
-
- $lockfile = "{$g['varrun_path']}/captiveportal.lock";
-
- if (file_exists($lockfile))
- unlink($lockfile);
+
+ global $lockfile;
+
+ if (file_exists($lockfile))
+ unlink($lockfile);
}
/* log successful captive portal authentication to syslog */
/* part of this code from php.net */
-function captiveportal_logportalauth($user,$mac,$ip,$status) {
+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();
}
+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");
+ }
+ }
+
+ return $auth_list;
+
+}
+
+/* read captive portal DB into array */
+function captiveportal_read_db() {
+
+ global $g;
+
+ $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);
+ }
+ return $cpdb;
+}
+
+/* write captive portal DB */
+function captiveportal_write_db($cpdb) {
+
+ global $g;
+
+ $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
+ 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'])) {
+
+ 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;
+}
+
?>
diff --git a/etc/inc/radius.inc b/etc/inc/radius.inc
new file mode 100644
index 0000000..260f7b1
--- /dev/null
+++ b/etc/inc/radius.inc
@@ -0,0 +1,1094 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/*
+Copyright (c) 2003, Michael Bretterklieber <michael@bretterklieber.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.
+3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+This code cannot simply be copied and put under the GNU Public License or
+any other GPL-like (LGPL, GPL2) License.
+
+ $Id$
+
+ This version of RADIUS.php has been modified by
+ Jonathan De Graeve <jonathan@imelda.be> to integrate with M0n0wall <http://www.m0n0.ch/wall>
+
+ $Id_jdg: 2005/12/22 14:22:42
+
+ Changes made include:
+ * StandardAttributes for M0n0wall use
+ * Removed internal Session-Id creation
+ * Adding of ReplyMessage to getAttributes()
+ * Adding of listAttributes()
+ * Adding of VENDOR Bay Networks (Nortel)
+ * Adding of VENDOR Nomadix
+ * Adding of VENDOR WISPr (Wi-Fi Alliance)
+
+*/
+
+require_once("PEAR.inc");
+
+/**
+* Client implementation of RADIUS. This are wrapper classes for
+* the RADIUS PECL.
+* Provides RADIUS Authentication (RFC2865) and RADIUS Accounting (RFC2866).
+*
+* @package Auth_RADIUS
+* @author Michael Bretterklieber <michael@bretterklieber.com>
+* @access public
+* @version $Revision$
+*/
+
+PEAR::loadExtension('radius');
+
+/**
+ * class Auth_RADIUS
+ *
+ * Abstract base class for RADIUS
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS extends PEAR {
+
+ /**
+ * List of RADIUS servers.
+ * @var array
+ * @see addServer(), putServer()
+ */
+ var $_servers = array();
+
+ /**
+ * Path to the configuration-file.
+ * @var string
+ * @see setConfigFile()
+ */
+ var $_configfile = null;
+
+ /**
+ * Resource.
+ * @var resource
+ * @see open(), close()
+ */
+ var $res = null;
+
+ /**
+ * Username for authentication and accounting requests.
+ * @var string
+ */
+ var $username = null;
+
+ /**
+ * Password for plaintext-authentication (PAP).
+ * @var string
+ */
+ var $password = null;
+
+ /**
+ * List of known attributes.
+ * @var array
+ * @see dumpAttributes(), getAttributes()
+ */
+ var $attributes = array();
+
+ /**
+ * List of raw attributes.
+ * @var array
+ * @see dumpAttributes(), getAttributes()
+ */
+ var $rawAttributes = array();
+
+ /**
+ * List of raw vendor specific attributes.
+ * @var array
+ * @see dumpAttributes(), getAttributes()
+ */
+ var $rawVendorAttributes = array();
+
+ /**
+ * Constructor
+ *
+ * Loads the RADIUS PECL/extension
+ *
+ * @return void
+ */
+ function Auth_RADIUS()
+ {
+ $this->PEAR();
+ }
+
+ /**
+ * Adds a RADIUS server to the list of servers for requests.
+ *
+ * At most 10 servers may be specified. When multiple servers
+ * are given, they are tried in round-robin fashion until a
+ * valid response is received
+ *
+ * @access public
+ * @param string $servername Servername or IP-Address
+ * @param integer $port Portnumber
+ * @param string $sharedSecret Shared secret
+ * @param integer $timeout Timeout for each request
+ * @param integer $maxtries Max. retries for each request
+ * @return void
+ */
+ function addServer($servername = 'localhost', $port = 0, $sharedSecret = 'testing123', $timeout = 5, $maxtries = 3)
+ {
+ $this->_servers[] = array($servername, $port, $sharedSecret, $timeout, $maxtries);
+ }
+
+ /**
+ * Returns an error message, if an error occurred.
+ *
+ * @access public
+ * @return string
+ */
+ function getError()
+ {
+ return radius_strerror($this->res);
+ }
+
+ /**
+ * Sets the configuration-file.
+ *
+ * @access public
+ * @param string $file Path to the configuration file
+ * @return void
+ */
+ function setConfigfile($file)
+ {
+ $this->_configfile = $file;
+ }
+
+ /**
+ * Puts an attribute.
+ *
+ * @access public
+ * @param integer $attrib Attribute-number
+ * @param mixed $port Attribute-value
+ * @param type $type Attribute-type
+ * @return bool true on success, false on error
+ */
+ function putAttribute($attrib, $value, $type = null)
+ {
+ if ($type == null) {
+ $type = gettype($value);
+ }
+
+ switch ($type) {
+ case 'integer':
+ return radius_put_int($this->res, $attrib, $value);
+
+ case 'addr':
+ return radius_put_addr($this->res, $attrib, $value);
+
+ case 'string':
+ default:
+ return radius_put_attr($this->res, $attrib, $value);
+ }
+
+ }
+
+ /**
+ * Puts a vendor-specific attribute.
+ *
+ * @access public
+ * @param integer $vendor Vendor (MSoft, Cisco, ...)
+ * @param integer $attrib Attribute-number
+ * @param mixed $port Attribute-value
+ * @param type $type Attribute-type
+ * @return bool true on success, false on error
+ */
+ function putVendorAttribute($vendor, $attrib, $value, $type = null)
+ {
+
+ if ($type == null) {
+ $type = gettype($value);
+ }
+
+ switch ($type) {
+ case 'integer':
+ return radius_put_vendor_int($this->res, $vendor, $attrib, $value);
+
+ case 'addr':
+ return radius_put_vendor_addr($this->res, $vendor,$attrib, $value);
+
+ case 'string':
+ default:
+ return radius_put_vendor_attr($this->res, $vendor, $attrib, $value);
+ }
+
+ }
+
+ /**
+ * Prints known attributes received from the server.
+ *
+ * @access public
+ */
+ function dumpAttributes()
+ {
+ foreach ($this->attributes as $name => $data) {
+ echo "$name:$data<br>\n";
+ }
+ }
+
+ /**
+ * Return our know attributes array received from the server.
+ *
+ * @access public
+ */
+ function listAttributes()
+ {
+ return $this->attributes;
+ }
+
+ /**
+ * Overwrite this.
+ *
+ * @access public
+ */
+ function open()
+ {
+ }
+
+ /**
+ * Overwrite this.
+ *
+ * @access public
+ */
+ function createRequest()
+ {
+ }
+
+ /**
+ * Puts standard attributes.
+ *
+ * @access public
+ */
+ function putStandardAttributes()
+ {
+ $this->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_ETHERNET);
+ $this->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN);
+ }
+
+ /**
+ * Puts custom attributes.
+ *
+ * @access public
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ }
+
+ /**
+ * Configures the radius library.
+ *
+ * @access public
+ * @param string $servername Servername or IP-Address
+ * @param integer $port Portnumber
+ * @param string $sharedSecret Shared secret
+ * @param integer $timeout Timeout for each request
+ * @param integer $maxtries Max. retries for each request
+ * @return bool true on success, false on error
+ * @see addServer()
+ */
+ function putServer($servername, $port = 0, $sharedsecret = 'testing123', $timeout = 3, $maxtries = 3)
+ {
+ if (!radius_add_server($this->res, $servername, $port, $sharedsecret, $timeout, $maxtries)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Configures the radius library via external configurationfile
+ *
+ * @access public
+ * @param string $servername Servername or IP-Address
+ * @return bool true on success, false on error
+ */
+ function putConfigfile($file)
+ {
+ if (!radius_config($this->res, $file)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Initiates a RADIUS request.
+ *
+ * @access public
+ * @return bool true on success, false on errors
+ */
+ function start()
+ {
+ if (!$this->open()) {
+ return false;
+ }
+
+ foreach ($this->_servers as $s) {
+ // Servername, port, sharedsecret, timeout, retries
+ if (!$this->putServer($s[0], $s[1], $s[2], $s[3], $s[4])) {
+ return false;
+ }
+ }
+
+ if (!empty($this->_configfile)) {
+ if (!$this->putConfigfile($this->_configfile)) {
+ return false;
+ }
+ }
+
+ $this->createRequest();
+ $this->putStandardAttributes();
+ $this->putAuthAttributes();
+ return true;
+ }
+
+ /**
+ * Sends a prepared RADIUS request and waits for a response
+ *
+ * @access public
+ * @return mixed true on success, false on reject, PEAR_Error on error
+ */
+ function send()
+ {
+ $req = radius_send_request($this->res);
+ if (!$req) {
+ return $this->raiseError('Error sending request: ' . $this->getError());
+ }
+
+ switch($req) {
+ case RADIUS_ACCESS_ACCEPT:
+ if (is_subclass_of($this, 'auth_radius_acct')) {
+ return $this->raiseError('RADIUS_ACCESS_ACCEPT is unexpected for accounting');
+ }
+ return true;
+
+ case RADIUS_ACCESS_REJECT:
+ return false;
+
+ case RADIUS_ACCOUNTING_RESPONSE:
+ if (is_subclass_of($this, 'auth_radius_pap')) {
+ return $this->raiseError('RADIUS_ACCOUNTING_RESPONSE is unexpected for authentication');
+ }
+ return true;
+
+ default:
+ return $this->raiseError("Unexpected return value: $req");
+ }
+
+ }
+
+ /**
+ * Reads all received attributes after sending the request.
+ *
+ * This methos stores know attributes in the property attributes,
+ * all attributes (including known attibutes) are stored in rawAttributes
+ * or rawVendorAttributes.
+ * NOTE: call this functio also even if the request was rejected, because the
+ * Server returns usualy an errormessage
+ *
+ * @access public
+ * @return bool true on success, false on error
+ */
+ function getAttributes()
+ {
+
+ while ($attrib = radius_get_attr($this->res)) {
+
+ if (!is_array($attrib)) {
+ return false;
+ }
+
+ $attr = $attrib['attr'];
+ $data = $attrib['data'];
+
+ $this->rawAttributes[$attr] = $data;
+
+ switch ($attr) {
+ case RADIUS_FRAMED_IP_ADDRESS:
+ $this->attributes['framed_ip'] = radius_cvt_addr($data);
+ break;
+
+ case RADIUS_FRAMED_IP_NETMASK:
+ $this->attributes['framed_mask'] = radius_cvt_addr($data);
+ break;
+
+ case RADIUS_FRAMED_MTU:
+ $this->attributes['framed_mtu'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_FRAMED_COMPRESSION:
+ $this->attributes['framed_compression'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_SESSION_TIMEOUT:
+ $this->attributes['session_timeout'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_IDLE_TIMEOUT:
+ $this->attributes['idle_timeout'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_SERVICE_TYPE:
+ $this->attributes['service_type'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_CLASS:
+ $this->attributes['class'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_FRAMED_PROTOCOL:
+ $this->attributes['framed_protocol'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_FRAMED_ROUTING:
+ $this->attributes['framed_routing'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_FILTER_ID:
+ $this->attributes['filter_id'] = radius_cvt_string($data);
+ break;
+
+ case RADIUS_REPLY_MESSAGE:
+ $this->attributes['reply_message'] = radius_cvt_string($data);
+ break;
+
+ case RADIUS_VENDOR_SPECIFIC:
+ $attribv = radius_get_vendor_attr($data);
+ if (!is_array($attribv)) {
+ return false;
+ }
+
+ $vendor = $attribv['vendor'];
+ $attrv = $attribv['attr'];
+ $datav = $attribv['data'];
+
+ $this->rawVendorAttributes[$vendor][$attrv] = $datav;
+
+ if ($vendor == RADIUS_VENDOR_MICROSOFT) {
+
+ switch ($attrv) {
+ case RADIUS_MICROSOFT_MS_CHAP2_SUCCESS:
+ $this->attributes['ms_chap2_success'] = radius_cvt_string($datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_CHAP_ERROR:
+ $this->attributes['ms_chap_error'] = radius_cvt_string(substr($datav,1));
+ break;
+
+ case RADIUS_MICROSOFT_MS_CHAP_DOMAIN:
+ $this->attributes['ms_chap_domain'] = radius_cvt_string($datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
+ $this->attributes['ms_mppe_encryption_policy'] = radius_cvt_int($datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
+ $this->attributes['ms_mppe_encryption_types'] = radius_cvt_int($datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_CHAP_MPPE_KEYS:
+ $demangled = radius_demangle($this->res, $datav);
+ $this->attributes['ms_chap_mppe_lm_key'] = substr($demangled, 0, 8);
+ $this->attributes['ms_chap_mppe_nt_key'] = substr($demangled, 8, RADIUS_MPPE_KEY_LEN);
+ break;
+
+ case RADIUS_MICROSOFT_MS_MPPE_SEND_KEY:
+ $this->attributes['ms_chap_mppe_send_key'] = radius_demangle_mppe_key($this->res, $datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_MPPE_RECV_KEY:
+ $this->attributes['ms_chap_mppe_recv_key'] = radius_demangle_mppe_key($this->res, $datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_PRIMARY_DNS_SERVER:
+ $this->attributes['ms_primary_dns_server'] = radius_cvt_string($datav);
+ break;
+ }
+ }
+
+ if ($vendor == RADIUS_VENDOR_BAY) {
+
+ switch ($attrv) {
+ case RADIUS_BAY_CES_GROUP:
+ $this->attributes['ces_group'] = radius_cvt_string($datav);
+ break;
+ }
+ }
+
+ if ($vendor == 3309) { /* RADIUS_VENDOR_NOMADIX */
+
+ switch ($attrv) {
+ case 1: /* RADIUS_NOMADIX_BW_UP */
+ $this->attributes['bw_up'] = radius_cvt_int($datav);
+ break;
+ case 2: /* RADIUS_NOMADIX_BW_DOWN */
+ $this->attributes['bw_down'] = radius_cvt_int($datav);
+ break;
+ case 3: /* RADIUS_NOMADIX_URL_REDIRECTION */
+ $this->attributes['url_redirection'] = radius_cvt_string($datav);
+ break;
+ case 5: /* RADIUS_NOMADIX_EXPIRATION */
+ $this->attributes['expiration'] = radius_cvt_string($datav);
+ break;
+ case 7: /* RADIUS_NOMADIX_MAXBYTESUP */
+ $this->attributes['maxbytesup'] = radius_cvt_int($datav);
+ break;
+ case 8: /* RADIUS_NOMADIX_MAXBYTESDOWN */
+ $this->attributes['maxbytesdown'] = radius_cvt_int($datav);
+ break;
+ case 10: /* RADIUS_NOMADIX_LOGOFF_URL */
+ $this->attributes['url_logoff'] = radius_cvt_string($datav);
+ break;
+ }
+ }
+
+ if ($vendor == 14122) { /* RADIUS_VENDOR_WISPr Wi-Fi Alliance */
+
+ switch ($attrv) {
+ case 1: /* WISPr-Location-ID */
+ $this->attributes['location_id'] = radius_cvt_string($datav);
+ break;
+ case 2: /* WISPr-Location-Name */
+ $this->attributes['location_name'] = radius_cvt_string($datav);
+ break;
+ case 3: /* WISPr-Logoff-URL */
+ $this->attributes['url_logoff'] = radius_cvt_string($datav);
+ break;
+ case 4: /* WISPr-Redirection-URL */
+ $this->attributes['url_redirection'] = radius_cvt_string($datav);
+ break;
+ case 5: /* WISPr-Bandwidth-Min-Up */
+ $this->attributes['bw_minbytesup'] = radius_cvt_int($datav);
+ break;
+ case 6: /* WISPr-Bandwidth-Min-Down */
+ $this->attributes['bw_minbytesdown'] = radius_cvt_int($datav);
+ break;
+ case 7: /* WIPSr-Bandwidth-Max-Up */
+ $this->attributes['bw_maxbytesup'] = radius_cvt_int($datav);
+ break;
+ case 8: /* WISPr-Bandwidth-Max-Down */
+ $this->attributes['bw_maxbytesdown'] = radius_cvt_int($datav);
+ break;
+ case 9: /* WISPr-Session-Terminate-Time */
+ $this->attributes['session_terminate_time'] = radius_cvt_string($datav);
+ break;
+ case 10: /* WISPr-Session-Terminate-End-Of-Day */
+ $this->attributes['session_terminate_endofday'] = radius_cvt_int($datav);
+ break;
+ case 11: /* WISPr-Billing-Class-Of-Service */
+ $this->attributes['billing_class_of_service'] = radius_cvt_string($datav);
+ break;
+ }
+ }
+
+ break;
+
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Frees resources.
+ *
+ * Calling this method is always a good idea, because all security relevant
+ * attributes are filled with Nullbytes to leave nothing in the mem.
+ *
+ * @access public
+ */
+ function close()
+ {
+ if ($this->res != null) {
+ radius_close($this->res);
+ $this->res = null;
+ }
+ $this->username = str_repeat("\0", strlen($this->username));
+ $this->password = str_repeat("\0", strlen($this->password));
+ }
+
+}
+
+/**
+ * class Auth_RADIUS_PAP
+ *
+ * Class for authenticating using PAP (Plaintext)
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_PAP extends Auth_RADIUS
+{
+
+ /**
+ * Constructor
+ *
+ * @param string $username Username
+ * @param string $password Password
+ * @return void
+ */
+ function Auth_RADIUS_PAP($username = null, $password = null)
+ {
+ $this->Auth_RADIUS();
+ $this->username = $username;
+ $this->password = $password;
+ }
+
+ /**
+ * Creates a RADIUS resource
+ *
+ * Creates a RADIUS resource for authentication. This should be the first
+ * call before you make any other things with the library.
+ *
+ * @return bool true on success, false on error
+ */
+ function open()
+ {
+ $this->res = radius_auth_open();
+ if (!$this->res) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates an authentication request
+ *
+ * Creates an authentication request.
+ * You MUST call this method before you can put any attribute
+ *
+ * @return bool true on success, false on error
+ */
+ function createRequest()
+ {
+ if (!radius_create_request($this->res, RADIUS_ACCESS_REQUEST)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Put authentication specific attributes
+ *
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ if (isset($this->password)) {
+ $this->putAttribute(RADIUS_USER_PASSWORD, $this->password);
+ }
+ }
+
+}
+
+/**
+ * class Auth_RADIUS_CHAP_MD5
+ *
+ * Class for authenticating using CHAP-MD5 see RFC1994.
+ * Instead og the plaintext password the challenge and
+ * the response are needed.
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_CHAP_MD5 extends Auth_RADIUS_PAP
+{
+ /**
+ * 8 Bytes binary challenge
+ * @var string
+ */
+ var $challenge = null;
+
+ /**
+ * 16 Bytes MD5 response binary
+ * @var string
+ */
+ var $response = null;
+
+ /**
+ * Id of the authentication request. Should incremented after every request.
+ * @var integer
+ */
+ var $chapid = 1;
+
+ /**
+ * Constructor
+ *
+ * @param string $username Username
+ * @param string $challenge 8 Bytes Challenge (binary)
+ * @param integer $chapid Requestnumber
+ * @return void
+ */
+ function Auth_RADIUS_CHAP_MD5($username = null, $challenge = null, $chapid = 1)
+ {
+ $this->Auth_RADIUS_PAP();
+ $this->username = $username;
+ $this->challenge = $challenge;
+ $this->chapid = $chapid;
+ }
+
+ /**
+ * Put CHAP-MD5 specific attributes
+ *
+ * For authenticating using CHAP-MD5 via RADIUS you have to put the challenge
+ * and the response. The chapid is inserted in the first byte of the response.
+ *
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ if (isset($this->response)) {
+ $response = pack('C', $this->chapid) . $this->response;
+ $this->putAttribute(RADIUS_CHAP_PASSWORD, $response);
+ }
+ if (isset($this->challenge)) {
+ $this->putAttribute(RADIUS_CHAP_CHALLENGE, $this->challenge);
+ }
+ }
+
+ /**
+ * Frees resources.
+ *
+ * Calling this method is always a good idea, because all security relevant
+ * attributes are filled with Nullbytes to leave nothing in the mem.
+ *
+ * @access public
+ */
+ function close()
+ {
+ Auth_RADIUS_PAP::close();
+ $this->challenge = str_repeat("\0", strlen($this->challenge));
+ $this->response = str_repeat("\0", strlen($this->response));
+ }
+
+}
+
+/**
+ * class Auth_RADIUS_MSCHAPv1
+ *
+ * Class for authenticating using MS-CHAPv1 see RFC2433
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_MSCHAPv1 extends Auth_RADIUS_CHAP_MD5
+{
+ /**
+ * LAN-Manager-Response
+ * @var string
+ */
+ var $lmResponse = null;
+
+ /**
+ * Wether using deprecated LM-Responses or not.
+ * 0 = use LM-Response, 1 = use NT-Response
+ * @var bool
+ */
+ var $flags = 1;
+
+ /**
+ * Put MS-CHAPv1 specific attributes
+ *
+ * For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge
+ * and the response. The response has this structure:
+ * struct rad_mschapvalue {
+ * u_char ident;
+ * u_char flags;
+ * u_char lm_response[24];
+ * u_char response[24];
+ * };
+ *
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ if (isset($this->response) || isset($this->lmResponse)) {
+ $lmResp = isset($this->lmResponse) ? $this->lmResponse : str_repeat ("\0", 24);
+ $ntResp = isset($this->response) ? $this->response : str_repeat ("\0", 24);
+ $resp = pack('CC', $this->chapid, $this->flags) . $lmResp . $ntResp;
+ $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_RESPONSE, $resp);
+ }
+ if (isset($this->challenge)) {
+ $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_CHALLENGE, $this->challenge);
+ }
+ }
+}
+
+/**
+ * class Auth_RADIUS_MSCHAPv2
+ *
+ * Class for authenticating using MS-CHAPv2 see RFC2759
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_MSCHAPv2 extends Auth_RADIUS_MSCHAPv1
+{
+ /**
+ * 16 Bytes binary challenge
+ * @var string
+ */
+ var $challenge = null;
+
+ /**
+ * 16 Bytes binary Peer Challenge
+ * @var string
+ */
+ var $peerChallenge = null;
+
+ /**
+ * Put MS-CHAPv2 specific attributes
+ *
+ * For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge
+ * and the response. The response has this structure:
+ * struct rad_mschapv2value {
+ * u_char ident;
+ * u_char flags;
+ * u_char pchallenge[16];
+ * u_char reserved[8];
+ * u_char response[24];
+ * };
+ * where pchallenge is the peer challenge. Like for MS-CHAPv1 we set the flags field to 1.
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ if (isset($this->response) && isset($this->peerChallenge)) {
+ // Response: chapid, flags (1 = use NT Response), Peer challenge, reserved, Response
+ $resp = pack('CCa16a8a24',$this->chapid , 1, $this->peerChallenge, str_repeat("\0", 8), $this->response);
+ $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP2_RESPONSE, $resp);
+ }
+ if (isset($this->challenge)) {
+ $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_CHALLENGE, $this->challenge);
+ }
+ }
+
+ /**
+ * Frees resources.
+ *
+ * Calling this method is always a good idea, because all security relevant
+ * attributes are filled with Nullbytes to leave nothing in the mem.
+ *
+ * @access public
+ */
+ function close()
+ {
+ Auth_RADIUS_MSCHAPv1::close();
+ $this->peerChallenge = str_repeat("\0", strlen($this->peerChallenge));
+ }
+}
+
+/**
+ * class Auth_RADIUS_Acct
+ *
+ * Class for RADIUS accounting
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct extends Auth_RADIUS
+{
+ /**
+ * Defines where the Authentication was made, possible values are:
+ * RADIUS_AUTH_RADIUS, RADIUS_AUTH_LOCAL, RADIUS_AUTH_REMOTE
+ * @var integer
+ */
+ var $authentic = null;
+
+ /**
+ * Defines the type of the accounting request, on of:
+ * RADIUS_START, RADIUS_STOP, RADIUS_ACCOUNTING_ON, RADIUS_ACCOUNTING_OFF
+ * @var integer
+ */
+ var $status_type = null;
+
+ /**
+ * The time the user was logged in in seconds
+ * @var integer
+ */
+ var $session_time = null;
+
+ /**
+ * A uniq identifier for the session of the user, maybe the PHP-Session-Id
+ * @var string
+ */
+ var $session_id = null;
+
+ /**
+ * Constructor
+ *
+ * This function is disabled for M0n0wall since we use our own session_id
+ *
+ * Generates a predefined session_id. We use the Remote-Address, the PID, and the Current user.
+ * @return void
+ *
+ function Auth_RADIUS_Acct()
+ {
+ $this->Auth_RADIUS();
+
+ if (isset($_SERVER)) {
+ $var = &$_SERVER;
+ } else {
+ $var = &$GLOBALS['HTTP_SERVER_VARS'];
+ }
+
+ $this->session_id = sprintf("%s:%d-%s", isset($var['REMOTE_ADDR']) ? $var['REMOTE_ADDR'] : '127.0.0.1' , getmypid(), get_current_user());
+ }
+ */
+
+ /**
+ * Constructor
+ *
+ */
+
+ function Auth_RADIUS_Acct()
+ {
+ $this->Auth_RADIUS();
+ }
+
+ /**
+ * Creates a RADIUS resource
+ *
+ * Creates a RADIUS resource for accounting. This should be the first
+ * call before you make any other things with the library.
+ *
+ * @return bool true on success, false on error
+ */
+ function open()
+ {
+ $this->res = radius_acct_open();
+ if (!$this->res) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates an accounting request
+ *
+ * Creates an accounting request.
+ * You MUST call this method before you can put any attribute.
+ *
+ * @return bool true on success, false on error
+ */
+ function createRequest()
+ {
+ if (!radius_create_request($this->res, RADIUS_ACCOUNTING_REQUEST)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Put attributes for accounting.
+ *
+ * Here we put some accounting values. There many more attributes for accounting,
+ * but for web-applications only certain attributes make sense.
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ $this->putAttribute(RADIUS_ACCT_SESSION_ID, $this->session_id);
+ $this->putAttribute(RADIUS_ACCT_STATUS_TYPE, $this->status_type);
+ if (isset($this->session_time) && $this->status_type == RADIUS_STOP) {
+ $this->putAttribute(RADIUS_ACCT_SESSION_TIME, $this->session_time);
+ }
+ if (isset($this->authentic)) {
+ $this->putAttribute(RADIUS_ACCT_AUTHENTIC, $this->authentic);
+ }
+
+ }
+
+}
+
+/**
+ * class Auth_RADIUS_Acct_Start
+ *
+ * Class for RADIUS accounting. Its usualy used, after the user has logged in.
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct_Start extends Auth_RADIUS_Acct
+{
+ /**
+ * Defines the type of the accounting request.
+ * It is set to RADIUS_START by default in this class.
+ * @var integer
+ */
+ var $status_type = RADIUS_START;
+}
+
+/**
+ * class Auth_RADIUS_Acct_Start
+ *
+ * Class for RADIUS accounting. Its usualy used, after the user has logged out.
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct_Stop extends Auth_RADIUS_Acct
+{
+ /**
+ * Defines the type of the accounting request.
+ * It is set to RADIUS_STOP by default in this class.
+ * @var integer
+ */
+ var $status_type = RADIUS_STOP;
+}
+
+if (!defined('RADIUS_UPDATE'))
+ define('RADIUS_UPDATE', 3);
+
+/**
+ * class Auth_RADIUS_Acct_Update
+ *
+ * Class for interim RADIUS accounting updates.
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct_Update extends Auth_RADIUS_Acct
+{
+ /**
+ * Defines the type of the accounting request.
+ * It is set to RADIUS_UPDATE by default in this class.
+ * @var integer
+ */
+ var $status_type = RADIUS_UPDATE;
+}
+
+?>
diff --git a/usr/local/www/services_captiveportal.php b/usr/local/www/services_captiveportal.php
index feeddfc..e1e7a36 100755
--- a/usr/local/www/services_captiveportal.php
+++ b/usr/local/www/services_captiveportal.php
@@ -3,7 +3,7 @@
services_captiveportal.php
part of m0n0wall (http://m0n0.ch/wall)
- Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
+ Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,6 +28,7 @@
POSSIBILITY OF SUCH DAMAGE.
*/
+$pgtitle = "Services:Captive portal";
require("guiconfig.inc");
if (!is_array($config['captiveportal'])) {
@@ -45,11 +46,15 @@ if ($_GET['act'] == "viewhtml") {
}
$pconfig['cinterface'] = $config['captiveportal']['interface'];
+$pconfig['maxproc'] = $config['captiveportal']['maxproc'];
+$pconfig['maxprocperip'] = $config['captiveportal']['maxprocperip'];
$pconfig['timeout'] = $config['captiveportal']['timeout'];
$pconfig['idletimeout'] = $config['captiveportal']['idletimeout'];
$pconfig['enable'] = isset($config['captiveportal']['enable']);
$pconfig['auth_method'] = $config['captiveportal']['auth_method'];
$pconfig['radacct_enable'] = isset($config['captiveportal']['radacct_enable']);
+$pconfig['radmac_enable'] = isset($config['captiveportal']['radmac_enable']);
+$pconfig['radmac_secret'] = $config['captiveportal']['radmac_secret'];
$pconfig['reauthenticate'] = isset($config['captiveportal']['reauthenticate']);
$pconfig['reauthenticateacct'] = $config['captiveportal']['reauthenticateacct'];
$pconfig['httpslogin_enable'] = isset($config['captiveportal']['httpslogin']);
@@ -58,11 +63,17 @@ $pconfig['cert'] = base64_decode($config['captiveportal']['certificate']);
$pconfig['key'] = base64_decode($config['captiveportal']['private-key']);
$pconfig['logoutwin_enable'] = isset($config['captiveportal']['logoutwin_enable']);
$pconfig['nomacfilter'] = isset($config['captiveportal']['nomacfilter']);
+$pconfig['noconcurrentlogins'] = isset($config['captiveportal']['noconcurrentlogins']);
$pconfig['redirurl'] = $config['captiveportal']['redirurl'];
$pconfig['radiusip'] = $config['captiveportal']['radiusip'];
+$pconfig['radiusip2'] = $config['captiveportal']['radiusip2'];
$pconfig['radiusport'] = $config['captiveportal']['radiusport'];
+$pconfig['radiusport2'] = $config['captiveportal']['radiusport2'];
$pconfig['radiusacctport'] = $config['captiveportal']['radiusacctport'];
$pconfig['radiuskey'] = $config['captiveportal']['radiuskey'];
+$pconfig['radiuskey2'] = $config['captiveportal']['radiuskey2'];
+$pconfig['radiusvendor'] = $config['captiveportal']['radiusvendor'];
+$pconfig['radiussession_timeout'] = isset($config['captiveportal']['radiussession_timeout']);
if ($_POST) {
@@ -76,6 +87,15 @@ if ($_POST) {
do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);
+ /* make sure no interfaces are bridged */
+ for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
+ $coptif = &$config['interfaces']['opt' . $i];
+ if (isset($coptif['enable']) && $coptif['bridge']) {
+ $input_errors[] = "The captive portal cannot be used when one or more interfaces are bridged.";
+ break;
+ }
+ }
+
if ($_POST['httpslogin_enable']) {
if (!$_POST['cert'] || !$_POST['key']) {
$input_errors[] = "Certificate and key must be specified for HTTPS login.";
@@ -101,57 +121,56 @@ if ($_POST) {
if (($_POST['radiusip'] && !is_ipaddr($_POST['radiusip']))) {
$input_errors[] = "A valid IP address must be specified. [".$_POST['radiusip']."]";
}
+ if (($_POST['radiusip2'] && !is_ipaddr($_POST['radiusip2']))) {
+ $input_errors[] = "A valid IP address must be specified. [".$_POST['radiusip2']."]";
+ }
if (($_POST['radiusport'] && !is_port($_POST['radiusport']))) {
$input_errors[] = "A valid port number must be specified. [".$_POST['radiusport']."]";
}
+ if (($_POST['radiusport2'] && !is_port($_POST['radiusport2']))) {
+ $input_errors[] = "A valid port number must be specified. [".$_POST['radiusport2']."]";
+ }
if (($_POST['radiusacctport'] && !is_port($_POST['radiusacctport']))) {
- $input_errors[] = "A valid port number must be specified. [".$_POST['radiusport']."]";
+ $input_errors[] = "A valid port number must be specified. [".$_POST['radiusacctport']."]";
+ }
+ if ($_POST['maxproc'] && (!is_numeric($_POST['maxproc']) || ($_POST['maxproc'] < 4) || ($_POST['maxproc'] > 100))) {
+ $input_errors[] = "The total maximum number of concurrent connections must be between 4 and 100.";
+ }
+ $mymaxproc = $_POST['maxproc'] ? $_POST['maxproc'] : 16;
+ if ($_POST['maxprocperip'] && (!is_numeric($_POST['maxprocperip']) || ($_POST['maxprocperip'] > $mymaxproc))) {
+ $input_errors[] = "The maximum number of concurrent connections per client IP address may not be larger than the global maximum.";
}
if (!$input_errors) {
$config['captiveportal']['interface'] = $_POST['cinterface'];
+ $config['captiveportal']['maxproc'] = $_POST['maxproc'];
+ $config['captiveportal']['maxprocperip'] = $_POST['maxprocperip'] ? $_POST['maxprocperip'] : false;
$config['captiveportal']['timeout'] = $_POST['timeout'];
$config['captiveportal']['idletimeout'] = $_POST['idletimeout'];
+ $config['captiveportal']['enable'] = $_POST['enable'] ? true : false;
$config['captiveportal']['auth_method'] = $_POST['auth_method'];
+ $config['captiveportal']['radacct_enable'] = $_POST['radacct_enable'] ? true : false;
+ $config['captiveportal']['reauthenticate'] = $_POST['reauthenticate'] ? true : false;
+ $config['captiveportal']['radmac_enable'] = $_POST['radmac_enable'] ? true : false;
+ $config['captiveportal']['radmac_secret'] = $_POST['radmac_secret'] ? $_POST['radmac_secret'] : false;
$config['captiveportal']['reauthenticateacct'] = $_POST['reauthenticateacct'];
+ $config['captiveportal']['httpslogin'] = $_POST['httpslogin_enable'] ? true : false;
$config['captiveportal']['httpsname'] = $_POST['httpsname'];
$config['captiveportal']['certificate'] = base64_encode($_POST['cert']);
$config['captiveportal']['private-key'] = base64_encode($_POST['key']);
+ $config['captiveportal']['logoutwin_enable'] = $_POST['logoutwin_enable'] ? true : false;
+ $config['captiveportal']['nomacfilter'] = $_POST['nomacfilter'] ? true : false;
+ $config['captiveportal']['noconcurrentlogins'] = $_POST['noconcurrentlogins'] ? true : false;
$config['captiveportal']['redirurl'] = $_POST['redirurl'];
$config['captiveportal']['radiusip'] = $_POST['radiusip'];
+ $config['captiveportal']['radiusip2'] = $_POST['radiusip2'];
$config['captiveportal']['radiusport'] = $_POST['radiusport'];
+ $config['captiveportal']['radiusport2'] = $_POST['radiusport2'];
$config['captiveportal']['radiusacctport'] = $_POST['radiusacctport'];
$config['captiveportal']['radiuskey'] = $_POST['radiuskey'];
-
- if($_POST['radacct_enable'] == "yes")
- $config['captiveportal']['radacct_enable'] = true;
- else
- unset($config['captiveportal']['radacct_enable']);
-
- if($_POST['reauthenticate'] == "yes")
- $config['captiveportal']['reauthenticate'] = true;
- else
- unset($config['captiveportal']['reauthenticate']);
-
- if($_POST['enable'] == "yes")
- $config['captiveportal']['enable'] = true;
- else
- unset($config['captiveportal']['enable']);
-
- if($_POST['httpslogin_enable'] == "yes")
- $config['captiveportal']['httpslogin'] = true;
- else
- unset($config['captiveportal']['httpslogin']);
-
- if($_POST['logoutwin_enable'] == "yes")
- $config['captiveportal']['logoutwin_enable'] = true;
- else
- unset($config['captiveportal']['logoutwin_enable']);
-
- if($_POST['nomacfilter'] == "yes")
- $config['captiveportal']['nomacfilter'] = true;
- else
- unset($config['captiveportal']['nomacfilter']);
+ $config['captiveportal']['radiuskey2'] = $_POST['radiuskey2'];
+ $config['captiveportal']['radiusvendor'] = $_POST['radiusvendor'] ? $_POST['radiusvendor'] : false;
+ $config['captiveportal']['radiussession_timeout'] = $_POST['radiussession_timeout'] ? true : false;
/* file upload? */
if (is_uploaded_file($_FILES['htmlfile']['tmp_name']))
@@ -162,55 +181,68 @@ if ($_POST) {
write_config();
$retval = 0;
-
- config_lock();
- $retval = captiveportal_configure();
- config_unlock();
-
+ if (!file_exists($d_sysrebootreqd_path)) {
+ config_lock();
+ $retval = captiveportal_configure();
+ config_unlock();
+ }
$savemsg = get_std_save_message($retval);
}
}
-
-$pgtitle = "Services: Captive Portal";
include("head.inc");
-
?>
-<body link="#000000" vlink="#000000" alink="#000000">
<?php include("fbegin.inc"); ?>
<script language="JavaScript">
<!--
function enable_change(enable_change) {
- var endis;
+ var endis, radius_endis;
endis = !(document.iform.enable.checked || enable_change);
+ radius_endis = !((!endis && document.iform.auth_method[2].checked) || enable_change);
document.iform.cinterface.disabled = endis;
+ document.iform.maxproc.disabled = endis;
+ document.iform.maxprocperip.disabled = endis;
document.iform.idletimeout.disabled = endis;
document.iform.timeout.disabled = endis;
document.iform.redirurl.disabled = endis;
- document.iform.radiusip.disabled = endis;
- document.iform.radiusport.disabled = endis;
- document.iform.radiuskey.disabled = endis;
- document.iform.radacct_enable.disabled = endis;
- document.iform.radiusacctport.disabled = endis;
- document.iform.reauthenticate.disabled = endis;
- document.iform.reauthenticateacct.disabled = endis;
+ document.iform.radiusip.disabled = radius_endis;
+ document.iform.radiusip2.disabled = radius_endis;
+ document.iform.radiusport.disabled = radius_endis;
+ document.iform.radiusport2.disabled = radius_endis;
+ document.iform.radiuskey.disabled = radius_endis;
+ document.iform.radiuskey2.disabled = radius_endis;
+ document.iform.radacct_enable.disabled = radius_endis;
+ document.iform.reauthenticate.disabled = radius_endis;
document.iform.auth_method[0].disabled = endis;
document.iform.auth_method[1].disabled = endis;
document.iform.auth_method[2].disabled = endis;
+ document.iform.radmac_enable.disabled = radius_endis;
document.iform.httpslogin_enable.disabled = endis;
document.iform.httpsname.disabled = endis;
document.iform.cert.disabled = endis;
document.iform.key.disabled = endis;
document.iform.logoutwin_enable.disabled = endis;
document.iform.nomacfilter.disabled = endis;
+ document.iform.noconcurrentlogins.disabled = endis;
+ document.iform.radiusvendor.disabled = radius_endis;
+ document.iform.radiussession_timeout.disabled = radius_endis;
document.iform.htmlfile.disabled = endis;
document.iform.errfile.disabled = endis;
+
+ document.iform.radiusacctport.disabled = (radius_endis || !document.iform.radacct_enable.checked) && !enable_change;
+
+ document.iform.radmac_secret.disabled = (radius_endis || !document.iform.radmac_enable.checked) && !enable_change;
+
+ var reauthenticate_dis = (radius_endis || !document.iform.reauthenticate.checked) && !enable_change;
+ document.iform.reauthenticateacct[0].disabled = reauthenticate_dis;
+ document.iform.reauthenticateacct[1].disabled = reauthenticate_dis;
+ document.iform.reauthenticateacct[2].disabled = reauthenticate_dis;
}
//-->
</script>
-<p class="pgtitle">Services: Captive portal</p>
<?php if ($input_errors) print_input_errors($input_errors); ?>
<?php if ($savemsg) print_info_box($savemsg); ?>
+<p class="pgtitle"><?=$pgtitle?></p>
<form action="services_captiveportal.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td class="tabnavtbl">
@@ -220,9 +252,9 @@ function enable_change(enable_change) {
$tab_array[] = array("Pass-through MAC", false, "services_captiveportal_mac.php");
$tab_array[] = array("Allowed IP addresses", false, "services_captiveportal_ip.php");
$tab_array[] = array("Users", false, "services_captiveportal_users.php");
+ $tab_array[] = array("File Manager", true, "services_captiveportal_filemanager.php");
display_top_tabs($tab_array);
-?>
- </td></tr>
+?> </td></tr>
<tr>
<td class="tabcont">
<table width="100%" border="0" cellpadding="6" cellspacing="0">
@@ -250,6 +282,21 @@ function enable_change(enable_change) {
<span class="vexpl">Choose which interface to run the captive portal on.</span></td>
</tr>
<tr>
+ <td valign="top" class="vncell">Maximum concurrent connections</td>
+ <td class="vtable">
+ <table cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input name="maxprocperip" type="text" class="formfld" id="maxprocperip" size="5" value="<?=htmlspecialchars($pconfig['maxprocperip']);?>"> per client IP address (0 = no limit)</td>
+ </tr>
+ <tr>
+ <td><input name="maxproc" type="text" class="formfld" id="maxproc" size="5" value="<?=htmlspecialchars($pconfig['maxproc']);?>"> total</td>
+ </tr>
+ </table>
+This setting limits the number of concurrent connections to the captive portal HTTP(S) server. This does not set how many users can be logged in
+to the captive portal, but rather how many users can load the portal page or authenticate at the same time!
+Default is 4 connections per client IP address, with a total maximum of 16 connections.</td>
+ </tr>
+ <tr>
<td valign="top" class="vncell">Idle timeout</td>
<td class="vtable">
<input name="idletimeout" type="text" class="formfld" id="idletimeout" size="6" value="<?=htmlspecialchars($pconfig['idletimeout']);?>">
@@ -279,69 +326,169 @@ If you provide a URL here, clients will be redirected to that URL instead of the
to access after they've authenticated.</td>
</tr>
<tr>
+ <td valign="top" class="vncell">Concurrent user logins</td>
+ <td class="vtable">
+ <input name="noconcurrentlogins" type="checkbox" class="formfld" id="noconcurrentlogins" value="yes" <?php if ($pconfig['noconcurrentlogins']) echo "checked"; ?>>
+ <strong>Disable concurrent logins</strong><br>
+ If this option is set, only the most recent login per username will be active. Subsequent logins will cause machines previously logged in with the same username to be disconnected.</td>
+ </tr>
+ <tr>
<td valign="top" class="vncell">MAC filtering </td>
<td class="vtable">
<input name="nomacfilter" type="checkbox" class="formfld" id="nomacfilter" value="yes" <?php if ($pconfig['nomacfilter']) echo "checked"; ?>>
<strong>Disable MAC filtering</strong><br>
- If this option is set, no attempts will be made to ensure that the MAC address of clients stays the same while they're logged in. This is required when the MAC address of cannot be determined (usually because there are routers between pfSense and the clients).</td>
+ If this option is set, no attempts will be made to ensure that the MAC address of clients stays the same while they're logged in.
+ This is required when the MAC address of the client cannot be determined (usually because there are routers between m0n0wall and the clients).
+ If this is enabled, RADIUS MAC authentication cannot be used.</td>
</tr>
<tr>
<td width="22%" valign="top" class="vncell">Authentication</td>
<td width="78%" class="vtable">
<table cellpadding="0" cellspacing="0">
<tr>
- <td colspan="2"><input name="auth_method" type="radio" id="auth_method" value="none" <?php if($pconfig['auth_method']!="local" && $pconfig['auth_method']!="radius") echo "checked"; ?>>
+ <td colspan="2"><input name="auth_method" type="radio" id="auth_method" value="none" onClick="enable_change(false)" <?php if($pconfig['auth_method']!="local" && $pconfig['auth_method']!="radius") echo "checked"; ?>>
No authentication</td>
</tr>
<tr>
- <td colspan="2"><input name="auth_method" type="radio" id="auth_method" value="local" <?php if($pconfig['auth_method']=="local") echo "checked"; ?>>
+ <td colspan="2"><input name="auth_method" type="radio" id="auth_method" value="local" onClick="enable_change(false)" <?php if($pconfig['auth_method']=="local") echo "checked"; ?>>
Local <a href="services_captiveportal_users.php">user manager</a></td>
</tr>
<tr>
- <td colspan="2"><input name="auth_method" type="radio" id="auth_method" value="radius" <?php if($pconfig['auth_method']=="radius") echo "checked"; ?>>
+ <td colspan="2"><input name="auth_method" type="radio" id="auth_method" value="radius" onClick="enable_change(false)" <?php if($pconfig['auth_method']=="radius") echo "checked"; ?>>
RADIUS authentication</td>
</tr><tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
- <tr>
- <td>IP address:</td>
- <td><input name="radiusip" type="text" class="formfld" id="radiusip" size="20" value="<?=htmlspecialchars($pconfig['radiusip']);?>"></td>
- </tr><tr>
- <td>Port:</td>
- <td><input name="radiusport" type="text" class="formfld" id="radiusport" size="5" value="<?=htmlspecialchars($pconfig['radiusport']);?>"></td>
- </tr><tr>
- <td>Shared secret:&nbsp;&nbsp;</td>
- <td><input name="radiuskey" type="text" class="formfld" id="radiuskey" size="16" value="<?=htmlspecialchars($pconfig['radiuskey']);?>"> </td>
- </tr>
- <tr>
- <td>Accounting:&nbsp;&nbsp;</td>
- <td><input name="radacct_enable" type="checkbox" id="radacct_enable" value="yes" <?php if($pconfig['radacct_enable']) echo "checked"; ?>>
- send RADIUS accounting packets</td>
- </tr>
- <tr>
- <td>Accounting port:&nbsp;&nbsp;</td>
- <td><input name="radiusacctport" type="text" class="formfld" id="radiusacctport" size="5" value="<?=htmlspecialchars($pconfig['radiusacctport']);?>"></td>
- </tr>
- <tr>
- <td valign="top">Reauthentication:&nbsp;&nbsp;</td>
- <td><input name="reauthenticate" type="checkbox" id="reauthenticate" value="yes" <?php if($pconfig['reauthenticate']) echo "checked"; ?>>
- reauthenticate connected users every minute<br><br>
- <input name="reauthenticateacct" type="radio" value="" <?php if(!$pconfig['reauthenticateacct']) echo "checked"; ?>> no accounting updates<br>
- <input name="reauthenticateacct" type="radio" value="stopstart" <?php if($pconfig['reauthenticateacct'] == "stopstart") echo "checked"; ?>> stop/start accounting<br>
- <input name="reauthenticateacct" type="radio" value="interimupdate" <?php if($pconfig['reauthenticateacct'] == "interimupdate") echo "checked"; ?>> interim update</td>
- </tr>
</table>
- <br>
- When using RADIUS authentication, enter the IP address and port of the RADIUS server which users of the captive portal have to authenticate against. Leave port number blank to use the default port (1812). Leave the RADIUS shared secret blank to not use a RADIUS shared secret. RADIUS accounting packets will also be sent to the RADIUS server if accounting is enabled (default port is 1813).
- <br><br>If reauthentication is enabled, Access-Requests will be sent to the RADIUS server for each user that is logged in every minute. If an Access-Reject is received for a user, that user is disconnected from the captive portal immediately.
+ <table width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td colspan="2" valign="top" class="optsect_t2">Primary RADIUS server</td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">IP address</td>
+ <td class="vtable"><input name="radiusip" type="text" class="formfld" id="radiusip" size="20" value="<?=htmlspecialchars($pconfig['radiusip']);?>"><br>
+ Enter the IP address of the RADIUS server which users of the captive portal have to authenticate against.</td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">Port</td>
+ <td class="vtable"><input name="radiusport" type="text" class="formfld" id="radiusport" size="5" value="<?=htmlspecialchars($pconfig['radiusport']);?>"><br>
+ Leave this field blank to use the default port (1812).</td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">Shared secret&nbsp;&nbsp;</td>
+ <td class="vtable"><input name="radiuskey" type="text" class="formfld" id="radiuskey" size="16" value="<?=htmlspecialchars($pconfig['radiuskey']);?>"><br>
+ Leave this field blank to not use a RADIUS shared secret (not recommended).</td>
+ </tr>
+ <tr>
+ <td colspan="2" class="list" height="12"></td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="optsect_t2">Secondary RADIUS server</td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">IP address</td>
+ <td class="vtable"><input name="radiusip2" type="text" class="formfld" id="radiusip2" size="20" value="<?=htmlspecialchars($pconfig['radiusip2']);?>"><br>
+ If you have a second RADIUS server, you can activate it by entering its IP address here.</td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">Port</td>
+ <td class="vtable"><input name="radiusport2" type="text" class="formfld" id="radiusport2" size="5" value="<?=htmlspecialchars($pconfig['radiusport2']);?>"></td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">Shared secret&nbsp;&nbsp;</td>
+ <td class="vtable"><input name="radiuskey2" type="text" class="formfld" id="radiuskey2" size="16" value="<?=htmlspecialchars($pconfig['radiuskey2']);?>"></td>
+ </tr>
+ <tr>
+ <td colspan="2" class="list" height="12"></td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="optsect_t2">Accounting</td>
+ </tr>
+ <tr>
+ <td class="vncell">&nbsp;</td>
+ <td class="vtable"><input name="radacct_enable" type="checkbox" id="radacct_enable" value="yes" onClick="enable_change(false)" <?php if($pconfig['radacct_enable']) echo "checked"; ?>>
+ <strong>send RADIUS accounting packets</strong><br>
+ If this is enabled, RADIUS accounting packets will be sent to the primary RADIUS server.</td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">Accounting port</td>
+ <td class="vtable"><input name="radiusacctport" type="text" class="formfld" id="radiusacctport" size="5" value="<?=htmlspecialchars($pconfig['radiusacctport']);?>"><br>
+ Leave blank to use the default port (1813).</td>
+ </tr>
+ <tr>
+ <td colspan="2" class="list" height="12"></td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="optsect_t2">Reauthentication</td>
+ </tr>
+ <tr>
+ <td class="vncell">&nbsp;</td>
+ <td class="vtable"><input name="reauthenticate" type="checkbox" id="reauthenticate" value="yes" onClick="enable_change(false)" <?php if($pconfig['reauthenticate']) echo "checked"; ?>>
+ <strong>Reauthenticate connected users every minute</strong><br>
+ If reauthentication is enabled, Access-Requests will be sent to the RADIUS server for each user that is
+ logged in every minute. If an Access-Reject is received for a user, that user is disconnected from the captive portal immediately.</td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">Accounting updates</td>
+ <td class="vtable">
+ <input name="reauthenticateacct" type="radio" value="" <?php if(!$pconfig['reauthenticateacct']) echo "checked"; ?>> no accounting updates<br>
+ <input name="reauthenticateacct" type="radio" value="stopstart" <?php if($pconfig['reauthenticateacct'] == "stopstart") echo "checked"; ?>> stop/start accounting<br>
+ <input name="reauthenticateacct" type="radio" value="interimupdate" <?php if($pconfig['reauthenticateacct'] == "interimupdate") echo "checked"; ?>> interim update
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" class="list" height="12"></td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="optsect_t2">RADIUS MAC authentication</td>
+ </tr>
+ <tr>
+ <td class="vncell">&nbsp;</td>
+ <td class="vtable">
+ <input name="radmac_enable" type="checkbox" id="radmac_enable" value="yes" onClick="enable_change(false)" <?php if ($pconfig['radmac_enable']) echo "checked"; ?>><strong>Enable RADIUS MAC authentication</strong><br>
+ If this option is enabled, the captive portal will try to authenticate users by sending their MAC address as the username and the password
+ entered below to the RADIUS server.</td>
+ </tr>
+ <tr>
+ <td class="vncell">Shared secret</td>
+ <td class="vtable"><input name="radmac_secret" type="text" class="formfld" id="radmac_secret" size="16" value="<?=htmlspecialchars($pconfig['radmac_secret']);?>"></td>
+ </tr>
+ <tr>
+ <td colspan="2" class="list" height="12"></td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="optsect_t2">RADIUS options</td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">Session-Timeout</td>
+ <td class="vtable"><input name="radiussession_timeout" type="checkbox" id="radiussession_timeout" value="yes" <?php if ($pconfig['radiussession_timeout']) echo "checked"; ?>><strong>Use RADIUS Session-Timeout attributes</strong><br>
+ When this is enabled, clients will be disconnected after the amount of time retrieved from the RADIUS Session-Timeout attribute.</td>
+ </tr>
+ <tr>
+ <td class="vncell" valign="top">Type</td>
+ <td class="vtable"><select name="radiusvendor" id="radiusvendor">
+ <option>default</option>
+ <?php
+ $radiusvendors = array("cisco");
+ foreach ($radiusvendors as $radiusvendor){
+ if ($pconfig['radiusvendor'] == $radiusvendor)
+ echo "<option selected value=\"$radiusvendor\">$radiusvendor</option>\n";
+ else
+ echo "<option value=\"$radiusvendor\">$radiusvendor</option>\n";
+ }
+ ?></select><br>
+ If RADIUS type is set to Cisco, in Access-Requests the value of Calling-Station-Id will be set to the client's IP address and
+ the Called-Station-Id to the client's MAC address. Default behaviour is Calling-Station-Id = client's MAC address and Called-Station-Id = m0n0wall's WAN IP address.</td>
+ </tr>
+ </table>
</tr>
<tr>
<td valign="top" class="vncell">HTTPS login</td>
<td class="vtable">
<input name="httpslogin_enable" type="checkbox" class="formfld" id="httpslogin_enable" value="yes" <?php if($pconfig['httpslogin_enable']) echo "checked"; ?>>
<strong>Enable HTTPS login</strong><br>
- If enabled, the username and password will be transmitted over an HTTPS connection to protect against eavesdroppers. This option only applies when RADIUS authentication is used. A server name, certificate and matching private key must also be specified below.</td>
+ If enabled, the username and password will be transmitted over an HTTPS connection to protect against eavesdroppers. A server name, certificate and matching private key must also be specified below.</td>
</tr>
<tr>
<td valign="top" class="vncell">HTTPS server name </td>
@@ -373,7 +520,9 @@ to access after they've authenticated.</td>
<br>
<?php endif; ?>
Upload an HTML file for the portal page here (leave blank to keep the current one). Make sure to include a form (POST to &quot;$PORTAL_ACTION$&quot;)
-with a submit button (name=&quot;accept&quot;) and a hidden field with name=&quot;redirurl&quot; and value=&quot;$PORTAL_REDIRURL$&quot;. Include the &quot;auth_user&quot; and &quot;auth_pass&quot; input elements if RADIUS authentication is enabled. If RADIUS is enabled and no &quot;auth_user&quot; is present, authentication will always fail. If RADIUS is not enabled, you can omit both of these input elements. Example code for the form:<br>
+with a submit button (name=&quot;accept&quot;) and a hidden field with name=&quot;redirurl&quot; and value=&quot;$PORTAL_REDIRURL$&quot;.
+Include the &quot;auth_user&quot; and &quot;auth_pass&quot; input fields if authentication is enabled, otherwise it will always fail.
+Example code for the form:<br>
<br>
<tt>&lt;form method=&quot;post&quot; action=&quot;$PORTAL_ACTION$&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&lt;input name=&quot;auth_user&quot; type=&quot;text&quot;&gt;<br>
@@ -393,7 +542,8 @@ with a submit button (name=&quot;accept&quot;) and a hidden field with name=&quo
<br>
<br>
<?php endif; ?>
-The contents of the HTML file that you upload here are displayed when a RADIUS authentication error occurs.</td>
+The contents of the HTML file that you upload here are displayed when an authentication error occurs.
+You may include &quot;$PORTAL_MESSAGE$&quot;, which will be replaced by the error or reply messages from the RADIUS server, if any.</td>
</tr>
<tr>
<td width="22%" valign="top">&nbsp;</td>
diff --git a/usr/local/www/services_captiveportal_filemanager.php b/usr/local/www/services_captiveportal_filemanager.php
new file mode 100755
index 0000000..dc52194
--- /dev/null
+++ b/usr/local/www/services_captiveportal_filemanager.php
@@ -0,0 +1,168 @@
+<?php
+/*
+ services_captiveportal_filemanager.php
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2005-2006 Jonathan De Graeve (jonathan.de.graeve@imelda.be)
+ and Paul Taylor (paultaylor@winn-dixie.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.
+*/
+
+$pgtitle = "Services:Captive portal";
+
+require_once("guiconfig.inc");
+
+if (!is_array($config['captiveportal']['element']))
+ $config['captiveportal']['element'] = array();
+
+cpelements_sort();
+$a_element = &$config['captiveportal']['element'];
+
+// Calculate total size of all files
+$total_size = 0;
+foreach ($a_element as $element) {
+ $total_size += $element['size'];
+}
+
+if ($_POST) {
+ unset($input_errors);
+
+ if (is_uploaded_file($_FILES['new']['tmp_name'])) {
+
+ $name = $_FILES['new']['name'];
+ $size = filesize($_FILES['new']['tmp_name']);
+
+ // is there already a file with that name?
+ foreach ($a_element as $element) {
+ if ($element['name'] == $name) {
+ $input_errors[] = "A file with the name '$name' already exists.";
+ break;
+ }
+ }
+
+ // check total file size
+ if (($total_size + $size) > $g['captiveportal_element_sizelimit']) {
+ $input_errors[] = "The total size of all files uploaded may not exceed " .
+ format_bytes($g['captiveportal_element_sizelimit']) . ".";
+ }
+
+ if (!$input_errors) {
+ $element = array();
+ $element['name'] = $name;
+ $element['size'] = $size;
+ $element['content'] = base64_encode(file_get_contents($_FILES['new']['tmp_name']));
+
+ $a_element[] = $element;
+
+ write_config();
+ captiveportal_write_elements();
+ header("Location: services_captiveportal_filemanager.php");
+ exit;
+ }
+ }
+} else {
+ if (($_GET['act'] == "del") && $a_element[$_GET['id']]) {
+ unset($a_element[$_GET['id']]);
+ write_config();
+ captiveportal_write_elements();
+ header("Location: services_captiveportal_filemanager.php");
+ exit;
+ }
+}
+
+include("head.inc");
+
+?>
+<?php include("fbegin.inc"); ?>
+<p class="pgtitle"><?=$pgtitle?></p>
+<form action="services_captiveportal_filemanager.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr><td class="tabnavtbl">
+<?php
+ $tab_array = array();
+ $tab_array[] = array("Captive portal", false, "services_captiveportal.php");
+ $tab_array[] = array("Pass-through MAC", false, "services_captiveportal_mac.php");
+ $tab_array[] = array("Allowed IP addresses", false, "services_captiveportal_ip.php");
+ $tab_array[] = array("Users", false, "services_captiveportal_users.php");
+ $tab_array[] = array("File Manager", true, "services_captiveportal_filemanager.php");
+ display_top_tabs($tab_array);
+?> </td></tr>
+ <tr>
+ <td class="tabcont">
+ <table width="80%" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td width="70%" class="listhdrr">Name</td>
+ <td width="20%" class="listhdr">Size</td>
+ <td width="10%" class="list"></td>
+ </tr>
+ <?php $i = 0; foreach ($a_element as $element): ?>
+ <tr>
+ <td class="listlr"><?=htmlspecialchars($element['name']);?></td>
+ <td class="listr" align="right"><?=format_bytes($element['size']);?></td>
+ <td valign="middle" nowrap class="list">
+ <a href="services_captiveportal_filemanager.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this file?')"><img src="/themes/<?php echo $g['theme']; ?>/images/icons/icon_x.gif" title="delete file" width="17" height="17" border="0"></a>
+ </td>
+ </tr>
+ <?php $i++; endforeach; ?>
+
+ <?php if (count($a_element) > 0): ?>
+ <tr>
+ <td class="listlr" style="background-color: #eee"><strong>TOTAL</strong></td>
+ <td class="listr" style="background-color: #eee" align="right"><strong><?=format_bytes($total_size);?></strong></td>
+ <td valign="middle" nowrap class="list"></td>
+ </tr>
+ <?php endif; ?>
+
+ <?php if ($_GET['act'] == 'add'): ?>
+ <tr>
+ <td class="listlr" colspan="2"><input type="file" name="new" class="formfld" size="40" id="new">
+ <input name="Submit" type="submit" class="formbtn" value="Upload"></td>
+ <td valign="middle" nowrap class="list">
+ <a href="services_captiveportal_filemanager.php"><img src="/themes/<?php echo $g['theme']; ?>/images/icons/icon_x.gif" title="cancel" width="17" height="17" border="0"></a>
+ </td>
+ </tr>
+ <?php else: ?>
+ <tr>
+ <td class="list" colspan="2"></td>
+ <td class="list"> <a href="services_captiveportal_filemanager.php?act=add"><img src="/themes/<?php echo $g['theme']; ?>/images/icons/icon_plus.gif" title="add file" width="17" height="17" border="0"></a></td>
+ </tr>
+ <?php endif; ?>
+ </table>
+ <span class="vexpl"><span class="red"><strong>
+ Note:<br>
+ </strong></span>
+ Any files that you upload here will be made available in the root directory
+ of the captive portal HTTP(S) server. You may reference them directly from
+ your portal page HTML code using relative paths. Example: you've uploaded
+ an image with the name 'test.jpg' using the file manager. Then you can
+ include it in your portal page like this:<br><br>
+ <tt>&lt;img src=&quot;test.jpg&quot; width=... height=...&gt;</tt>
+ <br><br>
+ The total size limit for all files is <?=format_bytes($g['captiveportal_element_sizelimit']);?>.</span>
+</td>
+</tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
diff --git a/usr/local/www/services_captiveportal_ip.php b/usr/local/www/services_captiveportal_ip.php
index 0ed1632..b0f9a40 100755
--- a/usr/local/www/services_captiveportal_ip.php
+++ b/usr/local/www/services_captiveportal_ip.php
@@ -28,7 +28,7 @@
POSSIBILITY OF SUCH DAMAGE.
*/
-$pgtitle = array("Services", "Captive portal");
+$pgtitle = "Services:Captive portal";
require("guiconfig.inc");
if (!is_array($config['captiveportal']['allowedip']))
@@ -43,9 +43,9 @@ if ($_POST) {
if ($_POST['apply']) {
$retval = 0;
-
- $retval = captiveportal_allowedip_configure();
-
+ if (!file_exists($d_sysrebootreqd_path)) {
+ $retval = captiveportal_allowedip_configure();
+ }
$savemsg = get_std_save_message($retval);
if ($retval == 0) {
if (file_exists($d_allowedipsdirty_path)) {
@@ -67,27 +67,26 @@ if ($_GET['act'] == "del") {
}
}
-$pgtitle = "Services: Captive Portal IP";
-include("head.inc");
+include("head.inc");
?>
-<body link="#000000" vlink="#000000" alink="#000000">
<?php include("fbegin.inc"); ?>
-<p class="pgtitle">Services: Captive portal IP</p>
+<p class="pgtitle"><?=$pgtitle?></p>
<form action="services_captiveportal_ip.php" method="post">
<?php if ($savemsg) print_info_box($savemsg); ?>
<?php if (file_exists($d_allowedipsdirty_path)): ?><p>
<?php print_info_box_np("The captive portal IP address configuration has been changed.<br>You must apply the changes in order for them to take effect.");?><br>
-</p>
+<input name="apply" type="submit" class="formbtn" id="apply" value="Apply changes"></p>
<?php endif; ?>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
- <tr><td class="tabnavtbl">
+ <tr><td class="tabnavtbl">
<?php
$tab_array = array();
$tab_array[] = array("Captive portal", false, "services_captiveportal.php");
$tab_array[] = array("Pass-through MAC", false, "services_captiveportal_mac.php");
$tab_array[] = array("Allowed IP addresses", true, "services_captiveportal_ip.php");
$tab_array[] = array("Users", false, "services_captiveportal_users.php");
+ $tab_array[] = array("File Manager", true, "services_captiveportal_filemanager.php");
display_top_tabs($tab_array);
?>
</td></tr>
@@ -128,14 +127,14 @@ include("head.inc");
Adding allowed IP addresses will allow IP access to/from these addresses through the captive portal without being taken to the portal page. This can be used for a web server serving images for the portal page or a DNS server on another network, for example. By specifying <em>from</em> addresses, it may be used to always allow pass-through access from a client behind the captive portal.</p>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
- <td><span class="vexpl">any <img src="/themes/<?php echo $g['theme']; ?>/images/icons/icon_in.gif" width="11" height="11" align="absmiddle"> x.x.x.x </span></td>
+ <td><span class="vexpl">any <img src="/themes/<=$g['theme'];?>/images/icons/icon_in.gif" width="11" height="11" align="absmiddle"> x.x.x.x </span></td>
<td><span class="vexpl">All connections <strong>to</strong> the IP address are allowed</span></td>
</tr>
<tr>
<td colspan="5" height="4"></td>
</tr>
<tr>
- <td>x.x.x.x <span class="vexpl"><img src="/themes/<?php echo $g['theme']; ?>/images/icons/icon_in.gif" width="11" height="11" align="absmiddle"></span> any&nbsp;&nbsp;&nbsp; </td>
+ <td>x.x.x.x <span class="vexpl"><img src="/themes/<=$g['theme'];?>/images/icons/icon_in.gif" width="11" height="11" align="absmiddle"></span> any&nbsp;&nbsp;&nbsp; </td>
<td><span class="vexpl">All connections <strong>from</strong> the IP address are allowed </span></td>
</tr>
</table></td>
diff --git a/usr/local/www/services_captiveportal_ip_edit.php b/usr/local/www/services_captiveportal_ip_edit.php
index 6e70f2e..4478abd 100755
--- a/usr/local/www/services_captiveportal_ip_edit.php
+++ b/usr/local/www/services_captiveportal_ip_edit.php
@@ -28,7 +28,7 @@
POSSIBILITY OF SUCH DAMAGE.
*/
-$pgtitle = array("Services", "Captive portal", "Edit allowed IP address");
+$pgtitle = "Services:Captive portal:Edit allowed IP address";
require("guiconfig.inc");
if (!is_array($config['captiveportal']['allowedip']))
@@ -92,15 +92,13 @@ if ($_POST) {
}
}
-$pgtitle = "Services: Captive Portal Edit Allowed IP Address";
include("head.inc");
?>
-<body link="#000000" vlink="#000000" alink="#000000">
<?php include("fbegin.inc"); ?>
-<p class="pgtitle">Services: Captive portal IP Edit</p>
<?php if ($input_errors) print_input_errors($input_errors); ?>
- <form action="services_captiveportal_ip_edit.php" method="post" name="iform" id="iform">
+<p class="pgtitle"><?=$pgtitle?></p>
+ <form action="services_captiveportal_ip_edit.php" method="post" name="iform" id="iform">
<table width="100%" border="0" cellpadding="6" cellspacing="0">
<tr>
<td width="22%" valign="top" class="vncellreq">Direction</td>
diff --git a/usr/local/www/services_captiveportal_mac.php b/usr/local/www/services_captiveportal_mac.php
index e793345..1a81080 100755
--- a/usr/local/www/services_captiveportal_mac.php
+++ b/usr/local/www/services_captiveportal_mac.php
@@ -28,7 +28,7 @@
POSSIBILITY OF SUCH DAMAGE.
*/
-$pgtitle = array("Services", "Captive portal");
+$pgtitle = "Services:Captive portal";
require("guiconfig.inc");
if (!is_array($config['captiveportal']['passthrumac']))
@@ -43,9 +43,9 @@ if ($_POST) {
if ($_POST['apply']) {
$retval = 0;
-
- $retval = captiveportal_passthrumac_configure();
-
+ if (!file_exists($d_sysrebootreqd_path)) {
+ $retval = captiveportal_passthrumac_configure();
+ }
$savemsg = get_std_save_message($retval);
if ($retval == 0) {
if (file_exists($d_passthrumacsdirty_path)) {
@@ -67,18 +67,16 @@ if ($_GET['act'] == "del") {
}
}
-$pgtitle = "Services: Captive Portal MACS";
include("head.inc");
?>
-<body link="#000000" vlink="#000000" alink="#000000">
<?php include("fbegin.inc"); ?>
+<p class="pgtitle"><?=$pgtitle?></p>
<form action="services_captiveportal_mac.php" method="post">
-<p class="pgtitle">Services: Captive portal MAC</p>
<?php if ($savemsg) print_info_box($savemsg); ?>
<?php if (file_exists($d_passthrumacsdirty_path)): ?><p>
<?php print_info_box_np("The captive portal MAC address configuration has been changed.<br>You must apply the changes in order for them to take effect.");?><br>
-</p>
+<input name="apply" type="submit" class="formbtn" id="apply" value="Apply changes"></p>
<?php endif; ?>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td class="tabnavtbl">
@@ -88,6 +86,7 @@ include("head.inc");
$tab_array[] = array("Pass-through MAC", true, "services_captiveportal_mac.php");
$tab_array[] = array("Allowed IP addresses", false, "services_captiveportal_ip.php");
$tab_array[] = array("Users", false, "services_captiveportal_users.php");
+ $tab_array[] = array("File Manager", true, "services_captiveportal_filemanager.php");
display_top_tabs($tab_array);
?>
</td></tr>
diff --git a/usr/local/www/services_captiveportal_mac_edit.php b/usr/local/www/services_captiveportal_mac_edit.php
index 66236a6..07719cc 100755
--- a/usr/local/www/services_captiveportal_mac_edit.php
+++ b/usr/local/www/services_captiveportal_mac_edit.php
@@ -28,7 +28,7 @@
POSSIBILITY OF SUCH DAMAGE.
*/
-$pgtitle = array("Services", "Captive portal", "Edit pass-through MAC address");
+$pgtitle = "Services:Captive portal:Edit pass-through MAC address";
require("guiconfig.inc");
if (!is_array($config['captiveportal']['passthrumac']))
@@ -91,16 +91,12 @@ if ($_POST) {
exit;
}
}
-
-$pgtitle = "Services: Captive Portal Edit MAC";
include("head.inc");
-
?>
-<body link="#000000" vlink="#000000" alink="#000000">
<?php include("fbegin.inc"); ?>
-<p class="pgtitle">Services: Captive portal MAC Edit</p>
<?php if ($input_errors) print_input_errors($input_errors); ?>
- <form action="services_captiveportal_mac_edit.php" method="post" name="iform" id="iform">
+<p class="pgtitle"><?=$pgtitle?></p>
+ <form action="services_captiveportal_mac_edit.php" method="post" name="iform" id="iform">
<table width="100%" border="0" cellpadding="6" cellspacing="0">
<tr>
<td width="22%" valign="top" class="vncellreq">MAC address</td>
diff --git a/usr/local/www/services_captiveportal_users.php b/usr/local/www/services_captiveportal_users.php
index 154abef..a55f873 100755
--- a/usr/local/www/services_captiveportal_users.php
+++ b/usr/local/www/services_captiveportal_users.php
@@ -3,7 +3,7 @@
services_captiveportal_users.php
part of m0n0wall (http://m0n0.ch/wall)
- Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
+ Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
All rights reserved.
Copyright (C) 2005 Pascal Suter <d-monodev@psuter.ch>.
All rights reserved.
@@ -30,7 +30,7 @@
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
-$pgtitle = array("Services", "Captive portal");
+$pgtitle = "Services:Captive portal";
require("guiconfig.inc");
if (!is_array($config['captiveportal']['user'])) {
@@ -62,13 +62,11 @@ if ($changed) {
exit;
}
-$pgtitle = "Services: Captive Portal";
include("head.inc");
?>
-<body link="#000000" vlink="#000000" alink="#000000">
<?php include("fbegin.inc"); ?>
-<p class="pgtitle">Services: Captive portal Users</p>
+<p class="pgtitle"><?=$pgtitle?></p>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td>
<?php
@@ -77,6 +75,7 @@ include("head.inc");
$tab_array[] = array("Pass-through MAC", false, "services_captiveportal_mac.php");
$tab_array[] = array("Allowed IP addresses", false, "services_captiveportal_ip.php");
$tab_array[] = array("Users", true, "services_captiveportal_users.php");
+ $tab_array[] = array("File Manager", true, "services_captiveportal_filemanager.php");
display_top_tabs($tab_array);
?>
</td></tr>
@@ -113,18 +112,3 @@ include("head.inc");
</tr>
</table>
<?php include("fend.inc"); ?>
-
-<?php
-
-function captiveportal_users_sort() {
- global $g, $config;
-
- function cpusercmp($a, $b) {
- return strcasecmp($a['name'], $b['name']);
- }
-
- usort($config['captiveportal']['user'], "cpusercmp");
-}
-
-
-?> \ No newline at end of file
diff --git a/usr/local/www/services_captiveportal_users_edit.php b/usr/local/www/services_captiveportal_users_edit.php
index 1198f15..917bed1 100755
--- a/usr/local/www/services_captiveportal_users_edit.php
+++ b/usr/local/www/services_captiveportal_users_edit.php
@@ -3,7 +3,7 @@
services_captiveportal_users_edit.php
part of m0n0wall (http://m0n0.ch/wall)
- Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
+ Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
All rights reserved.
Copyright (C) 2005 Pascal Suter <d-monodev@psuter.ch>.
All rights reserved.
@@ -30,7 +30,7 @@
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
-$pgtitle = array("Services", "Captive portal", "Edit user");
+$pgtitle = "Services: Captive portal: Edit user";
require("guiconfig.inc");
if (!is_array($config['captiveportal']['user'])) {
@@ -123,11 +123,10 @@ if ($_POST) {
}
}
-$pgtitle = "Services: Captive Portal Users Edit";
include("head.inc");
?>
-<body link="#000000" vlink="#000000" alink="#000000">
+?>
<?php include("fbegin.inc"); ?>
<script language="javascript" type="text/javascript" src="datetimepicker.js">
<!--
@@ -136,8 +135,8 @@ include("head.inc");
//For this script, visit http://www.javascriptkit.com
// -->
</script>
-<p class="pgtitle">Services: Captive portal Users Edit</p>
<?php if ($input_errors) print_input_errors($input_errors); ?>
+<p class="pgtitle"><?=$pgtitle?></p>
<form action="services_captiveportal_users_edit.php" method="post" name="iform" id="iform">
<table width="100%" border="0" cellpadding="6" cellspacing="0">
<tr>
@@ -183,17 +182,3 @@ include("head.inc");
</table>
</form>
<?php include("fend.inc"); ?>
-<?php
-
-function captiveportal_users_sort() {
- global $g, $config;
-
- function cpusercmp($a, $b) {
- return strcasecmp($a['name'], $b['name']);
- }
-
- usort($config['captiveportal']['user'], "cpusercmp");
-}
-
-
-?> \ No newline at end of file
OpenPOWER on IntegriCloud