merge Ermal's CP locking changes

This commit is contained in:
Chris Buechler 2009-05-19 20:24:24 -04:00
parent 03ef91efda
commit 8751763c64
4 changed files with 110 additions and 109 deletions

View File

@ -46,6 +46,8 @@ $lockfile = "{$g['varrun_path']}/captiveportal.lock";
function captiveportal_configure() {
global $config, $g;
$captiveportallck = lock('captiveportal');
if (isset($config['captiveportal']['enable']) &&
(($config['captiveportal']['interface'] == "lan") ||
isset($config['interfaces'][$config['captiveportal']['interface']]['enable']))) {
@ -81,7 +83,7 @@ function captiveportal_configure() {
mwexec("kldload dummynet");
/* stop accounting on all clients */
captiveportal_radius_stop_all();
captiveportal_radius_stop_all(true);
/* initialize minicron interval value */
$croninterval = $config['captiveportal']['croninterval'] ? $config['captiveportal']['croninterval'] : 60;
@ -229,9 +231,9 @@ EOD;
"/etc/rc.prunecaptiveportal");
/* generate passthru mac database */
captiveportal_passthrumac_configure();
captiveportal_passthrumac_configure(true);
/* create allowed ip database and insert ipfw rules to make it so */
captiveportal_allowedip_configure();
captiveportal_allowedip_configure(true);
/* generate radius server database */
if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) ||
@ -277,7 +279,7 @@ EOD;
killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
killbypid("{$g['varrun_path']}/minicron.pid");
captiveportal_radius_stop_all();
captiveportal_radius_stop_all(true);
mwexec("/sbin/sysctl net.link.ether.ipfw=0");
@ -298,8 +300,7 @@ EOD;
mwexec("/sbin/ipfw -f delete set 3");
}
}
captiveportal_unlock();
unlock($captiveportallck);
return 0;
}
@ -458,7 +459,7 @@ function captiveportal_prune_old() {
if (!$timeout && !$idletimeout && !isset($config['captiveportal']['reauthenticate']) && !isset($config['captiveportal']['radiussession_timeout']))
return;
captiveportal_lock();
$captiveportallck = lock('captiveportal');
/* read database */
$cpdb = captiveportal_read_db();
@ -585,7 +586,7 @@ function captiveportal_prune_old() {
/* write database */
captiveportal_write_db($cpdb);
captiveportal_unlock();
unlock($captiveportallck);
}
/* remove a single client according to the DB entry */
@ -632,7 +633,7 @@ function captiveportal_disconnect_client($id,$term_cause = 1) {
global $g, $config;
captiveportal_lock();
$captiveportallck = lock('captiveportal');
/* read database */
$cpdb = captiveportal_read_db();
@ -651,17 +652,19 @@ function captiveportal_disconnect_client($id,$term_cause = 1) {
/* write database */
captiveportal_write_db($cpdb);
captiveportal_unlock();
unlock($captiveportallck);
}
/* send RADIUS acct stop for all current clients */
function captiveportal_radius_stop_all() {
function captiveportal_radius_stop_all($lock = false) {
global $g, $config;
if (!isset($config['captiveportal']['radacct_enable']))
return;
captiveportal_lock();
if (!$lock)
$captiveportallck = lock('captiveportal');
$cpdb = captiveportal_read_db();
$radiusservers = captiveportal_get_radius_servers();
@ -680,13 +683,15 @@ function captiveportal_radius_stop_all() {
7); // Admin Reboot
}
}
captiveportal_unlock();
if (!$lock)
unlock($captiveportallck);
}
function captiveportal_passthrumac_configure() {
function captiveportal_passthrumac_configure($lock = false) {
global $config, $g;
captiveportal_lock();
if (!$lock)
$captiveportallck = lock('captiveportal');
/* clear out passthru macs, if necessary */
unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db");
@ -696,7 +701,8 @@ function captiveportal_passthrumac_configure() {
$fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db", "w");
if (!$fd) {
printf("Error: cannot open passthru mac DB file in captiveportal_passthrumac_configure().\n");
captiveportal_unlock();
if (!$lock)
unlock($captiveportallck);
return 1;
}
@ -725,16 +731,17 @@ function captiveportal_passthrumac_configure() {
mwexec("/sbin/ipfw add 50 skipto 29900 ip from any to any MAC any {$ptm['mac']} keep-state");
}
}
captiveportal_unlock();
if (!$lock)
unlock($captiveportallck);
return 0;
}
function captiveportal_allowedip_configure() {
function captiveportal_allowedip_configure($lock = false) {
global $config, $g;
captiveportal_lock();
if (!$lock)
$captiveportallck = lock('captiveportal');
/* clear out existing allowed ips, if necessary */
if (file_exists("{$g['vardb_path']}/captiveportal_ip.db")) {
@ -763,7 +770,8 @@ function captiveportal_allowedip_configure() {
$fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "w");
if (!$fd) {
printf("Error: cannot open allowed ip DB file in captiveportal_allowedip_configure().\n");
captiveportal_unlock();
if (!$lock)
unlock($captiveportallck);
return 1;
}
@ -775,7 +783,8 @@ function captiveportal_allowedip_configure() {
if (is_null($ruleno)) {
printf("Error: system reached maximum login capacity, no free FW rulenos in captiveportal_allowedip_configure().\n");
fclose($fd);
captiveportal_unlock();
if (!$lock)
unlock($captiveportallck);
return 1;
}
@ -796,7 +805,8 @@ function captiveportal_allowedip_configure() {
fclose($fd);
}
captiveportal_unlock();
if (!$lock)
unlock($captiveportallck);
return 0;
}
@ -843,48 +853,6 @@ function captiveportal_get_radius_servers() {
return false;
}
/* lock captive portal information, decide that the lock file is stale after
10 minutes and EXIT the process to not risk dataloss, issue warning in syslog every 1 minutes */
function captiveportal_lock() {
global $lockfile;
$n = 1;
while ($n) {
/* open the lock file in append mode to avoid race condition */
if ($fd = @fopen($lockfile, "x")) {
/* succeeded */
fclose($fd);
if($n > 10) {
captiveportal_syslog("LOCKINFO: Waiting for lock for $n seconds/s!");
}
return;
} else {
/* file locked, wait and try again */
sleep(1);
if(($n % 60) == 0) {
captiveportal_syslog("LOCKWARNING: waiting for lock for " . $n/60 . " minute/s!");
if(($n % 600) == 0) {
captiveportal_syslog("LOCKERROR: waiting for lock for 10 minute/s - EXITING PROCESS!");
die("Can't get a lock");
}
}
}
$n++;
}
/* we never get here */
}
/* unlock captive portal information file */
function captiveportal_unlock() {
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, $message = null) {
@ -912,16 +880,17 @@ function radius($username,$password,$clientip,$clientmac,$type) {
global $g, $config;
/* Start locking from the beginning of an authentication session */
captiveportal_lock();
$captiveportallck = lock('captiveportal');
$ruleno = captiveportal_get_next_ipfw_ruleno();
unlock($captiveportallck);
/* if the pool is empty, return apprioriate message and fail authentication */
if (is_null($ruleno)) {
$auth_list = array();
$auth_list['auth_val'] = 1;
$auth_list['error'] = "System reached maximum login capacity";
captiveportal_unlock();
return $auth_list;
}
@ -934,6 +903,8 @@ function radius($username,$password,$clientip,$clientmac,$type) {
$clientmac,
$ruleno);
$captiveportallck = lock('captiveportal');
if ($auth_list['auth_val'] == 2) {
captiveportal_logportalauth($username,$clientmac,$clientip,$type);
$sessionid = portal_allow($clientip,
@ -943,9 +914,8 @@ function radius($username,$password,$clientip,$clientmac,$type) {
$auth_list,
$ruleno);
}
else {
captiveportal_unlock();
}
unlock($captiveportallck);
return $auth_list;
@ -956,7 +926,7 @@ function captiveportal_read_db() {
global $g;
$cpdb = array();
$cpdb = array();
$fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
if ($fd) {
while (!feof($fd)) {
@ -1134,4 +1104,4 @@ function portal_mac_fixed($clientmac) {
return FALSE ;
}
?>
?>

View File

@ -343,6 +343,44 @@ function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "")
return $iflist;
}
/* lock configuration file */
function lock($lock) {
global $g, $cfglckkeyconsumers;
if (!$lock)
die("WARNING: You must give a name as parameter to lock() function.");
if (!file_exists("{$g['tmp_path']}/{$lock}.lock"))
@touch("{$g['tmp_path']}/{$lock}.lock");
$config_lock_key = ftok("{$g['tmp_path']}/{$lock}.lock", 'a');
$cfglckkey = sem_get($config_lock_key, 1);
$cfglckkeyconsumers++;
if (!sem_acquire($cfglckkey)) {
log_error("WARNING: lock() - Could not acquire {$lock} lock!");
sem_remove($cfglckkey);
return NULL;
} else if ($g['debug'])
log_error("lock() - Got {$file} lock.");
return $cfglckkey;
}
/* unlock configuration file */
function unlock($cfglckkey = 0) {
global $g, $cfglckkeyconsumers;
if (!$cfglckkey)
return;
if (!sem_release($cfglckkey))
log_error("WARNING: unlock() - Could not unlock lock.");
else {
if ($g['debug'])
log_error("Released lock.");
sem_remove($cfglckkey);
}
$cfglckkeyconsumers--;
}
/* wrapper for exec() */
function mwexec($command, $mute = true) {

View File

@ -219,8 +219,10 @@ function portal_allow($clientip,$clientmac,$username,$password = null, $attribut
global $redirurl, $g, $config, $url_redirection, $type;
/* See if a ruleno is passed, if not start locking the sessions because this means there isn't one atm */
$lockedcpnow = false;
if ($ruleno == null) {
captiveportal_lock();
$cplock = lock('captiveportal');
$lockedcpnow = true;
$ruleno = captiveportal_get_next_ipfw_ruleno();
}
@ -228,7 +230,8 @@ function portal_allow($clientip,$clientmac,$username,$password = null, $attribut
if (is_null($ruleno)) {
portal_reply_page($redirurl, "error", "System reached maximum login capacity");
log_error("WARNING! Captive portal has reached maximum login capacity");
captiveportal_unlock();
if ($lockedcpnow == true)
unlock($cplock);
exit;
}
@ -325,6 +328,8 @@ function portal_allow($clientip,$clientmac,$username,$password = null, $attribut
/* rewrite information to database */
captiveportal_write_db($cpdb);
if ($lockedcpnow == true)
unlock($cplock);
/* redirect user to desired destination */
if ($url_redirection)
$my_redirurl = $url_redirection;
@ -373,11 +378,9 @@ document.location.href="{$my_redirurl}";
EOD;
} else {
captiveportal_unlock();
header("Location: " . $my_redirurl);
return $sessionid;
}
captiveportal_unlock();
return $sessionid;
}
@ -390,7 +393,8 @@ function disconnect_client($sessionid, $logoutReason = "LOGOUT", $term_cause = 1
global $g, $config;
captiveportal_lock();
$cplock = lock('captiveportal');
/* read database */
$cpdb = captiveportal_read_db();
@ -409,7 +413,7 @@ function disconnect_client($sessionid, $logoutReason = "LOGOUT", $term_cause = 1
/* write database */
captiveportal_write_db($cpdb);
captiveportal_unlock();
unlock($cplock);
}
?>
?>

View File

@ -57,37 +57,26 @@ function clientcmp($a, $b) {
}
$cpdb = array();
captiveportal_lock();
$fp = @fopen("{$g['vardb_path']}/captiveportal.db","r");
if ($fp) {
while (!feof($fp)) {
$line = trim(fgets($fp));
if ($line) {
$cpent = explode(",", $line);
if ($_GET['showact'])
$cpent[5] = captiveportal_get_last_activity($cpent[1]);
$cpdb[] = $cpent;
}
}
fclose($fp);
if ($_GET['order']) {
if ($_GET['order'] == "ip")
$order = 2;
else if ($_GET['order'] == "mac")
$order = 3;
else if ($_GET['order'] == "user")
$order = 4;
else if ($_GET['order'] == "lastact")
$order = 5;
else
$order = 0;
usort($cpdb, "clientcmp");
}
$cpcontents = file("/var/db/captiveportal.db", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($cpcontents as $cpcontent) {
$cpent = explode(",", $cpcontent);
if ($_GET['showact'])
$cpent[5] = captiveportal_get_last_activity($cpent[1]);
$cpdb[] = $cpent;
}
if ($_GET['order']) {
if ($_GET['order'] == "ip")
$order = 2;
else if ($_GET['order'] == "mac")
$order = 3;
else if ($_GET['order'] == "user")
$order = 4;
else if ($_GET['order'] == "lastact")
$order = 5;
else
$order = 0;
usort($cpdb, "clientcmp");
}
captiveportal_unlock();
?>
<table class="sortable" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>