summaryrefslogtreecommitdiffstats
path: root/etc/inc/captiveportal.inc
diff options
context:
space:
mode:
authorVinicius Coque <vinicius.coque@bluepex.com>2011-03-25 08:49:04 -0300
committerVinicius Coque <vinicius.coque@bluepex.com>2011-03-25 08:49:04 -0300
commit54bdff758f68e2e1b1ebd42b8b0b629b68ed1a3d (patch)
tree27b7d45e582e3d84cdf8d0fa0f3bc93b65f3c986 /etc/inc/captiveportal.inc
parentb845290619244e8cfe3bc2aa6271c6629eeb86b5 (diff)
parent401fb0ad8fa7ad06743435808dac8e913b3c16bb (diff)
downloadpfsense-54bdff758f68e2e1b1ebd42b8b0b629b68ed1a3d.zip
pfsense-54bdff758f68e2e1b1ebd42b8b0b629b68ed1a3d.tar.gz
Merge remote-tracking branch 'mainline/master' into inc
Conflicts: etc/inc/auth.inc etc/inc/config.lib.inc etc/inc/filter.inc etc/inc/pfsense-utils.inc etc/inc/pkg-utils.inc etc/inc/priv.defs.inc etc/inc/services.inc etc/inc/shaper.inc etc/inc/voucher.inc etc/inc/vpn.inc usr/local/www/fbegin.inc
Diffstat (limited to 'etc/inc/captiveportal.inc')
-rw-r--r--etc/inc/captiveportal.inc611
1 files changed, 512 insertions, 99 deletions
diff --git a/etc/inc/captiveportal.inc b/etc/inc/captiveportal.inc
index 4a3b80d..6535f54 100644
--- a/etc/inc/captiveportal.inc
+++ b/etc/inc/captiveportal.inc
@@ -211,6 +211,8 @@ function captiveportal_configure() {
if ($g['booting'])
echo "Starting captive portal... ";
+ else
+ captiveportal_syslog("Restarting captive portal.");
/* kill any running mini_httpd */
killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
@@ -226,7 +228,7 @@ function captiveportal_configure() {
touch("{$g['vardb_path']}/captiveportal.db");
/* kill any running minicron */
- killbypid("{$g['varrun_path']}/minicron.pid");
+ killbypid("{$g['varrun_path']}/cp_prunedb.pid");
/* init ipfw rules */
captiveportal_init_rules(true);
@@ -417,8 +419,12 @@ EOD;
/* start up the webserving daemon */
captiveportal_init_webgui();
+ /* Kill any existing prunecaptiveportal processes */
+ if(file_exists("{$g['varrun_path']}/cp_prunedb.pid"))
+ killbypid("{$g['varrun_path']}/cp_prunedb.pid");
+
/* start pruning process (interval defaults to 60 seconds) */
- mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/minicron.pid " .
+ mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/cp_prunedb.pid " .
"/etc/rc.prunecaptiveportal");
/* generate radius server database */
@@ -429,7 +435,7 @@ EOD;
} else {
killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
- killbypid("{$g['varrun_path']}/minicron.pid");
+ killbypid("{$g['varrun_path']}/cp_prunedb.pid");
captiveportal_radius_stop_all();
@@ -498,6 +504,7 @@ function captiveportal_init_webgui() {
$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal-SSL.conf");
}
+/* reinit will disconnect all users, be careful! */
function captiveportal_init_rules($reinit = false) {
global $config, $g;
@@ -708,48 +715,47 @@ function captiveportal_prune_old() {
!isset($config['captiveportal']['radiussession_timeout']) && !isset($config['voucher']['enable']))
return;
+ $radiusservers = captiveportal_get_radius_servers();
+
/* read database */
$cpdb = captiveportal_read_db();
- $radiusservers = captiveportal_get_radius_servers();
-
/* To make sure we iterate over ALL accounts on every run the count($cpdb) is moved
* outside of the loop. Otherwise the loop would evaluate count() on every iteration
* and since $i would increase and count() would decrement they would meet before we
* had a chance to iterate over all accounts.
*/
$unsetindexes = array();
- $no_users = count($cpdb);
- for ($i = 0; $i < $no_users; $i++) {
+ foreach ($cpdb as $cpentry) {
$timedout = false;
$term_cause = 1;
/* hard timeout? */
if ($timeout) {
- if ((time() - $cpdb[$i][0]) >= $timeout) {
+ if ((time() - $cpentry[0]) >= $timeout) {
$timedout = true;
$term_cause = 5; // Session-Timeout
}
}
/* Session-Terminate-Time */
- if (!$timedout && !empty($cpdb[$i][9])) {
- if (time() >= $cpdb[$i][9]) {
+ if (!$timedout && !empty($cpentry[9])) {
+ if (time() >= $cpentry[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 */
- $uidletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout;
+ $uidletimeout = (is_numeric($cpentry[8])) ? $cpentry[8] : $idletimeout;
/* if an idle timeout is specified, get last activity timestamp from ipfw */
if (!$timedout && $uidletimeout) {
- $lastact = captiveportal_get_last_activity($cpdb[$i][2]);
+ $lastact = captiveportal_get_last_activity($cpentry[2]);
/* If the user has logged on but not sent any traffic they will never be logged out.
* We "fix" this by setting lastact to the login timestamp.
*/
- $lastact = $lastact ? $lastact : $cpdb[$i][0];
+ $lastact = $lastact ? $lastact : $cpentry[0];
if ($lastact && ((time() - $lastact) >= $uidletimeout)) {
$timedout = true;
$term_cause = 4; // Idle-Timeout
@@ -758,25 +764,25 @@ function captiveportal_prune_old() {
}
/* if vouchers are configured, activate session timeouts */
- if (!$timedout && isset($config['voucher']['enable']) && !empty($cpdb[$i][7])) {
- if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) {
+ if (!$timedout && isset($config['voucher']['enable']) && !empty($cpentry[7])) {
+ if (time() >= ($cpentry[0] + $cpentry[7])) {
$timedout = true;
$term_cause = 5; // Session-Timeout
}
}
/* 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])) {
+ if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpentry[7])) {
+ if (time() >= ($cpentry[0] + $cpentry[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");
- $unsetindexes[$i] = $i;
+ captiveportal_disconnect($cpentry, $radiusservers,$term_cause,$stop_time);
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "TIMEOUT");
+ $unsetindexes[] = $cpentry[5];
}
/* do periodic RADIUS reauthentication? */
@@ -784,30 +790,30 @@ function captiveportal_prune_old() {
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
+ RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno
+ $cpentry[4], // username
+ $cpentry[5], // sessionid
+ $cpentry[0], // start time
$radiusservers,
- $cpdb[$i][2], // clientip
- $cpdb[$i][3], // clientmac
+ $cpentry[2], // clientip
+ $cpentry[3], // clientmac
10); // NAS Request
- exec("/sbin/ipfw table 1 entryzerostats {$cpdb[$i][2]}");
- exec("/sbin/ipfw table 2 entryzerostats {$cpdb[$i][2]}");
- RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno
- $cpdb[$i][4], // username
- $cpdb[$i][5], // sessionid
+ exec("/sbin/ipfw table 1 entryzerostats {$cpentry[2]}");
+ exec("/sbin/ipfw table 2 entryzerostats {$cpentry[2]}");
+ RADIUS_ACCOUNTING_START($cpentry[1], // ruleno
+ $cpentry[4], // username
+ $cpentry[5], // sessionid
$radiusservers,
- $cpdb[$i][2], // clientip
- $cpdb[$i][3]); // clientmac
+ $cpentry[2], // clientip
+ $cpentry[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
+ RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno
+ $cpentry[4], // username
+ $cpentry[5], // sessionid
+ $cpentry[0], // start time
$radiusservers,
- $cpdb[$i][2], // clientip
- $cpdb[$i][3], // clientmac
+ $cpentry[2], // clientip
+ $cpentry[3], // clientmac
10, // NAS Request
true); // Interim Updates
}
@@ -815,26 +821,24 @@ function captiveportal_prune_old() {
/* check this user against RADIUS again */
if (isset($config['captiveportal']['reauthenticate'])) {
- $auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username
- base64_decode($cpdb[$i][6]), // password
+ $auth_list = RADIUS_AUTHENTICATION($cpentry[4], // username
+ base64_decode($cpentry[6]), // password
$radiusservers,
- $cpdb[$i][2], // clientip
- $cpdb[$i][3], // clientmac
- $cpdb[$i][1]); // ruleno
+ $cpentry[2], // clientip
+ $cpentry[3], // clientmac
+ $cpentry[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']);
- $unsetindexes[$i] = $i;
+ captiveportal_disconnect($cpentry, $radiusservers, 17);
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "RADIUS_DISCONNECT", $auth_list['reply_message']);
+ $unsetindexes[] = $cpentry[5];
}
}
}
}
- /* This is a kludge to overcome some php weirdness */
- foreach($unsetindexes as $unsetindex)
- unset($cpdb[$unsetindex]);
/* write database */
- captiveportal_write_db($cpdb);
+ if (!empty($unsetindexes))
+ captiveportal_write_db($cpdb, false, $unsetindexes);
}
/* remove a single client according to the DB entry */
@@ -856,12 +860,15 @@ function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_t
false,
$stop_time);
}
- /* Delete client's ip entry from tables 3 and 4. */
- mwexec("/sbin/ipfw table 1 delete {$dbent[2]}");
- mwexec("/sbin/ipfw table 2 delete {$dbent[2]}");
-
- /* Release the ruleno so it can be reallocated to new clients. */
- captiveportal_free_ipfw_ruleno($dbent[1]);
+
+ if (is_ipaddr($dbent[2])) {
+ /* Delete client's ip entry from tables 3 and 4. */
+ mwexec("/sbin/ipfw table 1 delete {$dbent[2]}");
+ mwexec("/sbin/ipfw table 2 delete {$dbent[2]}");
+ /* XXX: Redundant?! Ensure all pf(4) states are killed. */
+ mwexec("pfctl -k {$dbent[2]}");
+ mwexec("pfctl -K {$dbent[2]}");
+ }
/*
* These are the pipe numbers we use to control traffic shaping for each logged in user via captive portal
@@ -872,32 +879,33 @@ function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_t
mwexec("/sbin/ipfw pipe " . ($dbent[1]+20001) . " delete");
}
- /* XXX: Redundant?! Ensure all pf(4) states are killed. */
- mwexec("pfctl -k {$dbent[2]}");
- mwexec("pfctl -K {$dbent[2]}");
-
+ /* Release the ruleno so it can be reallocated to new clients. */
+ captiveportal_free_ipfw_ruleno($dbent[1]);
}
-/* remove a single client by ipfw rule number */
-function captiveportal_disconnect_client($id,$term_cause = 1) {
+/* remove a single client by sessionid */
+function captiveportal_disconnect_client($sessionid, $term_cause = 1, $logoutReason = "LOGOUT") {
global $g, $config;
- /* read database */
- $cpdb = captiveportal_read_db();
$radiusservers = captiveportal_get_radius_servers();
+ $unsetindex = array();
+
+ $cpdblck = lock('captiveportaldb', LOCK_EX);
+
+ /* read database */
+ $cpdb = captiveportal_read_db(true);
/* find entry */
- foreach ($cpdb as $i => $cpentry) {
- if ($cpentry[1] == $id) {
- captiveportal_disconnect($cpentry, $radiusservers, $term_cause);
- captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "DISCONNECT");
- unset($cpdb[$i]);
- break;
- }
- }
+ if (isset($cpdb[$sessionid])) {
+ $cpentry = $cpdb[$sessionid];
+ /* write database */
+ $unsetindex[] = $sessionid;
+ captiveportal_write_db($cpdb, true, $unsetindex);
+ unlock($cpdblck);
- /* write database */
- captiveportal_write_db($cpdb);
+ captiveportal_disconnect($cpentry, $radiusservers, $term_cause);
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "DISCONNECT");
+ }
}
/* send RADIUS acct stop for all current clients */
@@ -1077,10 +1085,10 @@ function setup_dnsfilter_entries() {
$cp_filterdns_conf = "";
if (is_array($config['captiveportal']['allowedhostname'])) {
foreach ($config['captiveportal']['allowedhostname'] as $hostnameent) {
- $cp_filterdns_conf .= "ipfw $hostnameent 3 '/etc/rc.captiveportal_configure'\n";
- $cp_filterdns_conf .= "ipfw $hostnameent 4 '/etc/rc.captiveportal_configure'\n";
- $cp_filterdns_conf .= "ipfw $hostnameent 7 '/etc/rc.captiveportal_configure'\n";
- $cp_filterdns_conf .= "ipfw $hostnameent 8 '/etc/rc.captiveportal_configure'\n";
+ $cp_filterdns_conf .= "ipfw {$hostnameent['hostname']} 3\n";
+ $cp_filterdns_conf .= "ipfw {$hostnameent['hostname']} 4\n";
+ $cp_filterdns_conf .= "ipfw {$hostnameent['hostname']} 7\n";
+ $cp_filterdns_conf .= "ipfw {$hostnameent['hostname']} 8\n";
}
}
file_put_contents($cp_filterdns_filename, $cp_filterdns_conf);
@@ -1254,38 +1262,54 @@ function radius($username,$password,$clientip,$clientmac,$type) {
}
/* read captive portal DB into array */
-function captiveportal_read_db() {
- global $g;
+function captiveportal_read_db($locked = false) {
+ global $g;
- $cpdb = array();
+ $cpdb = array();
+ if ($locked == false)
$cpdblck = lock('captiveportaldb');
- $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
- if ($fd) {
- while (!feof($fd)) {
- $line = trim(fgets($fd));
- if ($line)
- $cpdb[] = explode(",", $line);
+ $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
+ if ($fd) {
+ while (!feof($fd)) {
+ $line = trim(fgets($fd));
+ if ($line) {
+ $cpe = explode(",", $line);
+ /* Hash by session id */
+ $cpdb[$cpe[5]] = $cpe;
}
- fclose($fd);
}
+ fclose($fd);
+ }
+ if ($locked == false)
unlock($cpdblck);
- return $cpdb;
+ return $cpdb;
}
/* write captive portal DB */
-function captiveportal_write_db($cpdb) {
- global $g;
+function captiveportal_write_db($cpdb, $locked = false, $remove = false) {
+ global $g;
+ if ($locked == false)
$cpdblck = lock('captiveportaldb', LOCK_EX);
- $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
- if ($fd) {
- foreach ($cpdb as $cpent) {
- fwrite($fd, join(",", $cpent) . "\n");
- }
- fclose($fd);
+
+ if (is_array($remove)) {
+ if (!empty($remove)) {
+ $cpdb = captiveportal_read_db(true);
+ foreach ($remove as $key)
+ unset($cpdb[$key]);
+ } else
+ return; //This makes sure no record removal calls
+ }
+ $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
+ if ($fd) {
+ foreach ($cpdb as $cpent) {
+ fwrite($fd, join(",", $cpent) . "\n");
}
- unlock($cpdblck);
+ fclose($fd);
+ }
+ if ($locked == false)
+ unlock($cpdblck);
}
function captiveportal_write_elements() {
@@ -1515,4 +1539,393 @@ function portal_ip_from_client_ip($cliip) {
return false;
}
+/* functions move from index.php */
+
+function portal_reply_page($redirurl, $type = null, $message = null, $clientmac = null, $clientip = null, $username = null, $password = null) {
+ global $g, $config;
+
+ /* Get captive portal layout */
+ if ($type == "redir") {
+ header("Location: {$redirurl}");
+ return;
+ } else if ($type == "login")
+ $htmltext = get_include_contents("{$g['varetc_path']}/captiveportal.html");
+ else
+ $htmltext = get_include_contents("{$g['varetc_path']}/captiveportal-error.html");
+
+ /* substitute the PORTAL_REDIRURL variable */
+ if ($config['captiveportal']['preauthurl']) {
+ $htmltext = str_replace("\$PORTAL_REDIRURL\$", "{$config['captiveportal']['preauthurl']}", $htmltext);
+ $htmltext = str_replace("#PORTAL_REDIRURL#", "{$config['captiveportal']['preauthurl']}", $htmltext);
+ }
+
+ /* substitute other variables */
+ if (isset($config['captiveportal']['httpslogin'])) {
+ $htmltext = str_replace("\$PORTAL_ACTION\$", "https://{$config['captiveportal']['httpsname']}:8001/", $htmltext);
+ $htmltext = str_replace("#PORTAL_ACTION#", "https://{$config['captiveportal']['httpsname']}:8001/", $htmltext);
+ } else {
+ $ifip = portal_ip_from_client_ip($clientip);
+ if (!$ifip)
+ $ourhostname = $config['system']['hostname'] . ":8000";
+ else
+ $ourhostname = "{$ifip}:8000";
+ $htmltext = str_replace("\$PORTAL_ACTION\$", "http://{$ourhostname}/", $htmltext);
+ $htmltext = str_replace("#PORTAL_ACTION#", "http://{$ourhostname}/", $htmltext);
+ }
+
+ $htmltext = str_replace("\$PORTAL_REDIRURL\$", htmlspecialchars($redirurl), $htmltext);
+ $htmltext = str_replace("\$PORTAL_MESSAGE\$", htmlspecialchars($message), $htmltext);
+ $htmltext = str_replace("\$CLIENT_MAC\$", htmlspecialchars($clientmac), $htmltext);
+ $htmltext = str_replace("\$CLIENT_IP\$", htmlspecialchars($clientip), $htmltext);
+
+ // Special handling case for captive portal master page so that it can be ran
+ // through the PHP interpreter using the include method above. We convert the
+ // $VARIABLE$ case to #VARIABLE# in /etc/inc/captiveportal.inc before writing out.
+ $htmltext = str_replace("#PORTAL_REDIRURL#", htmlspecialchars($redirurl), $htmltext);
+ $htmltext = str_replace("#PORTAL_MESSAGE#", htmlspecialchars($message), $htmltext);
+ $htmltext = str_replace("#CLIENT_MAC#", htmlspecialchars($clientmac), $htmltext);
+ $htmltext = str_replace("#CLIENT_IP#", htmlspecialchars($clientip), $htmltext);
+ $htmltext = str_replace("#USERNAME#", htmlspecialchars($username), $htmltext);
+ $htmltext = str_replace("#PASSWORD#", htmlspecialchars($password), $htmltext);
+
+ echo $htmltext;
+}
+
+function portal_mac_radius($clientmac,$clientip) {
+ global $config ;
+
+ $radmac_secret = $config['captiveportal']['radmac_secret'];
+
+ /* authentication against the radius server */
+ $username = mac_format($clientmac);
+ $auth_list = radius($username,$radmac_secret,$clientip,$clientmac,"MACHINE LOGIN");
+ if ($auth_list['auth_val'] == 2)
+ return TRUE;
+ if (!empty($auth_list['url_redirection']))
+ portal_reply_page($auth_list['url_redirection'], "redir");
+
+ return FALSE;
+}
+
+function portal_allow($clientip,$clientmac,$username,$password = null, $attributes = null, $ruleno = null) {
+
+ global $redirurl, $g, $config, $type, $passthrumac, $_POST;
+
+ /* See if a ruleno is passed, if not start sessions because this means there isn't one atm */
+ if ($ruleno == null)
+ $ruleno = captiveportal_get_next_ipfw_ruleno();
+
+ /* if the pool is empty, return appropriate message and exit */
+ if (is_null($ruleno)) {
+ portal_reply_page($redirurl, "error", "System reached maximum login capacity");
+ log_error("WARNING! Captive portal has reached maximum login capacity");
+ exit;
+ }
+
+ // Ensure we create an array if we are missing attributes
+ if (!is_array($attributes))
+ $attributes = array();
+
+ $radiusservers = captiveportal_get_radius_servers();
+
+ /* Do not allow concurrent login execution. */
+ $cpdblck = lock('captiveportaldb', LOCK_EX);
+
+ unset($sessionid);
+
+ /* read in client database */
+ $cpdb = captiveportal_read_db(true);
+
+ if ($attributes['voucher'])
+ $remaining_time = $attributes['session_timeout'];
+
+ $writecfg = false;
+ /* Find an existing session */
+ if ((isset($config['captiveportal']['noconcurrentlogins'])) && $passthrumac) {
+ if (isset($config['captiveportal']['passthrumacadd'])) {
+ $mac = captiveportal_passthrumac_findbyname($username);
+ if (!empty($mac)) {
+ if ($_POST['replacemacpassthru']) {
+ foreach ($config['captiveportal']['passthrumac'] as $idx => $macent) {
+ if ($macent['mac'] == $mac['mac']) {
+ $macrules = "";
+ $ruleno = captiveportal_get_ipfw_passthru_ruleno($mac['mac']);
+ if ($ruleno) {
+ captiveportal_free_ipfw_ruleno($ruleno, true);
+ $macrules .= "delete {$ruleno}\n";
+ ++$ruleno;
+ $macrules .= "delete {$ruleno}\n";
+ }
+ unset($config['captiveportal']['passthrumac'][$idx]);
+ $mac['mac'] = $clientmac;
+ $config['captiveportal']['passthrumac'][] = $mac;
+ $macrules .= captiveportal_passthrumac_configure_entry($mac);
+ file_put_contents("{$g['tmp_path']}/macentry.rules.tmp", $macrules);
+ mwexec("/sbin/ipfw -q {$g['tmp_path']}/macentry.rules.tmp");
+ $writecfg = true;
+ $sessionid = true;
+ break;
+ }
+ }
+ } else {
+ portal_reply_page($redirurl, "error", "Username: {$username} is already authenticated using another MAC address.",
+ $clientmac, $clientip, $username, $password);
+ exit;
+ }
+ }
+ }
+ }
+
+ foreach ($cpdb as $sid => $cpentry) {
+ /* on the same ip */
+ if($cpentry[2] == $clientip) {
+ captiveportal_logportalauth($cpentry[4],$cpentry[3],$cpentry[2],"CONCURRENT LOGIN - REUSING OLD SESSION");
+ $sessionid = $sid;
+ break;
+ }
+ elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpentry[4] == $username)) {
+ // user logged in with an active voucher. Check for how long and calculate
+ // how much time we can give him (voucher credit - used time)
+ $remaining_time = $cpentry[0] + $cpentry[7] - time();
+ if ($remaining_time < 0) // just in case.
+ $remaining_time = 0;
+
+ /* This user was already logged in so we disconnect the old one */
+ captiveportal_disconnect($cpentry,$radiusservers,13);
+ captiveportal_logportalauth($cpentry[4],$cpentry[3],$cpentry[2],"CONCURRENT LOGIN - TERMINATING OLD SESSION");
+ unset($cpdb[$sid]);
+ break;
+ }
+ elseif ((isset($config['captiveportal']['noconcurrentlogins'])) && ($username != 'unauthenticated')) {
+ /* on the same username */
+ if (strcasecmp($cpentry[4], $username) == 0) {
+ /* This user was already logged in so we disconnect the old one */
+ captiveportal_disconnect($cpentry,$radiusservers,13);
+ captiveportal_logportalauth($cpentry[4],$cpentry[3],$cpentry[2],"CONCURRENT LOGIN - TERMINATING OLD SESSION");
+ unset($cpdb[$sid]);
+ break;
+ }
+ }
+ }
+
+ if ($attributes['voucher'] && $remaining_time <= 0)
+ return 0; // voucher already used and no time left
+
+ if (!isset($sessionid)) {
+ /* generate unique session ID */
+ $tod = gettimeofday();
+ $sessionid = substr(md5(mt_rand() . $tod['sec'] . $tod['usec'] . $clientip . $clientmac), 0, 16);
+
+ /* Add rules for traffic shaping
+ * We don't need to add extra rules since traffic will pass due to the following kernel option
+ * net.inet.ip.fw.one_pass: 1
+ */
+ $peruserbw = isset($config['captiveportal']['peruserbw']);
+
+ $bw_up = isset($attributes['bw_up']) ? trim($attributes['bw_up']) : $config['captiveportal']['bwdefaultup'];
+ $bw_down = isset($attributes['bw_down']) ? trim($attributes['bw_down']) : $config['captiveportal']['bwdefaultdn'];
+
+ if ($passthrumac) {
+ $mac = array();
+ $mac['mac'] = $clientmac;
+ if (isset($config['captiveportal']['passthrumacaddusername']))
+ $mac['username'] = $username;
+ $mac['descr'] = "Auto added pass-through MAC for user {$username}";
+ if (!empty($bw_up))
+ $mac['bw_up'] = $bw_up;
+ if (!empty($bw_down))
+ $mac['bw_down'] = $bw_down;
+ if (!is_array($config['captiveportal']['passthrumac']))
+ $config['captiveportal']['passthrumac'] = array();
+ $config['captiveportal']['passthrumac'][] = $mac;
+ unlock($cpdblck);
+ $macrules = captiveportal_passthrumac_configure_entry($mac);
+ file_put_contents("{$g['tmp_path']}/macentry.rules.tmp", $macrules);
+ mwexec("/sbin/ipfw -q {$g['tmp_path']}/macentry.rules.tmp");
+ $writecfg = true;
+ } else {
+ if ($peruserbw && !empty($bw_up) && is_numeric($bw_up)) {
+ $bw_up_pipeno = $ruleno + 20000;
+ //$bw_up /= 1000; // Scale to Kbit/s
+ mwexec("/sbin/ipfw pipe {$bw_up_pipeno} config bw {$bw_up}Kbit/s queue 100");
+
+ if (!isset($config['captiveportal']['nomacfilter']))
+ mwexec("/sbin/ipfw table 1 add {$clientip} mac {$clientmac} {$bw_up_pipeno}");
+ else
+ mwexec("/sbin/ipfw table 1 add {$clientip} {$bw_up_pipeno}");
+ } else {
+ if (!isset($config['captiveportal']['nomacfilter']))
+ mwexec("/sbin/ipfw table 1 add {$clientip} mac {$clientmac}");
+ else
+ mwexec("/sbin/ipfw table 1 add {$clientip}");
+ }
+ if ($peruserbw && !empty($bw_down) && is_numeric($bw_down)) {
+ $bw_down_pipeno = $ruleno + 20001;
+ //$bw_down /= 1000; // Scale to Kbit/s
+ mwexec("/sbin/ipfw pipe {$bw_down_pipeno} config bw {$bw_down}Kbit/s queue 100");
+
+ if (!isset($config['captiveportal']['nomacfilter']))
+ mwexec("/sbin/ipfw table 2 add {$clientip} mac {$clientmac} {$bw_down_pipeno}");
+ else
+ mwexec("/sbin/ipfw table 2 add {$clientip} {$bw_down_pipeno}");
+ } else {
+ if (!isset($config['captiveportal']['nomacfilter']))
+ mwexec("/sbin/ipfw table 2 add {$clientip} mac {$clientmac}");
+ else
+ mwexec("/sbin/ipfw table 2 add {$clientip}");
+ }
+
+ if ($attributes['voucher'])
+ $attributes['session_timeout'] = $remaining_time;
+
+ /* encode password in Base64 just in case it contains commas */
+ $bpassword = base64_encode($password);
+ $cpdb[] = array(time(), $ruleno, $clientip, $clientmac, $username, $sessionid, $bpassword,
+ $attributes['session_timeout'], $attributes['idle_timeout'], $attributes['session_terminate_time']);
+
+ /* rewrite information to database */
+ captiveportal_write_db($cpdb, true);
+ unlock($cpdblck);
+
+ if (isset($config['captiveportal']['radacct_enable']) && !empty($radiusservers)) {
+ $acct_val = RADIUS_ACCOUNTING_START($ruleno,
+ $username, $sessionid, $radiusservers, $clientip, $clientmac);
+ if ($acct_val == 1)
+ captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED");
+ }
+ }
+ } else
+ unlock($cpdblck);
+
+ if ($writecfg == true)
+ write_config();
+
+ /* redirect user to desired destination */
+ if (!empty($attributes['url_redirection']))
+ $my_redirurl = $attributes['url_redirection'];
+ else if ($config['captiveportal']['redirurl'])
+ $my_redirurl = $config['captiveportal']['redirurl'];
+ else
+ $my_redirurl = $redirurl;
+
+ if(isset($config['captiveportal']['logoutwin_enable']) && !$passthrumac) {
+
+ if (isset($config['captiveportal']['httpslogin']))
+ $logouturl = "https://{$config['captiveportal']['httpsname']}:8001/";
+ else {
+ $ifip = portal_ip_from_client_ip($clientip);
+ if (!$ifip)
+ $ourhostname = $config['system']['hostname'] . ":8000";
+ else
+ $ourhostname = "{$ifip}:8000";
+ $logouturl = "http://{$ourhostname}/";
+ }
+
+ if (isset($attributes['reply_message']))
+ $message = $attributes['reply_message'];
+ else
+ $message = 0;
+
+ include("{$g['varetc_path']}/captiveportal-logout.html");
+
+ } else {
+ header("Location: " . $my_redirurl);
+ }
+
+ return $sessionid;
+}
+
+
+/*
+ * Used for when pass-through credits are enabled.
+ * Returns true when there was at least one free login to deduct for the MAC.
+ * Expired entries are removed as they are seen.
+ * Active entries are updated according to the configuration.
+ */
+function portal_consume_passthrough_credit($clientmac) {
+ global $config;
+
+ if (!empty($config['captiveportal']['freelogins_count']) && is_numeric($config['captiveportal']['freelogins_count']))
+ $freeloginscount = $config['captiveportal']['freelogins_count'];
+ else
+ return false;
+
+ if (!empty($config['captiveportal']['freelogins_resettimeout']) && is_numeric($config['captiveportal']['freelogins_resettimeout']))
+ $resettimeout = $config['captiveportal']['freelogins_resettimeout'];
+ else
+ return false;
+
+ if ($freeloginscount < 1 || $resettimeout <= 0 || !$clientmac)
+ return false;
+
+ $updatetimeouts = isset($config['captiveportal']['freelogins_updatetimeouts']);
+
+ /*
+ * Read database of used MACs. Lines are a comma-separated list
+ * of the time, MAC, then the count of pass-through credits remaining.
+ */
+ $usedmacs = captiveportal_read_usedmacs_db();
+
+ $currenttime = time();
+ $found = false;
+ foreach ($usedmacs as $key => $usedmac) {
+ $usedmac = explode(",", $usedmac);
+
+ if ($usedmac[1] == $clientmac) {
+ if ($usedmac[0] + ($resettimeout * 3600) > $currenttime) {
+ if ($usedmac[2] < 1) {
+ if ($updatetimeouts) {
+ $usedmac[0] = $currenttime;
+ unset($usedmacs[$key]);
+ $usedmacs[] = implode(",", $usedmac);
+ captiveportal_write_usedmacs_db($usedmacs);
+ }
+
+ return false;
+ } else {
+ $usedmac[2] -= 1;
+ $usedmacs[$key] = implode(",", $usedmac);
+ }
+
+ $found = true;
+ } else
+ unset($usedmacs[$key]);
+
+ break;
+ } else if ($usedmac[0] + ($resettimeout * 3600) <= $currenttime)
+ unset($usedmacs[$key]);
+ }
+
+ if (!$found) {
+ $usedmac = array($currenttime, $clientmac, $freeloginscount - 1);
+ $usedmacs[] = implode(",", $usedmac);
+ }
+
+ captiveportal_write_usedmacs_db($usedmacs);
+ return true;
+}
+
+function captiveportal_read_usedmacs_db() {
+ global $g;
+
+ $cpumaclck = lock('captiveusedmacs');
+ if (file_exists("{$g['vardb_path']}/captiveportal_usedmacs.db")) {
+ $usedmacs = file("{$g['vardb_path']}/captiveportal_usedmacs.db", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if (!$usedmacs)
+ $usedmacs = array();
+ } else
+ $usedmacs = array();
+
+ unlock($cpumaclck);
+ return $usedmacs;
+}
+
+function captiveportal_write_usedmacs_db($usedmacs) {
+ global $g;
+
+ $cpumaclck = lock('captiveusedmacs', LOCK_EX);
+ @file_put_contents("{$g['vardb_path']}/captiveportal_usedmacs.db", implode("\n", $usedmacs));
+ unlock($cpumaclck);
+}
+
?>
OpenPOWER on IntegriCloud