diff options
author | Erik Fonnesbeck <efonnes@gmail.com> | 2010-09-24 22:17:39 -0600 |
---|---|---|
committer | Erik Fonnesbeck <efonnes@gmail.com> | 2010-09-24 23:09:48 -0600 |
commit | 03552507b71a1865e006b5f924dc80a0d7052b32 (patch) | |
tree | 61c5bc785f0fc4186c8341dd62b56bf62352d313 | |
parent | a36e98ff1d422985817e93332e14aecaca95a19f (diff) | |
download | pfsense-03552507b71a1865e006b5f924dc80a0d7052b32.zip pfsense-03552507b71a1865e006b5f924dc80a0d7052b32.tar.gz |
Add an option for allowing clients to pass through the captive portal a limited number of times before requiring login.
-rwxr-xr-x | usr/local/captiveportal/index.php | 94 | ||||
-rwxr-xr-x | usr/local/www/services_captiveportal.php | 36 |
2 files changed, 129 insertions, 1 deletions
diff --git a/usr/local/captiveportal/index.php b/usr/local/captiveportal/index.php index c7a3ebe..6428a91 100755 --- a/usr/local/captiveportal/index.php +++ b/usr/local/captiveportal/index.php @@ -188,7 +188,7 @@ exit; captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"FAILURE"); portal_reply_page($redirurl, "error", $errormsg); } -} else if ($_POST['accept'] && $clientip) { +} else if ( ($_POST['accept'] && $clientip) || portal_consume_free_login($clientmac) ) { captiveportal_logportalauth("unauthenticated",$clientmac,$clientip,"ACCEPT"); portal_allow($clientip, $clientmac, "unauthenticated"); } else { @@ -525,4 +525,96 @@ function disconnect_client($sessionid, $logoutReason = "LOGOUT", $term_cause = 1 unlock($cplock); } +/* + * Used when a limited number of free logins are allowed. + * 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_free_login($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']); + + $cplock = lock('captiveportal'); + + /* + * Read database of used MACs. Lines are a comma-separated list + * of the time, MAC, then the count of free logins 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); + } + + unlock($cplock); + 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); + unlock($cplock); + return true; +} + +function captiveportal_read_usedmacs_db() { + global $g; + + 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(); + + return $usedmacs; +} + +function captiveportal_write_usedmacs_db($usedmacs) { + global $g; + + file_put_contents("{$g['vardb_path']}/captiveportal_usedmacs.db", implode("\n", $usedmacs)); +} + ?> diff --git a/usr/local/www/services_captiveportal.php b/usr/local/www/services_captiveportal.php index 590b186..6c13c87 100755 --- a/usr/local/www/services_captiveportal.php +++ b/usr/local/www/services_captiveportal.php @@ -71,6 +71,9 @@ $pconfig['maxproc'] = $config['captiveportal']['maxproc']; $pconfig['maxprocperip'] = $config['captiveportal']['maxprocperip']; $pconfig['timeout'] = $config['captiveportal']['timeout']; $pconfig['idletimeout'] = $config['captiveportal']['idletimeout']; +$pconfig['freelogins_count'] = $config['captiveportal']['freelogins_count']; +$pconfig['freelogins_resettimeout'] = $config['captiveportal']['freelogins_resettimeout']; +$pconfig['freelogins_updatetimeouts'] = $config['captiveportal']['freelogins_updatetimeouts']; $pconfig['enable'] = isset($config['captiveportal']['enable']); $pconfig['auth_method'] = $config['captiveportal']['auth_method']; $pconfig['radacct_enable'] = isset($config['captiveportal']['radacct_enable']); @@ -146,6 +149,12 @@ if ($_POST) { if ($_POST['idletimeout'] && (!is_numeric($_POST['idletimeout']) || ($_POST['idletimeout'] < 1))) { $input_errors[] = gettext("The idle timeout must be at least 1 minute."); } + if ($_POST['freelogins_count'] && (!is_numeric($_POST['freelogins_count']))) { + $input_errors[] = gettext("The free pass-throughs count must be a number or left blank."); + } + if ($_POST['freelogins_resettimeout'] && (!is_numeric($_POST['freelogins_resettimeout']) || ($_POST['freelogins_resettimeout'] <= 0))) { + $input_errors[] = gettext("The waiting period until free pass-throughs restored cannot be 0 hours."); + } if (($_POST['radiusip'] && !is_ipaddr($_POST['radiusip']))) { $input_errors[] = sprintf(gettext("A valid IP address must be specified. [%s]"), $_POST['radiusip']); } @@ -176,6 +185,9 @@ if ($_POST) { $config['captiveportal']['maxprocperip'] = $_POST['maxprocperip'] ? $_POST['maxprocperip'] : false; $config['captiveportal']['timeout'] = $_POST['timeout']; $config['captiveportal']['idletimeout'] = $_POST['idletimeout']; + $config['captiveportal']['freelogins_count'] = $_POST['freelogins_count']; + $config['captiveportal']['freelogins_resettimeout'] = $_POST['freelogins_resettimeout']; + $config['captiveportal']['freelogins_updatetimeouts'] = $_POST['freelogins_updatetimeouts'] ? true : false; $config['captiveportal']['enable'] = $_POST['enable'] ? true : false; $config['captiveportal']['auth_method'] = $_POST['auth_method']; $config['captiveportal']['radacct_enable'] = $_POST['radacct_enable'] ? true : false; @@ -242,6 +254,9 @@ function enable_change(enable_change) { //document.iform.maxproc.disabled = endis; document.iform.maxprocperip.disabled = endis; document.iform.idletimeout.disabled = endis; + document.iform.freelogins_count.disabled = endis; + document.iform.freelogins_resettimeout.disabled = endis; + document.iform.freelogins_updatetimeouts.disabled = endis; document.iform.timeout.disabled = endis; document.iform.redirurl.disabled = endis; document.iform.radiusip.disabled = radius_endis; @@ -351,6 +366,27 @@ value="<?=htmlspecialchars($pconfig['maxprocperip']);?>"> <?=gettext("per client <?=gettext("Clients will be disconnected after this amount of time, regardless of activity. They may log in again immediately, though. Leave this field blank for no hard timeout (not recommended unless an idle timeout is set)."); ?></td> </tr> <tr> + <td width="22%" valign="top" class="vncell"><?=gettext("Free pass-throughs allowed per MAC address"); ?></td> + <td width="78%" class="vtable"> + <input name="freelogins_count" type="text" class="formfld unknown" id="freelogins_count" size="6" value="<?=htmlspecialchars($pconfig['freelogins_count']);?>"> + <?=gettext("per client MAC address (0 or blank = none)"); ?><br> + <?=gettext("This setting allows passing through the captive portal without authentication a limited number of times per MAC address. Once used up, the client can only log in with valid credentials until the waiting period specified below has expired. Recommended to set a hard timeout and/or idle timeout when using this for it to be effective."); ?></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?=gettext("Waiting period until free pass-throughs restored"); ?></td> + <td width="78%" class="vtable"> + <input name="freelogins_resettimeout" type="text" class="formfld unknown" id="freelogins_resettimeout" size="6" value="<?=htmlspecialchars($pconfig['freelogins_resettimeout']);?>"> + <?=gettext("hours"); ?><br> + <?=gettext("Clients will have their available free pass-throughs restored to the original count after this waiting period since using up their first pass-through. This must be greater than zero if free pass-throughs are enabled."); ?></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?=gettext("Reset free pass-throughs waiting period on attempted access"); ?></td> + <td width="78%" class="vtable"> + <input name="freelogins_updatetimeouts" type="checkbox" class="formfld" id="freelogins_updatetimeouts" value="yes" <?php if($pconfig['freelogins_updatetimeouts']) echo "checked"; ?>> + <strong><?=gettext("Enable waiting period reset on attempted access"); ?></strong><br> + <?=gettext("If enabled, the waiting period is reset to the original duration if access is attempted when all free pass-throughs have already been exhausted."); ?></td> + </tr> + <tr> <td width="22%" valign="top" class="vncell"><?=gettext("Logout popup window"); ?></td> <td width="78%" class="vtable"> <input name="logoutwin_enable" type="checkbox" class="formfld" id="logoutwin_enable" value="yes" <?php if($pconfig['logoutwin_enable']) echo "checked"; ?>> |