$cp) { if ($cpkey != $cpzone || empty($cpzone)) { if (in_array($cpbrif, explode(",", $cp['interface']))) { $input_errors[] = sprintf(gettext("The captive portal cannot be used on interface %s since it is used already on %s instance."), $cpbrif, $cp['zone']); } } } } } if ($_POST['httpslogin_enable']) { if (!$_POST['certref']) { $input_errors[] = gettext("Certificate must be specified for HTTPS login."); } if (!$_POST['httpsname'] || !is_domain($_POST['httpsname'])) { $input_errors[] = gettext("The HTTPS server name must be specified for HTTPS login."); } } } if ($_POST['timeout']) { if (!is_numeric($_POST['timeout']) || ($_POST['timeout'] < 1)) { $input_errors[] = gettext("The timeout must be at least 1 minute."); } else if (isset($config['dhcpd']) && is_array($config['dhcpd'])) { foreach ($config['dhcpd'] as $dhcpd_if => $dhcpd_data) { if (!isset($dhcpd_data['enable'])) { continue; } if (!is_array($_POST['cinterface']) || !in_array($dhcpd_if, $_POST['cinterface'])) { continue; } $deftime = 7200; // Default lease time if (isset($dhcpd_data['defaultleasetime']) && is_numeric($dhcpd_data['defaultleasetime'])) { $deftime = $dhcpd_data['defaultleasetime']; } if ($_POST['timeout'] > $deftime) { $input_errors[] = gettext("Hard timeout must be less than or equal to the Default lease time set on DHCP Server"); } } } } 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 pass-through credit count must be a number or left blank."); } else if ($_POST['freelogins_count'] && is_numeric($_POST['freelogins_count']) && ($_POST['freelogins_count'] >= 1)) { if (empty($_POST['freelogins_resettimeout']) || !is_numeric($_POST['freelogins_resettimeout']) || ($_POST['freelogins_resettimeout'] <= 0)) { $input_errors[] = gettext("The waiting period to restore pass-through credits must be above 0 hours."); } } if (($_POST['radiusip'] && !is_ipaddr($_POST['radiusip']))) { $input_errors[] = sprintf(gettext("A valid IP address must be specified. [%s]"), $_POST['radiusip']); } if (($_POST['radiusip2'] && !is_ipaddr($_POST['radiusip2']))) { $input_errors[] = sprintf(gettext("A valid IP address must be specified. [%s]"), $_POST['radiusip2']); } if (($_POST['radiusip3'] && !is_ipaddr($_POST['radiusip3']))) { $input_errors[] = sprintf(gettext("A valid IP address must be specified. [%s]"), $_POST['radiusip3']); } if (($_POST['radiusip4'] && !is_ipaddr($_POST['radiusip4']))) { $input_errors[] = sprintf(gettext("A valid IP address must be specified. [%s]"), $_POST['radiusip4']); } if (($_POST['radiusport'] && !is_port($_POST['radiusport']))) { $input_errors[] = sprintf(gettext("A valid port number must be specified. [%s]"), $_POST['radiusport']); } if (($_POST['radiusport2'] && !is_port($_POST['radiusport2']))) { $input_errors[] = sprintf(gettext("A valid port number must be specified. [%s]"), $_POST['radiusport2']); } if (($_POST['radiusport3'] && !is_port($_POST['radiusport3']))) { $input_errors[] = sprintf(gettext("A valid port number must be specified. [%s]"), $_POST['radiusport3']); } if (($_POST['radiusport4'] && !is_port($_POST['radiusport4']))) { $input_errors[] = sprintf(gettext("A valid port number must be specified. [%s]"), $_POST['radiusport4']); } if (($_POST['radiusacctport'] && !is_port($_POST['radiusacctport']))) { $input_errors[] = sprintf(gettext("A valid port number must be specified. [%s]"), $_POST['radiusacctport']); } if ($_POST['maxproc'] && (!is_numeric($_POST['maxproc']) || ($_POST['maxproc'] < 4) || ($_POST['maxproc'] > 100))) { $input_errors[] = gettext("The maximum number of concurrent connections per client IP address may not be larger than the global maximum."); } if (trim($_POST['radiusnasid']) !== "" && !preg_match("/^[\x21-\x7e]{3,253}$/i", trim($_POST['radiusnasid']))) { $input_errors[] = gettext("The NAS-Identifier must be 3-253 characters long and should only contain ASCII characters."); } if (!$input_errors) { $newcp =& $a_cp[$cpzone]; //$newcp['zoneid'] = $a_cp[$cpzone]['zoneid']; if (empty($newcp['zoneid'])) { $newcp['zoneid'] = 2; foreach ($a_cp as $keycpzone => $cp) { if ($cp['zoneid'] == $newcp['zoneid'] && $keycpzone != $cpzone) { $newcp['zoneid'] += 2; /* Reserve space for SSL config if needed */ } } $cpzoneid = $newcp['zoneid']; } $oldifaces = explode(",", $newcp['interface']); if (is_array($_POST['cinterface'])) { $newcp['interface'] = implode(",", $_POST['cinterface']); } $newcp['maxproc'] = $_POST['maxproc']; $newcp['maxprocperip'] = $_POST['maxprocperip'] ? $_POST['maxprocperip'] : false; $newcp['timeout'] = $_POST['timeout']; $newcp['idletimeout'] = $_POST['idletimeout']; $newcp['freelogins_count'] = $_POST['freelogins_count']; $newcp['freelogins_resettimeout'] = $_POST['freelogins_resettimeout']; $newcp['freelogins_updatetimeouts'] = $_POST['freelogins_updatetimeouts'] ? true : false; if ($_POST['enable']) { $newcp['enable'] = true; } else { unset($newcp['enable']); } $newcp['auth_method'] = $_POST['auth_method']; $newcp['localauth_priv'] = isset($_POST['localauth_priv']); $newcp['radacct_enable'] = $_POST['radacct_enable'] ? true : false; $newcp['reauthenticate'] = $_POST['reauthenticate'] ? true : false; $newcp['radmac_enable'] = $_POST['radmac_enable'] ? true : false; $newcp['radmac_secret'] = $_POST['radmac_secret'] ? $_POST['radmac_secret'] : false; $newcp['reauthenticateacct'] = $_POST['reauthenticateacct']; if ($_POST['httpslogin_enable']) { $newcp['httpslogin'] = true; } else { unset($newcp['httpslogin']); } $newcp['httpsname'] = $_POST['httpsname']; $newcp['preauthurl'] = $_POST['preauthurl']; $newcp['blockedmacsurl'] = $_POST['blockedmacsurl']; $newcp['peruserbw'] = $_POST['peruserbw'] ? true : false; if (isset($_POST['bwdefaultdn'])) { $newcp['bwdefaultdn'] = $_POST['bwdefaultdn']; } else { unset($newcp['bwdefaultdn']); } if (isset($_POST['bwdefaultup'])) { $newcp['bwdefaultup'] = $_POST['bwdefaultup']; } else { unset($newcp['bwdefaultup']); } $newcp['certref'] = $_POST['certref']; $newcp['nohttpsforwards'] = $_POST['nohttpsforwards'] ? true : false; $newcp['logoutwin_enable'] = $_POST['logoutwin_enable'] ? true : false; $newcp['nomacfilter'] = $_POST['nomacfilter'] ? true : false; $newcp['noconcurrentlogins'] = $_POST['noconcurrentlogins'] ? true : false; $newcp['radius_protocol'] = $_POST['radius_protocol']; $newcp['redirurl'] = $_POST['redirurl']; if (isset($_POST['radiusip'])) { $newcp['radiusip'] = $_POST['radiusip']; } else { unset($newcp['radiusip']); } if (isset($_POST['radiusip2'])) { $newcp['radiusip2'] = $_POST['radiusip2']; } else { unset($newcp['radiusip2']); } if (isset($_POST['radiusip3'])) { $newcp['radiusip3'] = $_POST['radiusip3']; } else { unset($newcp['radiusip3']); } if (isset($_POST['radiusip4'])) { $newcp['radiusip4'] = $_POST['radiusip4']; } else { unset($newcp['radiusip4']); } $newcp['radiusport'] = $_POST['radiusport']; $newcp['radiusport2'] = $_POST['radiusport2']; if (isset($_POST['radiusport3'])) { $newcp['radiusport3'] = $_POST['radiusport3']; } if (isset($_POST['radiusport4'])) { $newcp['radiusport4'] = $_POST['radiusport4']; } $newcp['radiusacctport'] = $_POST['radiusacctport']; $newcp['radiuskey'] = $_POST['radiuskey']; $newcp['radiuskey2'] = $_POST['radiuskey2']; $newcp['radiuskey3'] = $_POST['radiuskey3']; $newcp['radiuskey4'] = $_POST['radiuskey4']; $newcp['radiusvendor'] = $_POST['radiusvendor'] ? $_POST['radiusvendor'] : false; $newcp['radiussession_timeout'] = $_POST['radiussession_timeout'] ? true : false; $newcp['radiussrcip_attribute'] = $_POST['radiussrcip_attribute']; $newcp['passthrumacadd'] = $_POST['passthrumacadd'] ? true : false; $newcp['passthrumacaddusername'] = $_POST['passthrumacaddusername'] ? true : false; $newcp['radmac_format'] = $_POST['radmac_format'] ? $_POST['radmac_format'] : false; $newcp['reverseacct'] = $_POST['reverseacct'] ? true : false; $newcp['radiusnasid'] = trim($_POST['radiusnasid']); if (!is_array($newcp['page'])) { $newcp['page'] = array(); } /* file upload? */ if (is_uploaded_file($_FILES['htmlfile']['tmp_name'])) { $newcp['page']['htmltext'] = base64_encode(file_get_contents($_FILES['htmlfile']['tmp_name'])); } if (is_uploaded_file($_FILES['errfile']['tmp_name'])) { $newcp['page']['errtext'] = base64_encode(file_get_contents($_FILES['errfile']['tmp_name'])); } if (is_uploaded_file($_FILES['logoutfile']['tmp_name'])) { $newcp['page']['logouttext'] = base64_encode(file_get_contents($_FILES['logoutfile']['tmp_name'])); } write_config(); /* Clear up unselected interfaces */ $newifaces = explode(",", $newcp['interface']); $toremove = array_diff($oldifaces, $newifaces); if (!empty($toremove)) { foreach ($toremove as $removeif) { $removeif = get_real_interface($removeif); mwexec("/sbin/ipfw zone {$cpzoneid} mdel {$removeif}"); } } captiveportal_configure_zone($newcp); unset($newcp, $newifaces, $toremove); filter_configure(); header("Location: services_captiveportal_zones.php"); exit; } else { if (is_array($_POST['cinterface'])) { $pconfig['cinterface'] = implode(",", $_POST['cinterface']); } } } function build_radiusnas_list() { global $config; $list = array(); $iflist = get_configured_interface_with_descr(); foreach ($iflist as $ifdesc => $ifdescr) { $ipaddr = get_interface_ip($ifdesc); if (is_ipaddr($ipaddr)) { $list[$ifdescr] = $ifdescr . ' - ' . $ipaddr; } } if (is_array($config['virtualip']['vip'])) { foreach ($config['virtualip']['vip'] as $sn) { if ($sn['mode'] == "proxyarp" && $sn['type'] == "network") { $start = ip2long32(gen_subnet($sn['subnet'], $sn['subnet_bits'])); $end = ip2long32(gen_subnet_max($sn['subnet'], $sn['subnet_bits'])); $len = $end - $start; for ($i = 0; $i <= $len; $i++) { $snip = long2ip32($start+$i); $list[$snip] = $sn['descr'] . ' - ' . $snip; } } else { $list[$sn['subnet']] = $sn['descr'] . ' - ' . $sn['subnet']; } } } return($list); } function build_cert_list() { global $a_cert; $list = array(); foreach ($a_cert as $cert) { $list[$cert['refid']] = $cert['descr']; } return($list); } include("head.inc"); if ($input_errors) { print_input_errors($input_errors); } if ($savemsg) { print_info_box($savemsg, 'success'); } $tab_array = array(); $tab_array[] = array(gettext("Configuration"), true, "services_captiveportal.php?zone={$cpzone}"); $tab_array[] = array(gettext("MAC"), false, "services_captiveportal_mac.php?zone={$cpzone}"); $tab_array[] = array(gettext("Allowed IP Addresses"), false, "services_captiveportal_ip.php?zone={$cpzone}"); $tab_array[] = array(gettext("Allowed Hostnames"), false, "services_captiveportal_hostname.php?zone={$cpzone}"); $tab_array[] = array(gettext("Vouchers"), false, "services_captiveportal_vouchers.php?zone={$cpzone}"); $tab_array[] = array(gettext("File Manager"), false, "services_captiveportal_filemanager.php?zone={$cpzone}"); display_top_tabs($tab_array, true); $form = new Form(); $form->setMultipartEncoding(); $section = new Form_Section('Captive Portal Configuration'); $section->addInput(new Form_Checkbox( 'enable', 'Enable', 'Enable Captive Portal', $pconfig['enable'] )); $section->addInput(new Form_Select( 'cinterface', 'Interfaces', explode(",", $pconfig['cinterface']), get_configured_interface_with_descr(), true ))->addClass('general')->setHelp('Select the interface(s) to enable for captive portal.'); $section->addInput(new Form_Input( 'maxprocperip', 'Maximum concurrent connections', 'number', $pconfig['maxprocperip'], ['min' => '0', 'max' => '100'] ))->setHelp('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 connections a single IP can establish to the portal web server.'); $section->addInput(new Form_Input( 'idletimeout', 'Idle timeout (Minutes)', 'number', $pconfig['idletimeout'] ))->setHelp('Clients will be disconnected after this amount of inactivity. They may log in again immediately, though. Leave this field blank for no idle timeout.'); $section->addInput(new Form_Input( 'timeout', 'Hard timeout (Minutes)', 'number', $pconfig['timeout'] ))->setHelp('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).'); $section->addInput(new Form_Input( 'freelogins_count', 'Pass-through credits per MAC address.', 'number', $pconfig['freelogins_count'] ))->setHelp('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.'); $section->addInput(new Form_Checkbox( 'freelogins_updatetimeouts', 'Reset waiting period', 'Enable waiting period reset on attempted access', $pconfig['freelogins_updatetimeouts'] ))->setHelp('If enabled, the waiting period is reset to the original duration if access is attempted when all pass-through credits have already been exhausted.'); $section->addInput(new Form_Checkbox( 'logoutwin_enable', 'Logout popup window', 'Enable logout popup window', $pconfig['logoutwin_enable'] ))->setHelp('If enabled, a popup window will appear when clients are allowed through the captive portal. ' . 'This allows clients to explicitly disconnect themselves before the idle or hard timeout occurs.'); $section->addInput(new Form_Input( 'preauthurl', 'Pre-authentication redirect URL', 'text', $pconfig['preauthurl'] ))->setHelp('Use this field to set $PORTAL_REDIRURL$ variable which can be accessed using your custom captive portal index.php page or error pages.'); $section->addInput(new Form_Input( 'redirurl', 'After authentication Redirection URL', 'text', $pconfig['redirurl'] ))->setHelp('Clients will be redirected to this URL instead of the one they initially tried to access after they\'ve authenticated'); $section->addInput(new Form_Input( 'blockedmacsurl', 'Blocked MAC address redirect URL', 'text', $pconfig['blockedmacsurl'] ))->setHelp('Blocked MAC addresses will be redirected to this URL when attempting access.'); $section->addInput(new Form_Checkbox( 'noconcurrentlogins', 'Concurrent user logins', 'Disable Concurrent user logins', $pconfig['noconcurrentlogins'] ))->setHelp('If enabled 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.'); $section->addInput(new Form_Checkbox( 'nomacfilter', 'MAC filtering', 'Disable MAC filtering', $pconfig['nomacfilter'] ))->setHelp('If enabled no attempts will be made to ensure that the MAC address of clients stays the same while they are logged in. ' . 'This is required when the MAC address of the client cannot be determined (usually because there are routers between pfSense and the clients). ' . 'If this is enabled, RADIUS MAC authentication cannot be used.'); $section->addInput(new Form_Checkbox( 'passthrumacadd', 'Pass-through MAC Auto Entry', 'Enable Pass-through MAC automatic additions', $pconfig['passthrumacadd'] ))->setHelp(sprintf('When enabled, a MAC passthrough entry is automatically added after the user has successfully authenticated. Users of that MAC address will ' . 'never have to authenticate again. To remove the passthrough MAC entry you either have to log in and remove it manually from the ' . '%s or send a POST from another system.' . 'If this is enabled, RADIUS MAC authentication cannot be used. Also, the logout window will not be shown.', 'MAC tab')); $section->addInput(new Form_Checkbox( 'passthrumacaddusername', null, 'Enable Pass-through MAC automatic addition with username', $pconfig['passthrumacaddusername'] ))->setHelp(sprintf('If enabled with the automatically MAC passthrough entry created, the username used during authentication will be saved. ' . 'To remove the passthrough MAC entry you either have to log in and remove it manually from the %s or send a POST from another system.', 'MAC tab')); $section->addInput(new Form_Checkbox( 'peruserbw', 'Per-user bandwidth restriction', 'Enable per-user bandwidth restriction', $pconfig['peruserbw'] )); $section->addInput(new Form_Input( 'bwdefaultdn', 'Default download (Kbit/s)', 'number', $pconfig['bwdefaultdn'] )); $section->addInput(new Form_Input( 'bwdefaultup', 'Default upload (Kbit/s)', 'number', $pconfig['bwdefaultup'] ))->setHelp('If this option is set, the captive portal will restrict each user who logs in to the specified default bandwidth. ' . 'RADIUS can override the default settings. Leave empty or set to 0 for no limit.'); $form->add($section); $section = new Form_Section('Authentication'); $section->addClass('Authentication'); $group = new Form_Group('Authentication method'); $group->add(new Form_Checkbox( 'auth_method', null, 'No Authentication', $pconfig['auth_method'] == 'none', 'none' ))->displayasRadio(); $group->add(new Form_Checkbox( 'auth_method', null, 'Local User Manager / Vouchers', $pconfig['auth_method'] == 'local', 'local' ))->displayasRadio(); $group->add(new Form_Checkbox( 'auth_method', null, 'RADIUS Authentication', $pconfig['auth_method'] == 'radius', 'radius' ))->displayasRadio(); $section->add($group); $section->addInput(new Form_Checkbox( 'localauth_priv', null, 'Allow only users/groups with "Captive portal login" privilege set', $pconfig['localauth_priv'] )); $group = new Form_Group('RADIUS protocol'); $group->addClass("radiusproto"); $group->add(new Form_Checkbox( 'radius_protocol', null, 'PAP', $pconfig['radius_protocol'] == 'PAP', 'PAP' ))->displayasRadio(); $group->add(new Form_Checkbox( 'radius_protocol', null, 'CHAP-MD5', $pconfig['radius_protocol'] == 'CHAP_MD5', 'CHAP_MD5' ))->displayasRadio(); $group->add(new Form_Checkbox( 'radius_protocol', null, 'MSCHAPv1', $pconfig['radius_protocol'] == 'MSCHAPv1', 'MSCHAPv1' ))->displayasRadio(); $group->add(new Form_Checkbox( 'radius_protocol', null, 'MSCHAPv2', $pconfig['radius_protocol'] == 'MSCHAPv2', 'MSCHAPv2' ))->displayasRadio(); $section->add($group); $form->add($section); $section = new Form_Section('Primary Authentication Source'); $section->addClass('Primary'); $group = new Form_Group('Primary RADIUS server'); $group->add(new Form_IpAddress( 'radiusip', null, $pconfig['radiusip'] )); $group->add(new Form_Input( 'radiusport', null, 'number', $pconfig['radiusport'] )); $group->add(new Form_Input( 'radiuskey', null, 'text', $pconfig['radiuskey'] )); $section->add($group); $group = new Form_Group('Secondary RADIUS server'); $group->add(new Form_IpAddress( 'radiusip2', null, $pconfig['radiusip2'] ))->setHelp('IP address of the RADIUS server to authenticate against.'); $group->add(new Form_Input( 'radiusport2', null, 'number', $pconfig['radiusport2'] ))->setHelp('RADIUS port. Leave blank for default (1812)'); $group->add(new Form_Input( 'radiuskey2', null, 'text', $pconfig['radiuskey2'] ))->setHelp('RADIUS shared secret. Leave blank to not use a shared secret (not recommended)'); $section->add($group); $form->add($section); $section = new Form_Section('Secondary Authentication Source'); $section->addClass('Secondary'); $group = new Form_Group('Primary RADIUS server'); $group->add(new Form_IpAddress( 'radiusip3', null, $pconfig['radiusip3'] )); $group->add(new Form_Input( 'radiusport3', null, 'number', $pconfig['radiusport3'] )); $group->add(new Form_Input( 'radiuskey3', null, 'text', $pconfig['radiuskey3'] )); $section->add($group); $group = new Form_Group('Secondary RADIUS server'); $group->add(new Form_IpAddress( 'radiusip4', null, $pconfig['radiusip4'] ))->setHelp('IP address of the RADIUS server to authenticate against.'); $group->add(new Form_Input( 'radiusport4', null, 'number', $pconfig['radiusport4'] ))->setHelp('RADIUS port. Leave blank for default (1812)'); $group->add(new Form_Input( 'radiuskey4', null, 'text', $pconfig['radiuskey4'] ))->setHelp('RADIUS shared secret. Leave blank to not use a shared secret (not recommended)'); $section->add($group); $form->add($section); $section = new Form_Section('Accounting'); $section->addClass('Accounting'); $section->addInput(new Form_Checkbox( 'radacct_enable', 'RADIUS', 'Send RADIUS accounting packets to the primary RADIUS server.', $pconfig['radacct_enable'] )); $section->addInput(new Form_Input( 'radiusacctport', 'Accounting Port', 'text', $pconfig['radiusacctport'] ))->setHelp('Leave blank to use the default port (1813).'); $group = new Form_Group('Accounting updates'); $group->add(new Form_Checkbox( 'reauthenticateacct', null, 'No updates', $pconfig['reauthenticateacct'] == "", "" ))->displayasRadio(); $group->add(new Form_Checkbox( 'reauthenticateacct', null, 'Stop/Start', $pconfig['reauthenticateacct'] == 'stopstart', "stopstart" ))->displayasRadio(); $group->add(new Form_Checkbox( 'reauthenticateacct', null, 'Stop/Start (FreeRADIUS)', $pconfig['reauthenticateacct'] == 'stopstartfreeradius', "stopstartfreeradius" ))->displayasRadio(); $group->add(new Form_Checkbox( 'reauthenticateacct', null, 'Interim', $pconfig['reauthenticateacct'] == 'interimupdate', "interimupdate" ))->displayasRadio(); $section->add($group); $form->add($section); $section = new Form_Section('RADIUS options'); $section->addClass('Radius'); $section->addInput(new Form_Checkbox( 'reauthenticate', 'Reathentication', 'Reauthenticate connected users every minute', $pconfig['reauthenticate'] ))->setHelp('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.'); $section->addInput(new Form_Checkbox( 'radmac_enable', 'RADIUS MAC Authentication', 'Enable RADIUS MAC authentication', $pconfig['radmac_enable'] ))->setHelp('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.'); $section->addInput(new Form_Input( 'radmac_secret', 'MAC authentication secret', 'text', $pconfig['radmac_secret'] )); $section->addInput(new Form_Select( 'radiussrcip_attribute', 'RADIUS NAS IP Attribute', $pconfig['radiussrcip_attribute'], build_radiusnas_list() ))->setHelp('Choose the IP to use for calling station attribute.'); $section->addInput(new Form_Checkbox( 'radiussession_timeout', 'Session timeout', 'Use RADIUS Session-Timeout attributes', $pconfig['radiussession_timeout'] ))->setHelp('When enabled, clients will be disconnected after the amount of time retrieved from the RADIUS Session-Timeout attribute.'); $section->addInput(new Form_Select( 'radiusvendor', 'Type', $pconfig['radiusvendor'], ['default' => gettext('default'), 'cisco' => 'cisco'] ))->setHelp('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 behavior is Calling-Station-Id = client\'s MAC address and ' . 'Called-Station-ID = pfSense\'s WAN IP address.'); $section->addInput(new Form_Checkbox( 'reverseacct', 'Accounting style', 'Invert Acct-Input-Octets and Acct-Output-Octets', $pconfig['reverseacct'] ))->setHelp('When enabled, data counts for RADIUS accounting packets will be taken from the client perspective, not the NAS. ' . 'Acct-Input-Octets will represent download, and Acct-Output-Octets will represent upload.'); $section->addInput(new Form_Input( 'radiusnasid', 'NAS Identifier', 'text', $pconfig['radiusnasid'] ))->setHelp('Specify a NAS identifier to override the default value (pfSense.localdomain)'); $section->addInput(new Form_Select( 'radmac_format', 'MAC address format', $pconfig['radmac_format'], ['default' => 'Default', 'singledash' => gettext('Single dash'), 'ietf' => 'IETF', 'cisco' => 'Cisco', 'unformatted' => gettext('Unformatted')] ))->setHelp('This option changes the MAC address format used in the whole RADIUS system. Change this if you also need to change the username format for ' . 'RADIUS MAC authentication.' . '
' . 'Default: 00:11:22:33:44:55' . '
' . 'Single dash: 001122-334455' . '
' . 'IETF: 00-11-22-33-44-55' . '
' . 'Cisco: 0011.2233.4455' . '
' . 'Unformatted: 001122334455'); $form->add($section); $section = new Form_Section('HTTPS options'); $section->addClass('HTTPS'); $section->addInput(new Form_Checkbox( 'httpslogin_enable', 'Login', 'Enable HTTPS login', $pconfig['httpslogin_enable'] ))->setHelp('When enabled, the username and password will be transmitted over an HTTPS connection to protect against eavesdroppers. ' . 'A server name and certificate must also be specified below.'); $section->addInput(new Form_Input( 'httpsname', 'HTTPS server name', 'text', $pconfig['httpsname'] ))->setHelp('This name will be used in the form action for the HTTPS POST and should match the Common Name (CN) in your certificate ' . '(otherwise, the client browser will most likely display a security warning). ' . 'Make sure captive portal clients can resolve this name in DNS and verify on the client that the IP resolves to the correct interface IP on pfSense.'); $section->addInput(new Form_Select( 'certref', 'SSL Certificate', $pconfig['certref'], build_cert_list() ))->setHelp('If no certificates are defined, you may define one here: ' . 'System > Cert Manager'); $section->addInput(new Form_Checkbox( 'nohttpsforwards', 'HTTPS Forwards', 'Disable HTTPS Forwards', $pconfig['nohttpsforwards'] ))->setHelp('If this option is set, attempts to connect to SSL/HTTPS (Port 443) sites will not be forwarded to the captive portal' . 'This prevents certificate errors from being presented to the user even if HTTPS logins are enabled. ' . 'Users must attempt a connecton to an HTTP (Port 80) site to get forwarded to the captive portal. ' . 'If HTTPS logins are enabled, the user will be redirected to the HTTPS login page.'); $form->add($section); $section = new Form_Section('HTML page contents'); $section->addClass('HTML'); $section->addInput(new Form_Input( 'htmlfile', 'Portal page contents', 'file', $pconfig['htmlfile'] ))->setHelp('Upload an HTML/PHP file for the portal page here (leave blank to keep the current one). Make sure to include a form (POST to "$PORTAL_ACTION$") ' . 'with a submit button (name="accept") and a hidden field with name="redirurl" and value="$PORTAL_REDIRURL$". ' . 'Include the "auth_user" and "auth_pass" and/or "auth_voucher" input fields if authentication is enabled, otherwise it will always fail.' . '
' . 'Example code for the form:' . '
' . '<form method="post" action="$PORTAL_ACTION$">
   <input name="auth_user" type="text">
   <input name="auth_pass" type="password">
   <input name="auth_voucher" type="text">
   <input name="redirurl" type="hidden" value="$PORTAL_REDIRURL$">
   <input name="accept" type="submit" value="Continue">
</form>')->addClass('btn btn-info btn-sm'); list($host) = explode(":", $_SERVER['HTTP_HOST']); $zoneid = $pconfig['zoneid'] ? $pconfig['zoneid'] : 8000; if ($pconfig['httpslogin_enable']) { $port = $pconfig['listenporthttps'] ? $pconfig['listenporthttps'] : ($zoneid + 8001); $href = "https://{$host}:{$port}/?zone={$cpzone}"; } else { $port = $pconfig['listenporthttp'] ? $pconfig['listenporthttp'] : ($zoneid + 8000); $href = "http://{$host}:{$port}/?zone={$cpzone}"; } if ($pconfig['page']['htmltext']) { $section->addInput(new Form_Button( 'btnview', 'View current page', $href ))->removeClass('btn-primary')->addClass('btn btn-default btn-xs')->setAttribute("target", "_blank"); $section->addInput(new Form_Button( 'btndownload', 'Download current page', '?zone=' . $cpzone . '&act=gethtmlhtml' ))->removeClass('btn-primary')->addClass('btn btn-info btn-xs')->setAttribute("target", "_blank"); $section->addInput(new Form_Button( 'btndownload', 'Restore default portal page', '?zone=' . $cpzone . '&act=delhtmlhtml' ))->removeClass('btn-primary')->addClass('btn btn-danger btn-xs')->setAttribute("target", "_blank"); } $section->addInput(new Form_Input( 'errfile', 'Auth error page contents', 'file', $pconfig['errfile'] ))->setHelp('The contents of the HTML/PHP file that you upload here are displayed when an authentication error occurs. ' . 'You may include "$PORTAL_MESSAGE$", which will be replaced by the error or reply messages from the RADIUS ' . 'server, if any.')->addClass('btn btn-info btn-sm'); if ($pconfig['page']['errtext']) { $section->addInput(new Form_Button( 'btnview', 'View current page', '?zone=' . $cpzone . '&act=viewerrhtml' ))->removeClass('btn-primary')->addClass('btn btn-default btn-xs'); $section->addInput(new Form_Button( 'btndownload', 'Download current page', '?zone=' . $cpzone . '&act=geterrhtml' ))->removeClass('btn-primary')->addClass('btn btn-info btn-xs')->setAttribute("target", "_blank"); $section->addInput(new Form_Button( 'btndownload', 'Restore default error page', '?zone=' . $cpzone . '&act=delerrhtml' ))->removeClass('btn-primary')->addClass('btn btn-danger btn-xs')->setAttribute("target", "_blank"); } $section->addInput(new Form_Input( 'logoutfile', 'Logout page contents', 'file', $pconfig['logoutfile'] ))->setHelp('The contents of the HTML/PHP file that you upload here are displayed on authentication success when the logout popup is enabled.')->addClass('btn btn-info btn-sm'); if ($pconfig['page']['logouttext']) { $section->addInput(new Form_Button( 'btnview', 'View current page', '?zone=' . $cpzone . '&act=viewlogouthtml' ))->removeClass('btn-primary')->addClass('btn btn-default btn-xs')->setAttribute("target", "_blank"); $section->addInput(new Form_Button( 'btndownload', 'Download current page', '?zone=' . $cpzone . '&act=getlogouthtml' ))->removeClass('btn-primary')->addClass('btn btn-info btn-xs')->setAttribute("target", "_blank"); $section->addInput(new Form_Button( 'btndownload', 'Restore default logout page', '?zone=' . $cpzone . '&act=dellogouthtml' ))->removeClass('btn-primary')->addClass('btn btn-danger btn-xs')->setAttribute("target", "_blank"); } $section->addInput(new Form_Input( 'zone', null, 'hidden', $cpzone )); $form->add($section); print($form); print_info_box(gettext('Warning:' . '
' . 'Don\'t forget to enable the DHCP server on your captive portal interface! ' . 'Make sure that the default/maximum DHCP lease time is higher than the hard timeout entered on this page. ' . 'Also, the DNS Forwarder or Resolver must be enabled for DNS lookups by unauthenticated clients to work.')); ?>