diff --git a/src/etc/inc/captiveportal.inc b/src/etc/inc/captiveportal.inc index 31b71495b1..449d75cc86 100644 --- a/src/etc/inc/captiveportal.inc +++ b/src/etc/inc/captiveportal.inc @@ -347,15 +347,10 @@ EOD; @unlink("{$g['varetc_path']}/captiveportal-{$cpzone}-error.html"); @unlink("{$g['varetc_path']}/captiveportal-{$cpzone}-logout.html"); - captiveportal_radius_stop_all(); + captiveportal_radius_stop_all(10); // NAS-Request captiveportal_filterdns_configure(); - /* send Accounting-Off to server */ - if (!platform_booting()) { - captiveportal_send_server_accounting(true); - } - /* remove old information */ unlink_if_exists("{$g['vardb_path']}/captiveportal{$cpzone}.db"); unlink_if_exists("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db"); @@ -1086,10 +1081,24 @@ function captiveportal_disconnect_client($sessionid, $term_cause = 1, $logoutRea function captiveportal_disconnect_all($term_cause = 6, $logoutReason = "DISCONNECT") { global $g, $config, $cpzone, $cpzoneid; + /* check if we're pruning old entries and eventually wait */ + $rcprunelock = try_lock("rcprunecaptiveportal{$cpzone}", 60); + + /* if we still don't have the lock, unlock forcefully and take it */ + if (!$rcprunelock) { + log_error("CP zone ${cpzone}: could not obtain the lock for more than 60 seconds, lock taken forcefully to disconnect all users"); + unlock_force("rcprunecaptiveportal{$cpzone}"); + $rcprunelock = lock("rcprunecaptiveportal{$cpzone}", LOCK_EX); + } + $radiussrvs = captiveportal_get_radius_servers(); $cpdb = captiveportal_read_db(); - $unsetindexes = array(); + /* remove immediately the active users from the database to avoid races */ + $unsetindexes = array_column($cpdb,5); + if (!empty($unsetindexes)) { + captiveportal_remove_entries($unsetindexes); + } foreach ($cpdb as $cpentry) { if (empty($cpentry[11])) { @@ -1099,42 +1108,44 @@ function captiveportal_disconnect_all($term_cause = 6, $logoutReason = "DISCONNE captiveportal_disconnect($cpentry, $radiusservers, $term_cause); captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], $logoutReason); - $unsetindexes[] = $cpentry[5]; } unset($cpdb); - if (!empty($unsetindexes)) { - captiveportal_remove_entries($unsetindexes); - } + unlock($rcprunelock); } /* send RADIUS acct stop for all current clients */ -function captiveportal_radius_stop_all() { - global $config, $cpzone; +function captiveportal_radius_stop_all($term_cause = 6, $logoutReason = "DISCONNECT") { + global $g, $config, $cpzone, $cpzoneid; - if (!isset($config['captiveportal'][$cpzone]['radacct_enable'])) { - return; + $cpdb = captiveportal_read_db(); + + $radacct = isset($config['captiveportal'][$cpzone]['radacct_enable']) ? true : false; + if ($radacct) { + $radiusservers = captiveportal_get_radius_servers(); } - $radiusservers = captiveportal_get_radius_servers(); - if (!empty($radiusservers)) { - $cpdb = captiveportal_read_db(); - foreach ($cpdb as $cpentry) { - if (empty($cpentry[11])) { - $cpentry[11] = 'first'; - } - if (!empty($radiusservers[$cpentry[11]])) { - RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno - $cpentry[4], // username - $cpentry[5], // sessionid - $cpentry[0], // start time - $radiusservers[$cpentry[11]], - $cpentry[2], // clientip - $cpentry[3], // clientmac - 7); // Admin Reboot + foreach ($cpdb as $cpentry) { + if ($radacct) { + if (!empty($radiusservers)) { + if (empty($cpentry[11])) { + $cpentry[11] = 'first'; + } + if (!empty($radiusservers[$cpentry[11]])) { + RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno + $cpentry[4], // username + $cpentry[5], // sessionid + $cpentry[0], // start time + $radiusservers[$cpentry[11]], + $cpentry[2], // clientip + $cpentry[3], // clientmac + $term_cause); + } } } + captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], $logoutReason); } + unset($cpdb); } function captiveportal_passthrumac_configure_entry($macent, $pipeinrule = false) { diff --git a/src/etc/inc/dyndns.class b/src/etc/inc/dyndns.class index 8f1dcd9ba3..d0d27cf5d8 100644 --- a/src/etc/inc/dyndns.class +++ b/src/etc/inc/dyndns.class @@ -98,7 +98,7 @@ * SelfHost - Last Tested: 26 December 2011 * Amazon Route 53 - Last Tested: 30 August 2016 * DNS-O-Matic - Last Tested: 9 September 2010 - * CloudFlare - Last Tested: 17 July 2016 + * CloudFlare - Last Tested: 05 September 2016 * CloudFlare IPv6 - Last Tested: 17 July 2016 * Eurodns - Last Tested: 27 June 2013 * GratisDNS - Last Tested: 15 August 2012 @@ -139,6 +139,7 @@ var $_FQDN; var $_dnsIP; var $_dnsWildcard; + var $_dnsProxied; var $_dnsMX; var $_dnsBackMX; var $_dnsServer; @@ -170,7 +171,7 @@ * - $For custom requests, $dnsUpdateURL is parsed for '%IP%', which is replaced with the new IP. */ function updatedns ($dnsService = '', $dnsHost = '', $dnsDomain = '', $dnsUser = '', $dnsPass = '', - $dnsWildcard = 'OFF', $dnsMX = '', $dnsIf = '', $dnsBackMX = '', + $dnsWildcard = 'OFF', $dnsProxied = false, $dnsMX = '', $dnsIf = '', $dnsBackMX = '', $dnsServer = '', $dnsPort = '', $dnsUpdateURL = '', $forceUpdate = false, $dnsZoneID ='', $dnsTTL='', $dnsResultMatch = '', $dnsRequestIf = '', $dnsID = '', $dnsVerboseLog = false, $curlIpresolveV4 = false, $curlSslVerifypeer = true) { @@ -247,6 +248,7 @@ $this->_dnsServer = $dnsServer; $this->_dnsPort = $dnsPort; $this->_dnsWildcard = $dnsWildcard; + $this->_dnsProxied = $dnsProxied; $this->_dnsMX = $dnsMX; $this->_dnsZoneID = $dnsZoneID; $this->_dnsTTL = $dnsTTL; @@ -359,8 +361,7 @@ curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); } - if ($this->_dnsService != 'ods' and $this->_dnsService != 'route53 ') { - curl_setopt($ch, CURLOPT_HEADER, 1); + if ($this->_dnsService != 'ods') { curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif); @@ -713,6 +714,7 @@ $hostData = array( "content" => "{$this->_dnsIP}", "type" => "{$recordType}", + "proxied" => $this->_dnsProxied, "name" => "{$this->_dnsHost}" ); $data_json = json_encode($hostData); @@ -774,7 +776,6 @@ $server = 'https://api.dnsimple.com/v1/domains/'; $token = $this->_dnsUser . ':' . $this->_dnsPass; $jsondata = '{"record":{"content":"' . $this->_dnsIP . '","ttl":"' . $this->_dnsTTL . '"}}'; - curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json', 'X-DNSimple-Token: ' . $token)); curl_setopt($ch, CURLOPT_URL, $server . $this->_dnsHost . '/records/' . $this->_dnsZoneID); @@ -821,6 +822,7 @@ break; } if ($this->_dnsService != 'ods') { + curl_setopt($ch, CURLOPT_HEADER, 1); $response = curl_exec($ch); $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $header = substr($response, 0, $header_size); @@ -834,7 +836,7 @@ * Private Function (added 12 July 2005) [beta] * Retrieve Update Status */ - function _checkStatus($ch, $data) { + function _checkStatus($ch, $data, $header) { if ($this->_dnsVerboseLog) { log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkStatus() starting.'), $this->_dnsService, $this->_FQDN)); } diff --git a/src/etc/inc/globals.inc b/src/etc/inc/globals.inc index 1bb734cfca..ed635c3264 100644 --- a/src/etc/inc/globals.inc +++ b/src/etc/inc/globals.inc @@ -71,7 +71,7 @@ $g = array( "disablecrashreporter" => false, "crashreporterurl" => "https://crashreporter.pfsense.org/crash_reporter.php", "debug" => false, - "latest_config" => "16.0", + "latest_config" => "16.1", "minimum_ram_warning" => "101", "minimum_ram_warning_text" => "128 MB", "wan_interface_name" => "wan", diff --git a/src/etc/inc/gwlb.inc b/src/etc/inc/gwlb.inc index b240c1287c..fdb01515fe 100644 --- a/src/etc/inc/gwlb.inc +++ b/src/etc/inc/gwlb.inc @@ -466,6 +466,8 @@ function return_gateways_status($byname = false) { $status[$target]['loss'] = ""; $status[$target]['status'] = "none"; } + + $status[$target]['monitor_disable'] = true; } return($status); } diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc index c1fe817223..ef9af77c22 100644 --- a/src/etc/inc/interfaces.inc +++ b/src/etc/inc/interfaces.inc @@ -3868,6 +3868,13 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) { $wanif = get_real_interface($interface, "inet6"); $dhcp6cconf = ""; + if (!empty($config['system']['global-v6duid'])) { + // Write the DUID file + if(!write_dhcp6_duid($config['system']['global-v6duid'])) { + log_error(gettext("Failed to write user DUID file!")); + } + } + if ($wancfg['adv_dhcp6_config_file_override']) { // DHCP6 Config File Override $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); diff --git a/src/etc/inc/ipsec.inc b/src/etc/inc/ipsec.inc index c16e8547f4..5b4cbcc927 100644 --- a/src/etc/inc/ipsec.inc +++ b/src/etc/inc/ipsec.inc @@ -819,4 +819,21 @@ function ipsec_new_reqid() { return $keyid; } +function ipsec_get_loglevels() { + global $config, $ipsec_log_cats; + $def_loglevel = '1'; + + $levels = array(); + + foreach (array_keys($ipsec_log_cats) as $cat) { + if (isset($config['ipsec']['logging'][$cat])) { + $levels[$cat] = $config['ipsec']['logging'][$cat]; + } elseif (in_array($cat, array('ike', 'chd', 'cfg'))) { + $levels[$cat] = "2"; + } else { + $levels[$cat] = $def_loglevel; + } + } + return $levels; +} ?> diff --git a/src/etc/inc/openvpn.inc b/src/etc/inc/openvpn.inc index 727a4af791..abef6a859c 100644 --- a/src/etc/inc/openvpn.inc +++ b/src/etc/inc/openvpn.inc @@ -43,7 +43,10 @@ $openvpn_prots = array( ); global $openvpn_dev_mode; -$openvpn_dev_mode = array("tun", "tap"); +$openvpn_dev_mode = array( + "tun" => "tun - Layer 3 Tunnel Mode", + "tap" => "tap - Layer 2 Tap Mode" +); global $openvpn_verbosity_level; $openvpn_verbosity_level = array( @@ -119,11 +122,16 @@ $openvpn_client_modes = array( global $openvpn_compression_modes; $openvpn_compression_modes = array( - '' => gettext("No Preference"), - 'noadapt' => gettext("No Preference and Adaptive Compression Disabled"), - 'no' => gettext("Disabled - No Compression"), - 'adaptive' => gettext("Enabled with Adaptive Compression"), - 'yes' => gettext("Enabled without Adaptive Compression")); + '' => gettext("Omit Preference (Use OpenVPN Default)"), + 'lz4' => gettext("LZ4 Compression [compress lz4]"), + 'lz4-v2' => gettext("LZ4 Comression v2 [compress lz4-v2]"), + 'lzo' => gettext("LZO Compression [compress lzo, equivalent to comp-lzo yes for compatibility]"), + 'stub' => gettext("Enable Compression (stub) [compress]"), + 'noadapt' => gettext("Omit Preference, + Disable Adaptive LZO Compression [Legacy style, comp-noadapt]"), + 'adaptive' => gettext("Adaptive LZO Compression [Legacy style, comp-lzo adaptive]"), + 'yes' => gettext("LZO Compression [Legacy style, comp-lzo yes]"), + 'no' => gettext("No LZO Compression [Legacy style, comp-lzo no]"), +); global $openvpn_topologies; $openvpn_topologies = array( @@ -132,6 +140,12 @@ $openvpn_topologies = array( // 'p2p => gettext("Peer to Peer -- One IP address per client peer-to-peer style. Does not work on Windows.") ); +global $openvpn_tls_modes; +$openvpn_tls_modes = array( + 'auth' => gettext("TLS Authentication"), + 'crypt' => gettext("TLS Encryption and Authentication") +); + function openvpn_build_mode_list() { global $openvpn_server_modes; @@ -335,37 +349,38 @@ function openvpn_vpnid_next() { function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) { global $config; + $ovpn_settings = array(); if (is_array($config['openvpn']['openvpn-server'])) { - foreach ($config['openvpn']['openvpn-server'] as & $settings) { - if (isset($settings['disable'])) { - continue; - } - - if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) { - continue; - } - - if ($port == $settings['local_port'] && $prot == $settings['protocol'] && - ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) { - return $settings['vpnid']; - } - } + $ovpn_settings = $config['openvpn']['openvpn-server']; + } + if (is_array($config['openvpn']['openvpn-client'])) { + $ovpn_settings = array_merge($ovpn_settings, + $config['openvpn']['openvpn-client']); } - if (is_array($config['openvpn']['openvpn-client'])) { - foreach ($config['openvpn']['openvpn-client'] as & $settings) { - if (isset($settings['disable'])) { - continue; - } + foreach ($ovpn_settings as $settings) { + if (isset($settings['disable'])) { + continue; + } - if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) { - continue; - } + if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) { + continue; + } - if ($port == $settings['local_port'] && $prot == $settings['protocol'] && - ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) { - return $settings['vpnid']; - } + /* (TCP|UDP)(4|6) does not conflict unless interface is any */ + if (($interface != "any" && $settings['interface'] != "any") && + (strlen($prot) == 4) && + (strlen($settings['protocol']) == 4) && + substr($prot,0,3) == substr($settings['protocol'],0,3) && + substr($prot,3,1) != substr($settings['protocol'],3,1)) { + continue; + } + + if ($port == $settings['local_port'] && + substr($prot,0,3) == substr($settings['protocol'],0,3) && + ($interface == $settings['interface'] || + $interface == "any" || $settings['interface'] == "any")) { + return $settings['vpnid']; } } @@ -638,7 +653,7 @@ function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") } function openvpn_reconfigure($mode, $settings) { - global $g, $config, $openvpn_tls_server_modes; + global $g, $config, $openvpn_tls_server_modes, $openvpn_dh_lengths; if (empty($settings)) { return; @@ -866,7 +881,7 @@ function openvpn_reconfigure($mode, $settings) { // configure user auth modes switch ($settings['mode']) { case 'server_user': - $conf .= "client-cert-not-required\n"; + $conf .= "verify-client-cert none\n"; case 'server_tls_user': /* username-as-common-name is not compatible with server-bridge */ if (stristr($conf, "server-bridge") === false) { @@ -1072,21 +1087,58 @@ function openvpn_reconfigure($mode, $settings) { openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify"); } if ($settings['tls']) { - if ($mode == "server") { - $tlsopt = 0; + if ($settings['tls_type'] == "crypt") { + $tls_directive = "tls-crypt"; + $tlsopt = ""; } else { - $tlsopt = 1; + $tls_directive = "tls-auth"; + if ($mode == "server") { + $tlsopt = 0; + } else { + $tlsopt = 1; + } } - openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt); + openvpn_add_keyfile($settings['tls'], $conf, $mode_id, $tls_directive, $tlsopt); } + + /* NCP support. If it is not set, assume enabled since that is OpenVPN's default. */ + if ($settings['ncp_enable'] == "disabled") { + $conf .= "ncp-disable\n"; + } else { + /* If the ncp-ciphers list is empty, don't specify a list so OpenVPN's default will be used. */ + if (!empty($settings['ncp-ciphers'])) { + $conf .= "ncp-ciphers " . str_replace(',', ':', $settings['ncp-ciphers']) . "\n"; + } + } + break; } - if (!empty($settings['compression'])) { - if ($settings['compression'] == "noadapt") { - $conf .= "comp-noadapt\n"; - } else { - $conf .= "comp-lzo {$settings['compression']}\n"; + $compression = ""; + switch ($settings['compression']) { + case 'lz4': + case 'lz4-v2': + case 'lzo': + case 'stub': + $compression .= "compress {$settings['compression']}"; + break; + case 'noadapt': + $compression .= "comp-noadapt"; + break; + case 'adaptive': + case 'yes': + case 'no': + $compression .= "comp-lzo {$settings['compression']}"; + break; + default: + /* Add nothing to the configuration */ + break; + } + + if (!empty($compression)) { + $conf .= "{$compression}\n"; + if ($settings['compression_push']) { + $conf .= "push \"{$compression}\"\n"; } } @@ -1205,19 +1257,12 @@ function openvpn_restart($mode, $settings) { unlock($lockhandle); } -function openvpn_delete($mode, & $settings) { +function openvpn_delete($mode, $settings) { global $g, $config; $vpnid = $settings['vpnid']; $mode_id = $mode.$vpnid; - if (isset($settings['dev_mode'])) { - $tunname = "{$settings['dev_mode']}{$vpnid}"; - } else { - /* defaults to tun */ - $tunname = "tun{$vpnid}"; - } - if ($mode == "server") { $devname = "ovpns{$vpnid}"; } else { @@ -1236,11 +1281,8 @@ function openvpn_delete($mode, & $settings) { posix_kill($pid, SIGTERM); } - /* remove the device from the openvpn group */ - mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " -group openvpn"); - - /* restore the original adapter name */ - mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " name " . escapeshellarg($tunname)); + /* destroy the device */ + pfSense_interface_destroy($devname); /* remove the configuration files */ @array_map('unlink', glob("{$g['varetc_path']}/openvpn/{$mode_id}.*")); @@ -1314,6 +1356,13 @@ function openvpn_resync_csc(& $settings) { $csc_conf .= "ifconfig-push {$clientip} {$serverip}\n"; } } + + if (!empty($serversettings['tunnel_networkv6']) && !empty($settings['tunnel_networkv6'])) { + list($ipv6, $prefix) = explode('/', trim($serversettings['tunnel_networkv6'])); + list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix); + $csc_conf .= "ifconfig-ipv6-push {$settings['tunnel_networkv6']} {$ipv6_1}\n"; + } + file_put_contents($csc_path, $csc_conf); chown($csc_path, 'nobody'); chgrp($csc_path, 'nobody'); diff --git a/src/etc/inc/pfsense-utils.inc b/src/etc/inc/pfsense-utils.inc index aca0e902b0..847826bfb1 100644 --- a/src/etc/inc/pfsense-utils.inc +++ b/src/etc/inc/pfsense-utils.inc @@ -2395,13 +2395,12 @@ function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $ touch($urltable_filename); } - /* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */ - if (!isset($config['system']['use_mfs_tmpvar'])) { - unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz"); - } else { - /* Update the RAM disk store with the new/updated table file. */ - mwexec("cd / && /usr/bin/tar -czf \"{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz\" -C / \"{$urltable_filename}\""); + /* Remove existing archive and create an up to date archive if RAM disk is enabled. */ + unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz"); + if (isset($config['system']['use_mfs_tmpvar'])) { + mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename)); } + unlink_if_exists($tmp_urltable_filename); } else { if (!$validateonly) { @@ -3154,38 +3153,6 @@ function pkg_call_plugins($plugin_type, $plugin_params) { return $results; } -function restore_aliastables() { - global $g, $config; - - $dbpath = "{$g['vardb_path']}/aliastables/"; - - /* restore the alias tables, if we have them */ - $files = glob("{$g['cf_conf_path']}/RAM_Disk_Store{$dbpath}*.tgz"); - if (count($files)) { - echo "Restoring alias tables..."; - foreach ($files as $file) { - if (file_exists($file)) { - $aliastablesrestore = ""; - $aliastablesreturn = ""; - exec("cd /;LANG=C /usr/bin/tar -xzf {$file} 2>&1", $aliastablesrestore, $aliastablesreturn); - $aliastablesrestore = implode(" ", $aliastablesrestore); - if ($aliastablesreturn <> 0) { - log_error(sprintf(gettext('Alias table restore failed exited with %1$s, the error is: %2$s %3$s%4$s'), $aliastablesreturn, $aliastablesrestore, $file, "\n")); - } else { - log_error(sprintf(gettext('Alias table restore succeeded exited with %1$s, the result is: %2$s %3$s%4$s'), $aliastablesreturn, $aliastablesrestore, $dbpath.basename($file, ".tgz"), "\n")); - } - } - /* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */ - if (!isset($config['system']['use_mfs_tmpvar'])) { - unlink_if_exists("{$file}"); - } - } - echo "done.\n"; - return true; - } - return false; -} - // Convert IPv6 addresses to lower case function addrtolower($ip) { if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { diff --git a/src/etc/inc/priv.inc b/src/etc/inc/priv.inc index c430ced0f7..58dfe0971d 100644 --- a/src/etc/inc/priv.inc +++ b/src/etc/inc/priv.inc @@ -182,7 +182,7 @@ function get_user_privdesc(& $user) { return $privs; } -function isAllowed($username, $page) { +function isAdminUID($username) { global $_SESSION; if (!isset($username)) { @@ -199,6 +199,20 @@ function isAllowed($username, $page) { } } + return false; +} + +function isAllowed($username, $page) { + global $_SESSION; + + if (!isset($username)) { + return false; + } + + if (isAdminUID($username)) { + return true; + } + /* user privilege access check */ if (cmp_page_matches($page, $_SESSION['page-match'])) { return true; @@ -207,7 +221,6 @@ function isAllowed($username, $page) { return false; } - function isAllowedPage($page) { global $_SESSION; @@ -218,14 +231,8 @@ function isAllowedPage($page) { return false; } - /* admin/root access check */ - $user = getUserEntry($username); - if (isset($user)) { - if (isset($user['uid'])) { - if ($user['uid'] == 0) { - return true; - } - } + if (isAdminUID($username)) { + return true; } /* user privilege access check */ @@ -269,12 +276,33 @@ function getAllowedPages($username, &$attributes = array()) { if ($_SESSION['remoteauth']) { $authcfg = auth_get_authserver($config['system']['webgui']['authmode']); + // cache auth results for a short time to ease load on auth services & logs + if (isset($config['system']['webgui']['auth_refresh_time'])) { + $recheck_time = $config['system']['webgui']['auth_refresh_time']; + } else { + $recheck_time = 30; + } // obtain ldap groups if we are in ldap mode if ($authcfg['type'] == "ldap") { - $allowed_groups = @ldap_get_groups($username, $authcfg); + if ( isset($_SESSION["ldap_allowed_groups"]) && + ( time() <= $_SESSION["auth_check_time"]+ $recheck_time) ) { + $allowed_groups = $_SESSION["ldap_allowed_groups"]; + } else { + $allowed_groups = @ldap_get_groups($username, $authcfg); + $_SESSION["ldap_allowed_groups"] = $allowed_groups; + $_SESSION["auth_check_time"] = time(); + } } elseif ($authcfg['type'] == "radius") { - $allowed_groups = @radius_get_groups($attributes); + if ( isset($_SESSION["radius_allowed_groups"]) && + (time() <= $_SESSION["auth_check_time"] + $recheck_time) ) { + $allowed_groups = $_SESSION["radius_allowed_groups"]; + } else { + $allowed_groups = @radius_get_groups($attributes); + $_SESSION["radius_allowed_groups"] = $allowed_groups; + $_SESSION["auth_check_time"] = time(); + } } + } if (!$allowed_groups) { // search for a local user by name diff --git a/src/etc/inc/rrd.inc b/src/etc/inc/rrd.inc index 183f84ae15..cf3a1a9268 100644 --- a/src/etc/inc/rrd.inc +++ b/src/etc/inc/rrd.inc @@ -34,54 +34,6 @@ function dump_rrd_to_xml($rrddatabase, $xmldumpfile) { return($dumpret); } -function restore_rrd() { - global $g, $config; - - $rrddbpath = "{$g['vardb_path']}/rrd/"; - $rrdtool = "/usr/bin/nice -n20 /usr/local/bin/rrdtool"; - - $rrdrestore = ""; - $rrdreturn = ""; - if (file_exists("{$g['cf_conf_path']}/rrd.tgz") && isset($config['system']['use_mfs_tmpvar'])) { - foreach (glob("{$rrddbpath}/*.xml") as $xml_file) { - @unlink($xml_file); - } - unset($rrdrestore); - $_gb = exec("cd /;LANG=C /usr/bin/tar -tf {$g['cf_conf_path']}/rrd.tgz", $rrdrestore, $rrdreturn); - if ($rrdreturn != 0) { - log_error(sprintf(gettext('RRD restore failed exited with %1$s, the error is: %2$s'), $rrdreturn, $rrdrestore)); - return; - } - foreach ($rrdrestore as $xml_file) { - $rrd_file = '/' . substr($xml_file, 0, -4) . '.rrd'; - if (file_exists("{$rrd_file}")) { - @unlink($rrd_file); - } - file_put_contents("{$g['tmp_path']}/rrd_restore", $xml_file); - $_gb = exec("cd /;LANG=C /usr/bin/tar -xf {$g['cf_conf_path']}/rrd.tgz -T {$g['tmp_path']}/rrd_restore"); - if (!file_exists("/{$xml_file}")) { - log_error(sprintf(gettext("Could not extract %s RRD xml file from archive!"), $xml_file)); - continue; - } - $_gb = exec("$rrdtool restore -f '/{$xml_file}' '{$rrd_file}'", $output, $status); - if ($status) { - log_error(sprintf(gettext("rrdtool restore -f '%1\$s' '%2\$s' failed returning %3\$s."), $xml_file, $rrd_file, $status)); - continue; - } - unset($output); - @unlink("/{$xml_file}"); - } - unset($rrdrestore); - @unlink("{$g['tmp_path']}/rrd_restore"); - /* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */ - if (!isset($config['system']['use_mfs_tmpvar'])) { - unlink_if_exists("{$g['cf_conf_path']}/rrd.tgz"); - } - return true; - } - return false; -} - function create_new_rrd($rrdcreatecmd) { $rrdcreateoutput = array(); $rrdcreatereturn = 0; @@ -281,10 +233,6 @@ function enable_rrd_graphing() { } chown($rrddbpath, "nobody"); - if (platform_booting()) { - restore_rrd(); - } - /* db update script */ $rrdupdatesh = "#!/bin/sh\n"; $rrdupdatesh .= "\n"; @@ -309,14 +257,6 @@ function enable_rrd_graphing() { } } - if (platform_booting()) { - if (!is_dir($rrddbpath)) { - mkdir($rrddbpath, 0775); - } - - @chown($rrddbpath, "nobody"); - } - /* process all real and pseudo interfaces */ foreach ($ifdescrs as $ifname => $ifdescr) { $temp = get_real_interface($ifname); diff --git a/src/etc/inc/services.inc b/src/etc/inc/services.inc index ffabbbdd2c..45177d2d62 100644 --- a/src/etc/inc/services.inc +++ b/src/etc/inc/services.inc @@ -263,10 +263,22 @@ function services_radvd_configure($blacklist = array()) { $radvdconf .= "\tRDNSS {$dnsstring} { };\n"; } } + + $searchlist = array(); + $domainsearchlist = explode(';', $dhcpv6ifconf['radomainsearchlist']); + foreach ($domainsearchlist as $sd) { + $sd = trim($sd); + if (is_hostname($sd)) { + $searchlist[] = $sd; + } + } + if (count($searchlist) > 0) { + $searchliststring = trim(implode(" ", $searchlist)); + } if (!empty($dhcpv6ifconf['domain'])) { - $radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n"; + $radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} {$searchliststring} { };\n"; } elseif (!empty($config['system']['domain'])) { - $radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n"; + $radvdconf .= "\tDNSSL {$config['system']['domain']} {$searchliststring} { };\n"; } $radvdconf .= "};\n"; } @@ -468,23 +480,6 @@ function services_dhcpdv4_configure() { } } - if (platform_booting()) { - /* restore the leases, if we have them */ - if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) { - $dhcprestore = ""; - $dhcpreturn = ""; - exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn); - $dhcprestore = implode(" ", $dhcprestore); - if ($dhcpreturn <> 0) { - log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n")); - } - } - /* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */ - if (!isset($config['system']['use_mfs_tmpvar'])) { - unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz"); - } - } - $syscfg = $config['system']; if (!is_array($config['dhcpd'])) { $config['dhcpd'] = array(); @@ -1265,22 +1260,6 @@ function services_dhcpdv6_configure($blacklist = array()) { return 0; } - /* restore the leases, if we have them */ - if (platform_booting() && - isset($config['system']['use_mfs_tmpvar']) && - file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) { - $dhcprestore = ""; - $dhcpreturn = ""; - exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", - $dhcprestore, $dhcpreturn); - $dhcprestore = implode(" ", $dhcprestore); - if ($dhcpreturn <> 0) { - log_error(sprintf(gettext( - 'DHCP leases v6 restore failed exited with %1$s, the error is: %2$s'), - $dhcpreturn, $dhcprestore)); - } - } - $syscfg = $config['system']; if (!is_array($config['dhcpdv6'])) { $config['dhcpdv6'] = array(); @@ -1961,6 +1940,7 @@ function services_dyndns_configure_client($conf) { $dnsUser = $conf['username'], $dnsPass = $conf['password'], $dnsWildcard = $conf['wildcard'], + $dnsProxied = $conf['proxied'], $dnsMX = $conf['mx'], $dnsIf = "{$conf['interface']}", $dnsBackMX = NULL, @@ -2457,7 +2437,8 @@ begemotSnmpdModulePath."pf" = "/usr/lib/snmp_pf.so" EOD; } - if (isset($config['snmpd']['modules']['hostres'])) { + if (isset($config['snmpd']['modules']['hostres']) + && !(($specplatform['name'] == 'VMware') && (file_exists('/dev/cd0')))) { $snmpdconf .= << $dnsupdate) { - if (!isset($dnsupdate['enable'])) { - continue; - } - /* - * If it's using a gateway group, check if interface is - * the active gateway for that group - */ - $group_int = ''; - if (is_array($gwgroups[$dnsupdate['interface']])) { - if (!empty($gwgroups[$dnsupdate['interface']][0]['vip'])) { - $group_int = $gwgroups[$dnsupdate['interface']][0]['vip']; - } else { - $group_int = $gwgroups[$dnsupdate['interface']][0]['int']; - } - } - if (!empty($int) && ($int != $dnsupdate['interface']) && ($int != $group_int)) { - continue; - } - if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) { - continue; - } + if (!is_array($config['dnsupdates']['dnsupdate'])) { + return 0; + } - /* determine interface name */ - $if = get_failover_interface($dnsupdate['interface']); - - if (isset($dnsupdate['usepublicip'])) { - $wanip = dyndnsCheckIP($if); + $notify_text = ""; + $gwgroups = return_gateway_groups_array(); + foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) { + if (!isset($dnsupdate['enable'])) { + continue; + } + /* + * If it's using a gateway group, check if interface is + * the active gateway for that group + */ + $group_int = ''; + if (is_array($gwgroups[$dnsupdate['interface']])) { + if (!empty($gwgroups[$dnsupdate['interface']][0]['vip'])) { + $group_int = $gwgroups[$dnsupdate['interface']][0]['vip']; } else { - $wanip = get_interface_ip($if); + $group_int = $gwgroups[$dnsupdate['interface']][0]['int']; } + } + if (!empty($int) && ($int != $dnsupdate['interface']) && ($int != $group_int)) { + continue; + } + if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) { + continue; + } - $wanipv6 = get_interface_ipv6($if); - $cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache"; - $currentTime = time(); + /* determine interface name */ + $if = get_failover_interface($dnsupdate['interface']); - if ($wanip || $wanipv6) { - $keyname = $dnsupdate['keyname']; - /* trailing dot */ - if (substr($keyname, -1) != ".") { - $keyname .= "."; - } + if (isset($dnsupdate['usepublicip'])) { + $wanip = dyndnsCheckIP($if); + } else { + $wanip = get_interface_ip($if); + } - $hostname = $dnsupdate['host']; - /* trailing dot */ - if (substr($hostname, -1) != ".") { - $hostname .= "."; - } + $wanipv6 = get_interface_ipv6($if); + $cacheFile = $g['conf_path'] . + "/dyndns_{$dnsupdate['interface']}_rfc2136_" . + escapeshellarg($dnsupdate['host']) . + "_{$dnsupdate['server']}.cache"; + $cacheFilev6 = $cacheFile . ".ipv6"; + $currentTime = time(); - /* write private key file - this is dumb - public and private keys are the same for HMAC-MD5, - but nsupdate insists on having both */ - $fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w"); - $privkey = << $maxCacheAgeSecs) || $forced) { - $upinst .= "update delete {$dnsupdate['host']}. A\n"; - $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n"; - $notify_text .= sprintf(gettext('DynDNS updated IP Address (A) for %1$s on %2$s (%3$s) to %4$s'), $dnsupdate['host'], convert_real_interface_to_friendly_descr($if), $if, $wanip) . "\n"; - @file_put_contents($cacheFile, "{$wanip}|{$currentTime}"); - log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $cacheFile, $wanip)); - $need_update = true; - } else { - log_error(sprintf(gettext("phpDynDNS: Not updating %s A record because the IP address has not changed."), $dnsupdate['host'])); - } - } else { - @unlink($cacheFile); - } + /* Update IPv4 if we have it. */ + if (is_ipaddrv4($wanip) && $dnsupdate['recordtype'] != "AAAA") { + if (($wanip != $cachedipv4) || $forced || + (($currentTime - $cacheTimev4) > $maxCacheAgeSecs)) { + $upinst .= "update delete " . + "{$dnsupdate['host']}. A\n"; + $upinst .= "update add {$dnsupdate['host']}. " . + "{$dnsupdate['ttl']} A {$wanip}\n"; + $need_update = true; + } else { + log_error(sprintf(gettext( + "phpDynDNS: Not updating %s A record because the IP address has not changed."), + $dnsupdate['host'])); + } + } else { + @unlink($cacheFile); + unset($cacheFile); + } - /* Update IPv6 if we have it. */ - if (is_ipaddrv6($wanipv6) && $dnsupdate['recordtype'] != "A") { - if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) { - $upinst .= "update delete {$dnsupdate['host']}. AAAA\n"; - $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n"; - $notify_text .= sprintf(gettext('DynDNS updated IPv6 Address (AAAA) for %1$s on %2$s (%3$s) to %4$s'), $dnsupdate['host'], convert_real_interface_to_friendly_descr($if), $if, $wanipv6) . "\n"; - @file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}"); - log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s.ipv6: %2$s'), $cacheFile, $wanipv6)); - $need_update = true; - } else { - log_error(sprintf(gettext("phpDynDNS: Not updating %s AAAA record because the IPv6 address has not changed."), $dnsupdate['host'])); - } - } else { - @unlink("{$cacheFile}.ipv6"); - } + /* Update IPv6 if we have it. */ + if (is_ipaddrv6($wanipv6) && $dnsupdate['recordtype'] != "A") { + if (($wanipv6 != $cachedipv6) || $forced || + (($currentTime - $cacheTimev6) > $maxCacheAgeSecs)) { + $upinst .= "update delete " . + "{$dnsupdate['host']}. AAAA\n"; + $upinst .= "update add {$dnsupdate['host']}. " . + "{$dnsupdate['ttl']} AAAA {$wanipv6}\n"; + $need_update = true; + } else { + log_error(sprintf(gettext( + "phpDynDNS: Not updating %s AAAA record because the IPv6 address has not changed."), + $dnsupdate['host'])); + } + } else { + @unlink($cacheFilev6); + unset($cacheFilev6); + } - $upinst .= "\n"; /* mind that trailing newline! */ + $upinst .= "\n"; /* mind that trailing newline! */ - if ($need_update) { - @file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst); - unset($upinst); - /* invoke nsupdate */ - $cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key"; - if (isset($dnsupdate['usetcp'])) { - $cmd .= " -v"; - } - $cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}"; - mwexec_bg($cmd); - unset($cmd); - } + if (!$need_update) { + continue; + } + + @file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", + $upinst); + unset($upinst); + /* invoke nsupdate */ + $cmd = "/usr/local/bin/nsupdate -k " . + "{$g['varetc_path']}/K{$i}{$keyname}+157+00000.key"; + + if (isset($dnsupdate['usetcp'])) { + $cmd .= " -v"; + } + + $cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}"; + + if (mwexec($cmd) == 0) { + if (!empty($cacheFile)) { + @file_put_contents($cacheFile, + "{$wanip}|{$currentTime}"); + log_error(sprintf(gettext( + 'phpDynDNS: updating cache file %1$s: %2$s'), + $cacheFile, $wanip)); + $notify_text .= sprintf(gettext( + 'DynDNS updated IP Address (A) for %1$s on %2$s (%3$s) to %4$s'), + $dnsupdate['host'], + convert_real_interface_to_friendly_descr($if), + $if, $wanip) . "\n"; + } + if (!empty($cacheFilev6)) { + @file_put_contents($cacheFilev6, + "{$wanipv6}|{$currentTime}"); + log_error(sprintf(gettext( + 'phpDynDNS: updating cache file %1$s: %2$s'), + $cacheFilev6, $wanipv6)); + $notify_text .= sprintf(gettext( + 'DynDNS updated IPv6 Address (AAAA) for %1$s on %2$s (%3$s) to %4$s'), + $dnsupdate['host'], + convert_real_interface_to_friendly_descr($if), + $if, $wanipv6) . "\n"; + } + } else { + if (!empty($cacheFile)) { + log_error(sprintf(gettext( + 'phpDynDNS: ERROR while updating IP Address (A) for %1$s (%2$s)'), + $dnsupdate['host'], $wanip)); + } + if (!empty($cacheFilev6)) { + log_error(sprintf(gettext( + 'phpDynDNS: ERROR while updating IP Address (AAAA) for %1$s (%2$s)'), + $dnsupdate['host'], $wanipv6)); } } - if (!empty($notify_text)) { - notify_all_remote($notify_text); - } + unset($cmd); + } + + if (!empty($notify_text)) { + notify_all_remote($notify_text); } return 0; diff --git a/src/etc/inc/system.inc b/src/etc/inc/system.inc index 573f074f50..10673167bc 100644 --- a/src/etc/inc/system.inc +++ b/src/etc/inc/system.inc @@ -1931,13 +1931,16 @@ function system_reboot_sync($reroot=false) { } function system_reboot_cleanup() { - global $config, $cpzone; + global $config, $cpzone, $cpzoneid; mwexec("/usr/local/bin/beep.sh stop"); require_once("captiveportal.inc"); if (is_array($config['captiveportal'])) { foreach ($config['captiveportal'] as $cpzone=>$cp) { - captiveportal_radius_stop_all(); + /* send Accounting-Stop packet for all clients, termination cause 'Admin-Reboot' */ + $cpzoneid = $cp[zoneid]; + captiveportal_radius_stop_all(7); // Admin-Reboot + /* Send Accounting-Off packet to the RADIUS server */ captiveportal_send_server_accounting(true); } } @@ -2230,6 +2233,11 @@ function system_identify_specific_platform() { return (array('name' => 'Hyper-V', 'descr' => 'Hyper-V Virtual Machine')); } break; + case 'VMware Virtual Platform': + if ($maker[0] == "VMware, Inc.") { + return (array('name' => 'VMware', 'descr' => 'VMware Virtual Machine')); + } + break; } if (strpos($hw_model, "PC Engines WRAP") !== false) { diff --git a/src/etc/inc/upgrade_config.inc b/src/etc/inc/upgrade_config.inc index 61ecc5129b..41b4e3a897 100644 --- a/src/etc/inc/upgrade_config.inc +++ b/src/etc/inc/upgrade_config.inc @@ -5063,4 +5063,86 @@ function upgrade_159_to_160() { } } } + +/* RAM Disk Management */ +function upgrade_160_to_161() { + global $g, $config; + + if (!isset($config['system']['use_mfs_tmpvar'])) { + return; + } + + // Move existing RRD backup to the RAM Disk Store if it don't already exist there. + // Restore existing RRD XML dump backup. + if (file_exists("{$g['cf_conf_path']}/rrd.tgz") && !file_exists("{$g['cf_conf_path']}/RAM_Disk_Store/rrd.tgz")) { + $rrddbpath = "{$g['vardb_path']}/rrd/"; + $rrdtool = "/usr/bin/nice -n20 /usr/local/bin/rrdtool"; + + $rrdrestore = ""; + $rrdreturn = ""; + unlink_if_exists("{$rrddbpath}/*.xml"); + + unset($rrdrestore); + $_gb = exec("LANG=C /usr/bin/tar -tf {$g['cf_conf_path']}/rrd.tgz", $rrdrestore, $rrdreturn); + if ($rrdreturn != 0) { + log_error(sprintf(gettext('RRD restore failed exited with %1$s, the error is: %2$s'), $rrdreturn, $rrdrestore)); + } else { + foreach ($rrdrestore as $xml_file) { + $rrd_file = '/' . substr($xml_file, 0, -4) . '.rrd'; + unlink_if_exists("{$rrd_file}"); + + file_put_contents("{$g['tmp_path']}/rrd_restore", $xml_file); + $_gb = exec("LANG=C /usr/bin/tar -xf {$g['cf_conf_path']}/rrd.tgz -C / -T {$g['tmp_path']}/rrd_restore"); + if (!file_exists("/{$xml_file}")) { + log_error(sprintf(gettext("Could not extract %s RRD xml file from archive!"), $xml_file)); + continue; + } + $_gb = exec("$rrdtool restore -f '/{$xml_file}' '{$rrd_file}'", $output, $status); + if ($status) { + log_error(sprintf(gettext("rrdtool restore -f '%1\$s' '%2\$s' failed returning %3\$s."), $xml_file, $rrd_file, $status)); + continue; + } + unset($output); + @unlink("/{$xml_file}"); + } + unset($rrdrestore); + @unlink("{$g['tmp_path']}/rrd_restore"); + + // Create a new RRD backup to the RAM Disk Store (without RRD XML dump). + exec("/etc/rc.backup_rrd.sh"); + $ramds_updated = true; + + // Rename previous RRD backup so it will not restore again. Don't delete in case needed for recovery. + rename("{$g['cf_conf_path']}/rrd.tgz", "{$g['cf_conf_path']}/rrd.tgz.old"); + } + } + + // Move existing DHCP leases backup to the RAM Disk Store if it don't already exist there. + if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz") && ! file_exists("{$g['cf_conf_path']}/RAM_Disk_Store/dhcpleases.tgz")) { + rename("{$g['cf_conf_path']}/dhcpleases.tgz", "{$g['cf_conf_path']}/RAM_Disk_Store/dhcpleases.tgz"); + $ramds_updated = true; + } + + // Move existing alias table backups to the RAM Disk Store if they don't already exist there. + $dbpath = "{$g['vardb_path']}/aliastables/"; + $files = glob("{$g['cf_conf_path']}/RAM_Disk_Store{$dbpath}*.tgz"); + if (count($files)) { + foreach ($files as $file) { + if (! file_exists("{$g['cf_conf_path']}/RAM_Disk_Store/".basename($file))) { + rename($file, "{$g['cf_conf_path']}/RAM_Disk_Store/".basename($file)); + $ramds_updated = true; + } + } + // Remove existing alias table backups directory if empty. + @rmdir("{$g['cf_conf_path']}/RAM_Disk_Store/var/db/aliastables"); + @rmdir("{$g['cf_conf_path']}/RAM_Disk_Store/var/db/"); + @rmdir("{$g['cf_conf_path']}/RAM_Disk_Store/var/"); + } + + // Restore RAM Disk Store if updated. + if ($ramds_updated) { + exec("/etc/rc.restore_ramdisk_store"); + } +} + ?> diff --git a/src/etc/inc/util.inc b/src/etc/inc/util.inc index 78bf1b638e..2176423d86 100644 --- a/src/etc/inc/util.inc +++ b/src/etc/inc/util.inc @@ -485,32 +485,32 @@ function ip_range_to_address_array($startip, $endip, $max_size = 5000) { return $rangeaddresses; } -/* Convert an IPv4 or IPv6 IP range to an array of subnets which can contain the range. - Algorithm and embodying code PD'ed by Stilez - enjoy as you like :-) - - Documented on pfsense dev list 19-20 May 2013. Summary: - - The algorithm looks at patterns of 0's and 1's in the least significant bit(s), whether IPv4 or IPv6. - These are all that needs checking to identify a _guaranteed_ correct, minimal and optimal subnet array. - - As a result, string/binary pattern matching of the binary IP is very efficient. It uses just 2 pattern-matching rules - to chop off increasingly larger subnets at both ends that can't be part of larger subnets, until nothing's left. - - (a) If any range has EITHER low bit 1 (in startip) or 0 (in endip), that end-point is _always guaranteed_ to be optimally - represented by its own 'single IP' CIDR; the remaining range then shrinks by one IP up or down, causing the new end-point's - low bit to change from 1->0 (startip) or 0->1 (endip). Only one edge case needs checking: if a range contains exactly 2 - adjacent IPs of this format, then the two IPs themselves are required to span it, and we're done. - Once this rule is applied, the remaining range is _guaranteed_ to end in 0's and 1's so rule (b) can now be used, and its - low bits can now be ignored. - - (b) If any range has BOTH startip and endip ending in some number of 0's and 1's respectively, these low bits can - *always* be ignored and "bit-shifted" for subnet spanning. So provided we remember the bits we've place-shifted, we can - _always_ right-shift and chop off those bits, leaving a smaller range that has EITHER startip ending in 1 or endip ending - in 0 (ie can now apply (a) again) or the entire range has vanished and we're done. - We then loop to redo (a) again on the remaining (place shifted) range until after a few loops, the remaining (place shifted) - range 'vanishes' by meeting the exit criteria of (a) or (b), and we're done. -*/ - +/* + * Convert an IPv4 or IPv6 IP range to an array of subnets which can contain the range. + * Algorithm and embodying code PD'ed by Stilez - enjoy as you like :-) + * + * Documented on pfsense dev list 19-20 May 2013. Summary: + * + * The algorithm looks at patterns of 0's and 1's in the least significant bit(s), whether IPv4 or IPv6. + * These are all that needs checking to identify a _guaranteed_ correct, minimal and optimal subnet array. + * + * As a result, string/binary pattern matching of the binary IP is very efficient. It uses just 2 pattern-matching rules + * to chop off increasingly larger subnets at both ends that can't be part of larger subnets, until nothing's left. + * + * (a) If any range has EITHER low bit 1 (in startip) or 0 (in endip), that end-point is _always guaranteed_ to be optimally + * represented by its own 'single IP' CIDR; the remaining range then shrinks by one IP up or down, causing the new end-point's + * low bit to change from 1->0 (startip) or 0->1 (endip). Only one edge case needs checking: if a range contains exactly 2 + * adjacent IPs of this format, then the two IPs themselves are required to span it, and we're done. + * Once this rule is applied, the remaining range is _guaranteed_ to end in 0's and 1's so rule (b) can now be used, and its + * low bits can now be ignored. + * + * (b) If any range has BOTH startip and endip ending in some number of 0's and 1's respectively, these low bits can + * *always* be ignored and "bit-shifted" for subnet spanning. So provided we remember the bits we've place-shifted, we can + * _always_ right-shift and chop off those bits, leaving a smaller range that has EITHER startip ending in 1 or endip ending + * in 0 (ie can now apply (a) again) or the entire range has vanished and we're done. + * We then loop to redo (a) again on the remaining (place shifted) range until after a few loops, the remaining (place shifted) + * range 'vanishes' by meeting the exit criteria of (a) or (b), and we're done. + */ function ip_range_to_subnet_array($ip1, $ip2) { if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2)) { @@ -986,12 +986,18 @@ function is_domain($domain, $allow_wildcard=false) { } /* returns true if $macaddr is a valid MAC address */ -function is_macaddr($macaddr) { +function is_macaddr($macaddr, $partial=false) { $values = explode(":", $macaddr); - if (count($values) != 6) { + + /* Verify if the MAC address has a proper amount of parts for either a partial or full match. */ + if ($partial) { + if ((count($values) < 1) || (count($values) > 6)) { + return false; + } + } elseif (count($values) != 6) { return false; } - for ($i = 0; $i < 6; $i++) { + for ($i = 0; $i < count($values); $i++) { if (ctype_xdigit($values[$i]) == false) return false; if (hexdec($values[$i]) < 0 || hexdec($values[$i]) > 255) @@ -1784,10 +1790,11 @@ function arp_get_mac_by_ip($ip) { /* return a fieldname that is safe for xml usage */ function xml_safe_fieldname($fieldname) { - $replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', - '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?', - ':', ',', '.', '\'', '\\' - ); + $replace = array( + '/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', + '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?', + ':', ',', '.', '\'', '\\' + ); return strtolower(str_replace($replace, "", $fieldname)); } @@ -2546,4 +2553,92 @@ function validateipaddr(&$addr, $type, $label, &$err_msg, $alias=false) { return false; } + +/* format a string to look (more) like the expected DUID format: + * 1) Replace any "-" with ":" + * 2) If the user inputs 14 components, then add the expected "0e:00:" to the front. + * This is convenience, because the actual DUID (which is reported in logs) is the last 14 components. + * 3) If any components are input with just a single char (hex digit hopefully), put a "0" in front. + * + * The final result should be closer to: + * + * "0e:00:00:01:00:01:nn:nn:nn:nn:nn:nn:nn:nn:nn:nn" + * + * This function does not validate the input. is_duid() will do validation. +*/ +function format_duid($dhcp6duid) { + $values = explode(":", strtolower(str_replace("-", ":", $dhcp6duid))); + if (count($values) == 14) { + array_unshift($values, "0e", "00"); + } + + array_walk($values, function(&$value) { + $value = str_pad($value, 2, '0', STR_PAD_LEFT); + }); + + return implode(":", $values); +} + +/* returns true if $dhcp6duid is a valid duid entry */ +function is_duid($dhcp6duid) { + $values = explode(":", $dhcp6duid); + if (count($values) != 16 || strlen($dhcp6duid) != 47) { + return false; + } + for ($i = 0; $i < 16; $i++) { + if (ctype_xdigit($values[$i]) == false) + return false; + if (hexdec($values[$i]) < 0 || hexdec($values[$i]) > 255) + return false; + } + return true; +} + +/* Write the DHCP6 DUID file */ +function write_dhcp6_duid($duidstring) { + // Create the hex array from the dhcp6duid config entry and write to file + global $g; + + if(!is_duid($duidstring)) { + log_error(gettext("Error: attempting to write DUID file - Invalid DUID detected")); + return false; + } + $temp = str_replace(":","",$duidstring); + $duid_binstring = pack("H*",$temp); + if ($fd = fopen("{$g['vardb_path']}/dhcp6c_duid", "wb")) { + fwrite($fd, $duid_binstring); + fclose($fd); + return true; + } + log_error(gettext("Error: attempting to write DUID file - File write error")); + return false; +} + +/* returns duid string from 'vardb_path']}/dhcp6c_duid' */ +function get_duid_from_file() { + global $g; + + $duid_ASCII = ""; + $count = 0; + + if (file_exists("{$g['vardb_path']}/dhcp6c_duid") && + ($fd = fopen("{$g['vardb_path']}/dhcp6c_duid", "r"))) { + if(filesize("{$g['vardb_path']}/dhcp6c_duid")==16) { + $buffer = fread($fd,16); + while($count < 16) { + $duid_ASCII .= bin2hex($buffer[$count]); + $count++; + if($count < 16) { + $duid_ASCII .= ":"; + } + } + } + fclose($fd); + } + //if no file or error with read then the string returns blanked DUID string + if(!is_duid($duid_ASCII)) { + return "--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--"; + } + return($duid_ASCII); +} ?> diff --git a/src/etc/inc/vpn.inc b/src/etc/inc/vpn.inc index f4fa23df95..7cd3475bf1 100644 --- a/src/etc/inc/vpn.inc +++ b/src/etc/inc/vpn.inc @@ -47,10 +47,11 @@ function vpn_logging_cfgtxt() { global $config, $ipsec_log_cats, $ipsec_log_sevs; $cfgtext = array(); + $log_levels = ipsec_get_loglevels(); foreach (array_keys($ipsec_log_cats) as $cat) { - if (is_numeric($config['ipsec']['logging'][$cat]) && - in_array(intval($config['ipsec']['logging'][$cat]), array_keys($ipsec_log_sevs), true)) { - $cfgtext[] = "${cat} = {$config['ipsec']['logging'][$cat]}"; + if (is_numeric($log_levels[$cat]) && + in_array(intval($log_levels[$cat]), array_keys($ipsec_log_sevs), true)) { + $cfgtext[] = "${cat} = {$log_levels[$cat]}"; } } diff --git a/src/etc/pfSense-rc b/src/etc/pfSense-rc index 382da912fe..2bc0ab8b56 100755 --- a/src/etc/pfSense-rc +++ b/src/etc/pfSense-rc @@ -105,6 +105,20 @@ while [ ${mount_rc} -ne 0 -a ${attempts} -lt 3 ]; do attempts=$((attempts+1)) done +# Handle ZFS read-only case +/sbin/kldstat -qm zfs +if [ $? -eq 0 ]; then + ZFSFSAVAILABLE=$(/sbin/zfs mount 2>/dev/null | wc -l) + if [ $ZFSFSAVAILABLE -eq 0 ]; then + /sbin/kldunload zfs + elif [ -f /usr/bin/grep ]; then + ZFSROOT=`/sbin/zfs mount | /usr/bin/grep ' /$' | /usr/bin/cut -d ' ' -f 1` + if [ "$ZFSROOT" != "" ]; then + /sbin/zfs set readonly=off $ZFSROOT + fi + fi +fi + # If /conf is a directory, convert it to a symlink to /cf/conf if [ -d "/conf" ]; then # If item is not a symlink then rm and recreate @@ -122,14 +136,16 @@ if [ "${USE_MFS_TMPVAR}" != "true" -a -f /root/var/db/pkg/local.sqlite ]; then MOVE_PKG_DATA=1 rm -rf /var/db/pkg 2>/dev/null rm -rf /var/cache/pkg 2>/dev/null - mv /root/var/db/pkg /var/db - mv /root/var/cache/pkg /var/cache + mv -f /root/var/db/pkg /var/db + mv -f /root/var/cache/pkg /var/cache # If use MFS var is enabled, move files to a safe place elif [ "${USE_MFS_TMPVAR}" = "true" -a -f /var/db/pkg/local.sqlite ]; then MOVE_PKG_DATA=1 + rm -rf /root/var/db/pkg 2>/dev/null + rm -rf /root/var/cache/pkg 2>/dev/null /bin/mkdir -p /root/var/db /root/var/cache - mv /var/db/pkg /root/var/db - mv /var/cache/pkg /root/var/cache + mv -f /var/db/pkg /root/var/db + mv -f /var/cache/pkg /root/var/cache fi if [ "${USE_MFS_TMPVAR}" = "true" ]; then @@ -142,6 +158,9 @@ if [ -n "${MOVE_PKG_DATA}" -o "${USE_MFS_TMPVAR}" = "true" ]; then ln -sf ../../root/var/cache/pkg /var/cache/pkg fi +# Restore contents of the RAM disk store +/etc/rc.restore_ramdisk_store + # Make sure /home exists [ -d /home ] \ || mkdir /home @@ -150,20 +169,6 @@ fi /bin/rm -f /root/TRIM_set /bin/rm -f /root/TRIM_unset -# Handle ZFS read-only case -/sbin/kldstat -qm zfs -if [ $? -eq 0 ]; then - ZFSFSAVAILABLE=$(/sbin/zfs mount 2>/dev/null | wc -l) - if [ $ZFSFSAVAILABLE -eq 0 ]; then - /sbin/kldunload zfs - elif [ -f /usr/bin/grep ]; then - ZFSROOT=`/sbin/zfs mount | /usr/bin/grep ' /$' | /usr/bin/cut -d ' ' -f 1` - if [ "$ZFSROOT" != "" ]; then - /sbin/zfs set readonly=off $ZFSROOT - fi - fi -fi - # Disable APM on ATA drives. Leaving this on will kill drives long-term, especially laptop drives, by generating excessive Load Cycles. if [ -f /etc/rc.disable_hdd_apm ]; then /etc/rc.disable_hdd_apm diff --git a/src/etc/pfSense-rc.shutdown b/src/etc/pfSense-rc.shutdown index dc6221f851..0f7b48c70b 100755 --- a/src/etc/pfSense-rc.shutdown +++ b/src/etc/pfSense-rc.shutdown @@ -50,4 +50,5 @@ if [ "${USE_MFS_TMPVAR}" = "true" ] || [ "${DISK_TYPE}" = "md" ]; then /etc/rc.backup_aliastables.sh /etc/rc.backup_rrd.sh /etc/rc.backup_dhcpleases.sh + /etc/rc.backup_logs.sh fi diff --git a/src/etc/rc.backup_aliastables.sh b/src/etc/rc.backup_aliastables.sh index 7999b0ad7c..b25d20cc68 100755 --- a/src/etc/rc.backup_aliastables.sh +++ b/src/etc/rc.backup_aliastables.sh @@ -3,18 +3,23 @@ : ${DBPATH:=/var/db/aliastables} : ${CF_CONF_PATH:=/cf/conf} -: ${RAM_Disk_Store:=${CF_CONF_PATH}/RAM_Disk_Store/${DBPATH}} +: ${RAM_Disk_Store:=${CF_CONF_PATH}/RAM_Disk_Store} # Save the alias tables database to the RAM disk store. if [ -d "${DBPATH}" ]; then + echo -n "Saving Alias Tables to RAM disk store..."; + if [ ! -d "${RAM_Disk_Store}" ]; then mkdir -p "${RAM_Disk_Store}" fi for aliastablefile in "${DBPATH}"/* ; do filename="$(basename ${aliastablefile})" - if [ ! -f "${RAM_Disk_Store}/${filename}.tgz" ]; then - cd / && /usr/bin/tar -czf "${RAM_Disk_Store}/${filename}.tgz" -C / "${DBPATH}/${filename}" + if [ ! -f "${RAM_Disk_Store}/${filename}.tgz" -o "${RAM_Disk_Store}/${filename}.tgz" -ot "${DBPATH#/}/${filename}" ]; then + [ -f "${RAM_Disk_Store}/${filename}.tgz" ] && /bin/rm -f "${RAM_Disk_Store}/${filename}.tgz" + /usr/bin/tar -czf "${RAM_Disk_Store}/${filename}.tgz" -C / "${DBPATH#/}/${filename}" fi done + + echo "done."; fi diff --git a/src/etc/rc.backup_dhcpleases.sh b/src/etc/rc.backup_dhcpleases.sh index 7a8e7419de..d7c154a652 100755 --- a/src/etc/rc.backup_dhcpleases.sh +++ b/src/etc/rc.backup_dhcpleases.sh @@ -1,6 +1,21 @@ #!/bin/sh -# Save the DHCP lease database to the config path. -if [ -d "/var/dhcpd/var/db" ]; then - cd / && tar -czf /cf/conf/dhcpleases.tgz -C / var/dhcpd/var/db/ +: ${DBPATH:=/var/dhcpd/var/db} +: ${CF_CONF_PATH:=/cf/conf} + +: ${RAM_Disk_Store:=${CF_CONF_PATH}/RAM_Disk_Store} + +# Save the DHCP lease database to the RAM disk store. +if [ -d "${DBPATH}" ]; then + echo -n "Saving DHCP Leases to RAM disk store..."; + + [ -f "${RAM_Disk_Store}/dhcpleases.tgz" ] && /bin/rm -f "${RAM_Disk_Store}/dhcpleases.tgz" + + if [ ! -d "${RAM_Disk_Store}" ]; then + mkdir -p "${RAM_Disk_Store}" + fi + + /usr/bin/tar -czf "${RAM_Disk_Store}/dhcpleases.tgz" -C / "${DBPATH#/}/" + + echo "done."; fi diff --git a/src/etc/rc.backup_logs.sh b/src/etc/rc.backup_logs.sh new file mode 100755 index 0000000000..89495e5149 --- /dev/null +++ b/src/etc/rc.backup_logs.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# +# rc.backup_logs.sh +# +# part of pfSense (https://www.pfsense.org) +# Copyright (c) 2016 Rubicon Communications, LLC (Netgate) +# All rights reserved. +# +# Based on src/etc/rc.d/savecore from FreeBSD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +: ${DBPATH:=/var/log} +: ${CF_CONF_PATH:=/cf/conf} + +: ${RAM_Disk_Store:=${CF_CONF_PATH}/RAM_Disk_Store} + +# Save the logs database to the RAM disk store. +if [ -d "${DBPATH}" ]; then + echo -n "Saving Logs to RAM disk store..."; + + [ -f "${RAM_Disk_Store}/logs.tgz" ] && /bin/rm -f "${RAM_Disk_Store}/logs.tgz" + + if [ ! -d "${RAM_Disk_Store}" ]; then + mkdir -p "${RAM_Disk_Store}" + fi + + /usr/bin/tar -czf "${RAM_Disk_Store}/logs.tgz" -C / "${DBPATH#/}/" + + echo "done."; +fi diff --git a/src/etc/rc.backup_rrd.sh b/src/etc/rc.backup_rrd.sh index 7914bd10a9..ca3d67c12f 100755 --- a/src/etc/rc.backup_rrd.sh +++ b/src/etc/rc.backup_rrd.sh @@ -1,25 +1,21 @@ #!/bin/sh -: ${RRDDBPATH:=/var/db/rrd} +: ${DBPATH:=/var/db/rrd} : ${CF_CONF_PATH:=/cf/conf} -# Save the rrd databases to the config path. -if [ -d "${RRDDBPATH}" ]; then - [ -f "${CF_CONF_PATH}/rrd.tgz" ] && /bin/rm -f "${CF_CONF_PATH}"/rrd.tgz +: ${RAM_Disk_Store:=${CF_CONF_PATH}/RAM_Disk_Store} - tgzlist="" +# Save the rrd databases to the RAM disk store. +if [ -d "${DBPATH}" ]; then + echo -n "Saving RRD to RAM disk store..."; - for rrdfile in "${RRDDBPATH}"/*.rrd ; do - xmlfile="${rrdfile%.rrd}.xml" - tgzfile="${rrdfile%.rrd}.tgz" - /usr/bin/nice -n20 /usr/local/bin/rrdtool dump "$rrdfile" "$xmlfile" - cd / && /usr/bin/tar -czf "${tgzfile}" -C / "${RRDDBPATH#/}"/*.xml - /bin/rm -f "${RRDDBPATH}"/*.xml - tgzlist="${tgzlist} @${tgzfile}" - done - if [ -n "${tgzlist}" ]; then - cd / && /usr/bin/tar -czf "${CF_CONF_PATH}/rrd.tgz" ${tgzlist} - /bin/rm -f "${RRDDBPATH}"/*.tgz + [ -f "${RAM_Disk_Store}/rrd.tgz" ] && /bin/rm -f "${RAM_Disk_Store}/rrd.tgz" + + if [ ! -d "${RAM_Disk_Store}" ]; then + mkdir -p "${RAM_Disk_Store}" fi -fi + /usr/bin/tar -czf "${RAM_Disk_Store}/rrd.tgz" -C / "${DBPATH#/}/" + + echo "done."; +fi diff --git a/src/etc/rc.bootup b/src/etc/rc.bootup index 5629102eb8..8fe9b16a99 100755 --- a/src/etc/rc.bootup +++ b/src/etc/rc.bootup @@ -176,8 +176,10 @@ interfaces_loopback_configure(); /* start syslogd */ system_syslogd_start(); -/* restore alias tables */ -restore_aliastables(); +/* Log the RAM disk restore messages. */ +if (file_exists("/var/log/restore_ramdisk_store.boot")) { + exec("logger -f /var/log/restore_ramdisk_store.boot"); +} echo "Starting Secure Shell Services..."; send_event("service reload sshd"); diff --git a/src/etc/rc.prunecaptiveportal b/src/etc/rc.prunecaptiveportal index 8a5253baa4..89e63282ed 100755 --- a/src/etc/rc.prunecaptiveportal +++ b/src/etc/rc.prunecaptiveportal @@ -43,18 +43,16 @@ if (!is_array($config['captiveportal'][$cpzone])) { } $cpzoneid = $config['captiveportal'][$cpzone]['zoneid']; -if (file_exists("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running")) { - $stat = stat("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running"); - if (time() - $stat['mtime'] >= 120) { - @unlink("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running"); - } else { - log_error("Skipping CP pruning process because previous/another instance is already running"); - return; - } +$rcprunelock = try_lock("rcprunecaptiveportal{$cpzone}", 3); + +if (!$rcprunelock) { + log_error("Skipping CP pruning process for zone {$cpzone} because previous/another instance is already running"); + unlock_force("rcprunecaptiveportal{$cpzone}"); + return; } -@file_put_contents("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running", ""); captiveportal_prune_old(); -@unlink("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running"); + +unlock($rcprunelock); ?> diff --git a/src/etc/rc.reboot b/src/etc/rc.reboot index e48f927614..c547456974 100755 --- a/src/etc/rc.reboot +++ b/src/etc/rc.reboot @@ -44,6 +44,7 @@ if [ "${USE_MFS_TMPVAR}" = "true" ] || [ "${DISK_TYPE}" = "md" ]; then /etc/rc.backup_aliastables.sh /etc/rc.backup_rrd.sh /etc/rc.backup_dhcpleases.sh + /etc/rc.backup_logs.sh fi sleep 1 diff --git a/src/etc/rc.restore_ramdisk_store b/src/etc/rc.restore_ramdisk_store new file mode 100755 index 0000000000..cd3332455f --- /dev/null +++ b/src/etc/rc.restore_ramdisk_store @@ -0,0 +1,82 @@ +#!/bin/sh +# +# rc.restore_ramdisk_store +# +# part of pfSense (https://www.pfsense.org) +# Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate) +# All rights reserved. +# +# Based on src/etc/rc.d/savecore from FreeBSD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Wildcard file existence check function +wildcard_file_exists() { + for file in "$1"; do + if [ -f "$file" ]; then + return 0 + fi + done + return 1 +} + +: ${DBPATH:=/var/dhcpd/var/db} +: ${CF_CONF_PATH:=/cf/conf} + +: ${RAM_Disk_Store:=${CF_CONF_PATH}/RAM_Disk_Store} + +# See if there are any backup files (*.tgz) in the RAM disk store. If so, restore them. +if wildcard_file_exists "${RAM_Disk_Store}/"*".tgz"; then + + mesg="Restoring contents of RAM disk store..." + echo -n "$mesg" + + USE_MFS_TMPVAR=$(/usr/local/sbin/read_xml_tag.sh boolean system/use_mfs_tmpvar) + + # Restore the ram disk + for backup_file in "${RAM_Disk_Store}/"*".tgz"; do + if [ -f "$backup_file" ]; then + /usr/bin/tar -xzf "${backup_file}" -C / 2>&1 + exit_code=$? + if [ $exit_code -ne 0 ]; then + mesg="$mesg\nRAM disk restore failed: exit code $exit_code: $backup_file" + error=1; + continue + fi + + mesg="$mesg\nRAM disk restore succeeded: $backup_file" + + #If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. + if [ "${USE_MFS_TMPVAR}" != "true" ]; then + /bin/rm -f "${backup_file}" + fi + fi + done + + if [ $error ]; then + mesg="$mesg\nRAM disk restore failed." + echo " error."; + else + mesg="$mesg\nRAM disk restore succeeded." + echo " done."; + fi + + /bin/mkdir -p /var/log/ + printf "$mesg" > /var/log/restore_ramdisk_store.boot + + # See if there are any backup files (*.tgz) in the RAM disk store. If not, and no error, clean up. + if ! wildcard_file_exists "${RAM_Disk_Store}/"*".tgz" && [ ! $error ]; then + /bin/rmdir "$RAM_Disk_Store" >/dev/null 2>&1 + /bin/rm -f /var/log/restore_ramdisk_store.boot + fi +fi diff --git a/src/etc/skel/dot.shrc b/src/etc/skel/dot.shrc index e72197bfd8..e9f0ca6f65 100644 --- a/src/etc/skel/dot.shrc +++ b/src/etc/skel/dot.shrc @@ -32,6 +32,12 @@ if [ "${HTTP_PROXY_AUTH_USER}" != "" ] && [ "${HTTP_PROXY_AUTH_PASS}" != "" ]; t export HTTP_PROXY_AUTH fi +USE_MFS_TMPVAR=$(/usr/local/sbin/read_xml_tag.sh boolean system/use_mfs_tmpvar) +if [ "${USE_MFS_TMPVAR}" = "true" ]; then + export PKG_DBDIR='/root/var/db/pkg' + export PKG_CACHEDIR='/root/var/cache/pkg' +fi + # Detect interactive logins and display the shell unset _interactive if [ -n "${SSH_TTY}" ]; then diff --git a/src/etc/skel/dot.tcshrc b/src/etc/skel/dot.tcshrc index db9846ff96..28e3fc8d74 100644 --- a/src/etc/skel/dot.tcshrc +++ b/src/etc/skel/dot.tcshrc @@ -55,3 +55,9 @@ if ( ${http_proxy_auth_user} != "" && ${http_proxy_auth_pass} != "" ) then set http_proxy_auth="basic:*:${http_proxy_auth_user}:${http_proxy_auth_pass}" setenv HTTP_PROXY_AUTH "${http_proxy_auth}" endif + +set use_mfs_tmpvar=`/usr/local/sbin/read_xml_tag.sh boolean system/use_mfs_tmpvar` +if ( $use_mfs_tmpvar == "true" ) then + setenv PKG_DBDIR '/root/var/db/pkg' + setenv PKG_CACHEDIR '/root/var/cache/pkg' +endif diff --git a/src/usr/local/www/crash_reporter.php b/src/usr/local/www/crash_reporter.php index 9a74c3eead..4bb2ad7ac5 100644 --- a/src/usr/local/www/crash_reporter.php +++ b/src/usr/local/www/crash_reporter.php @@ -103,8 +103,10 @@ exec("/bin/cat /tmp/PHP_errors.log", $php_errors); if (count($php_errors) > 0) { $crash_reports .= "\nPHP Errors:\n"; $crash_reports .= implode("\n", $php_errors) . "\n\n"; + } else { + $crash_reports .= "\nNo PHP errors found.\n"; } - if (is_array($crash_files)) { + if (count($crash_files) > 0) { foreach ($crash_files as $cf) { if (filesize($cf) < FILE_SIZE) { $crash_reports .= "\nFilename: {$cf}\n"; @@ -112,7 +114,7 @@ exec("/bin/cat /tmp/PHP_errors.log", $php_errors); } } } else { - echo gettext("Could not locate any crash data."); + $crash_reports .= "\nNo FreeBSD crash data found.\n"; } ?>
diff --git a/src/usr/local/www/css/pfSense-BETA.css b/src/usr/local/www/css/pfSense-BETA.css index 455060185e..dbf35a4e8f 100644 --- a/src/usr/local/www/css/pfSense-BETA.css +++ b/src/usr/local/www/css/pfSense-BETA.css @@ -86,3 +86,10 @@ a.fa, i.fa { .ui-widget { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; } + +/** This style adds a gray outline around unchecked checkboxes to +make them more visible. Unfortunately the exact alignment of those +outlines varies considerably with browser/OS **/ +input[type="checkbox"]:not(:checked) { + outline: 1px solid #888888; +} diff --git a/src/usr/local/www/css/pfSense.css b/src/usr/local/www/css/pfSense.css index 6cf09454d8..6c43c248d5 100644 --- a/src/usr/local/www/css/pfSense.css +++ b/src/usr/local/www/css/pfSense.css @@ -70,7 +70,7 @@ h1 a:hover, h1 a:active { } /* Zero-width optional linebreaks can help the browser to linebreak at 'good' places. - Unfortunately the two most compatible options aren't consistently supported. + Unfortunately the two most compatible options aren't consistently supported. "\00200B" or #8203; is part of unicode and widely implemented; and is widely supported even on old browsers but not IE<5.5 and IE>7. http://stackoverflow.com/a/23759279/2238378 suggests a neat "80%" solution for broad diff --git a/src/usr/local/www/diag_reboot.php b/src/usr/local/www/diag_reboot.php index 8b6229eb1c..8052e40746 100644 --- a/src/usr/local/www/diag_reboot.php +++ b/src/usr/local/www/diag_reboot.php @@ -43,8 +43,8 @@ $guiretry = 20; // Seconds to try again if $guitimeout was not long enough $pgtitle = array(gettext("Diagnostics"), gettext("Reboot")); include("head.inc"); - -if (($_SERVER['REQUEST_METHOD'] == 'POST') && ($_POST['override'] != "yes")) { +if (($_SERVER['REQUEST_METHOD'] == 'POST') && (empty($_POST['override']) || + ($_POST['override'] != "yes"))): if (DEBUG) { print_info_box(gettext("Not actually rebooting (DEBUG is set true)."), 'success'); } else { @@ -98,7 +98,7 @@ events.push(function() { //]]> @@ -135,6 +135,6 @@ events.push(function() { true) { - $savemsg = get_std_save_message($retval); - $class = "success"; - } else { - $savemsg = $retval; - $class = "danger"; - } if ($retval == 0) { clear_subsystem_dirty('aliases'); } @@ -99,8 +92,7 @@ if ($_GET['act'] == "del") { // Static routes find_alias_reference(array('staticroutes', 'route'), array('network'), $alias_name, $is_alias_referenced, $referenced_by); if ($is_alias_referenced == true) { - $savemsg = sprintf(gettext("Cannot delete alias. Currently in use by %s."), htmlspecialchars($referenced_by)); - $class = "danger"; + $delete_error = sprintf(gettext("Cannot delete alias. Currently in use by %s."), htmlspecialchars($referenced_by)); } else { if (preg_match("/urltable/i", $a_aliases[$_GET['id']]['type'])) { // this is a URL table type alias, delete its file as well @@ -173,8 +165,11 @@ $shortcut_section = "aliases"; include("head.inc"); -if ($savemsg) { - print_info_box($savemsg, $class); +if ($delete_error) { + print_info_box($delete_error, 'danger'); +} +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('aliases')) { diff --git a/src/usr/local/www/firewall_nat.php b/src/usr/local/www/firewall_nat.php index 3fd7c36212..681c98149e 100644 --- a/src/usr/local/www/firewall_nat.php +++ b/src/usr/local/www/firewall_nat.php @@ -86,7 +86,6 @@ if ($_POST) { $retval = 0; $retval |= filter_configure(); - $savemsg = get_std_save_message($retval); pfSense_handle_custom_code("/usr/local/pkg/firewall_nat/apply"); @@ -186,8 +185,8 @@ if (isset($_POST['del_x'])) { $pgtitle = array(gettext("Firewall"), gettext("NAT"), gettext("Port Forward")); include("head.inc"); -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('natconf')) { diff --git a/src/usr/local/www/firewall_nat_1to1.php b/src/usr/local/www/firewall_nat_1to1.php index 5ae075bf52..87f9169873 100644 --- a/src/usr/local/www/firewall_nat_1to1.php +++ b/src/usr/local/www/firewall_nat_1to1.php @@ -68,7 +68,6 @@ if ($_POST) { if ($_POST['apply']) { $retval = 0; $retval |= filter_configure(); - $savemsg = get_std_save_message($retval); if ($retval == 0) { clear_subsystem_dirty('natconf'); @@ -122,8 +121,8 @@ if (isset($_POST['del_x'])) { $pgtitle = array(gettext("Firewall"), gettext("NAT"), gettext("1:1")); include("head.inc"); -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('natconf')) { diff --git a/src/usr/local/www/firewall_nat_npt.php b/src/usr/local/www/firewall_nat_npt.php index b585d99acf..e2d785694f 100644 --- a/src/usr/local/www/firewall_nat_npt.php +++ b/src/usr/local/www/firewall_nat_npt.php @@ -69,7 +69,6 @@ if ($_POST) { if ($_POST['apply']) { $retval = 0; $retval |= filter_configure(); - $savemsg = get_std_save_message($retval); if ($retval == 0) { clear_subsystem_dirty('natconf'); @@ -122,8 +121,8 @@ if (isset($_POST['del_x'])) { $pgtitle = array(gettext("Firewall"), gettext("NAT"), gettext("NPt")); include("head.inc"); -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('natconf')) { diff --git a/src/usr/local/www/firewall_nat_out.php b/src/usr/local/www/firewall_nat_out.php index 6915780e62..a09988c54d 100644 --- a/src/usr/local/www/firewall_nat_out.php +++ b/src/usr/local/www/firewall_nat_out.php @@ -82,12 +82,6 @@ if ($_POST['apply']) { $retval = 0; $retval |= filter_configure(); - if (stristr($retval, "error") <> true) { - $savemsg = get_std_save_message($retval); - } else { - $savemsg = $retval; - } - if ($retval == 0) { clear_subsystem_dirty('natconf'); clear_subsystem_dirty('filter'); @@ -139,7 +133,7 @@ if ($_POST['save']) { } } } - $savemsg = gettext("Default rules for each interface have been created."); + $default_rules_msg = gettext("Default rules for each interface have been created."); unset($FilterIflist, $GatewaysList); } @@ -206,8 +200,12 @@ if (isset($_POST['del_x'])) { $pgtitle = array(gettext("Firewall"), gettext("NAT"), gettext("Outbound")); include("head.inc"); -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($default_rules_msg) { + print_info_box($default_rules_msg, 'success'); +} + +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('natconf')) { diff --git a/src/usr/local/www/firewall_rules_edit.php b/src/usr/local/www/firewall_rules_edit.php index 9e72d9cfa8..f280691729 100644 --- a/src/usr/local/www/firewall_rules_edit.php +++ b/src/usr/local/www/firewall_rules_edit.php @@ -1245,7 +1245,7 @@ if ($if == "FloatingRules" || isset($pconfig['floating'])) { ) )); - $section->addInput(new Form_Input( + $form->addGlobal(new Form_Input( 'floating', 'Floating', 'hidden', diff --git a/src/usr/local/www/firewall_shaper.php b/src/usr/local/www/firewall_shaper.php index 82410ccd4b..ef50e8bb3b 100644 --- a/src/usr/local/www/firewall_shaper.php +++ b/src/usr/local/www/firewall_shaper.php @@ -121,19 +121,11 @@ if ($_GET) { } if (write_config()) { + $changes_applied = true; $retval = 0; $retval |= filter_configure(); - - if (stristr($retval, "error") <> true) { - $savemsg = get_std_save_message($retval); - $class = 'success'; - } else { - $savemsg = $retval; - $class = 'warning'; - } } else { - $savemsg = gettext("Unable to write config.xml (Access Denied?)."); - $class = 'warning'; + $no_write_config_msg = gettext("Unable to write config.xml (Access Denied?)."); } $dfltmsg = true; @@ -280,17 +272,9 @@ if ($_POST) { } } else if ($_POST['apply']) { write_config(); - + $changes_applied = true; $retval = 0; - $retval = filter_configure(); - - if (stristr($retval, "error") <> true) { - $savemsg = get_std_save_message($retval); - $class = 'success'; - } else { - $savemsg = $retval; - $class = 'warning'; - } + $retval |= filter_configure(); /* reset rrd queues */ system("rm -f /var/db/rrd/*queuedrops.rrd"); @@ -369,8 +353,12 @@ if ($input_errors) { print_input_errors($input_errors); } -if ($savemsg) { - print_info_box($savemsg, $class); +if ($no_write_config_msg) { + print_info_box($no_write_config_msg, 'danger'); +} + +if ($changes_applied) { + print_apply_result_box($retval); } if (is_subsystem_dirty('shaper')) { @@ -452,7 +440,7 @@ if (!$dfltmsg && $sform) {
- +
diff --git a/src/usr/local/www/firewall_shaper_queues.php b/src/usr/local/www/firewall_shaper_queues.php index 0bdb99e5a2..a25c47006c 100644 --- a/src/usr/local/www/firewall_shaper_queues.php +++ b/src/usr/local/www/firewall_shaper_queues.php @@ -167,15 +167,7 @@ if ($_POST['apply']) { $retval = 0; /* Setup pf rules since the user may have changed the optimization value */ - $retval = filter_configure(); - $savemsg = get_std_save_message($retval); - if (stristr($retval, "error") <> true) { - $savemsg = get_std_save_message($retval); - $class = 'alert-success'; - } else { - $savemsg = $retval; - $class = 'alert-danger'; - } + $retval |= filter_configure(); /* reset rrd queues */ system("rm -f /var/db/rrd/*queuedrops.rrd"); @@ -198,8 +190,8 @@ if ($input_errors) { print_input_errors($input_errors); } -if ($savemsg) { - print_info_box($savemsg, $class); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('shaper')) { @@ -231,7 +223,7 @@ display_top_tabs($tab_array);
- +
diff --git a/src/usr/local/www/firewall_shaper_vinterface.php b/src/usr/local/www/firewall_shaper_vinterface.php index 74526e9a14..5de573f4b4 100644 --- a/src/usr/local/www/firewall_shaper_vinterface.php +++ b/src/usr/local/www/firewall_shaper_vinterface.php @@ -134,20 +134,11 @@ if ($_GET) { } } if (write_config()) { + $changes_applied = true; $retval = 0; - $retval = filter_configure(); - - if (stristr($retval, "error") != true) { - $savemsg = get_std_save_message($retval); - $class = 'success'; - } else { - $savemsg = $retval; - $class = 'danger'; - } - + $retval |= filter_configure(); } else { - $savemsg = gettext("Unable to write config.xml (Access Denied?)."); - $class = 'danger'; + $no_write_config_msg = gettext("Unable to write config.xml (Access Denied?)."); } $dfltmsg = true; @@ -271,16 +262,9 @@ if ($_POST) { } else if ($_POST['apply']) { write_config(); + $changes_applied = true; $retval = 0; - $retval = filter_configure(); - - if (stristr($retval, "error") != true) { - $savemsg = get_std_save_message($retval); - $class = 'success'; - } else { - $savemsg = $retval; - $class = 'danger'; - } + $retval |= filter_configure(); /* XXX: TODO Make dummynet pretty graphs */ // enable_rrd_graphing(); @@ -369,8 +353,12 @@ if ($input_errors) { print_input_errors($input_errors); } -if ($savemsg) { - print_info_box($savemsg, $class); +if ($no_write_config_msg) { + print_info_box($no_write_config_msg, 'danger'); +} + +if ($changes_applied) { + print_apply_result_box($retval); } if (is_subsystem_dirty('shaper')) { diff --git a/src/usr/local/www/firewall_shaper_wizards.php b/src/usr/local/www/firewall_shaper_wizards.php index 594ed63e57..b9d647e128 100644 --- a/src/usr/local/www/firewall_shaper_wizards.php +++ b/src/usr/local/www/firewall_shaper_wizards.php @@ -42,14 +42,7 @@ if ($_POST['apply']) { $retval = 0; /* Setup pf rules since the user may have changed the optimization value */ - $retval = filter_configure(); - if (stristr($retval, "error") <> true) { - $savemsg = get_std_save_message($retval); - $class = 'success'; - } else { - $savemsg = $retval; - $class = 'warning'; - } + $retval |= filter_configure(); /* reset rrd queues */ unlink_if_exists("/var/db/rrd/*queuedrops.rrd"); @@ -82,8 +75,8 @@ $tab_array[] = array(gettext("Limiters"), false, "firewall_shaper_vinterface.php $tab_array[] = array(gettext("Wizards"), true, "firewall_shaper_wizards.php"); display_top_tabs($tab_array); -if ($savemsg) { - print_info_box($savemsg, $class); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('shaper')) { diff --git a/src/usr/local/www/firewall_virtual_ip.php b/src/usr/local/www/firewall_virtual_ip.php index 33a1f4f074..a15a60b9fb 100644 --- a/src/usr/local/www/firewall_virtual_ip.php +++ b/src/usr/local/www/firewall_virtual_ip.php @@ -79,7 +79,6 @@ if ($_POST) { $retval = 0; $retval |= filter_configure(); - $savemsg = get_std_save_message($retval); clear_subsystem_dirty('vip'); } @@ -240,8 +239,8 @@ include("head.inc"); if ($input_errors) { print_input_errors($input_errors); -} else if ($savemsg) { - print_info_box($savemsg, 'success'); +} else if ($_POST['apply']) { + print_apply_result_box($retval); } else if (is_subsystem_dirty('vip')) { print_apply_box(gettext("The VIP configuration has been changed.") . "
" . gettext("The changes must be applied for them to take effect.")); } diff --git a/src/usr/local/www/guiconfig.inc b/src/usr/local/www/guiconfig.inc index d4fc383d60..c9e78dcf5d 100644 --- a/src/usr/local/www/guiconfig.inc +++ b/src/usr/local/www/guiconfig.inc @@ -323,6 +323,27 @@ function print_apply_box($msg) { print_info_box($msg, "warning", "apply", gettext("Apply Changes"), 'fa-check', 'success'); } +// Format and print a box reporting that changes have been applied +// $retval = status value from the functions called to apply the changes +// 0 is good +// non-zero is a problem +// $extra_text = optional extra text to display after the standard message +function print_apply_result_box($retval, $extra_text="") { + $result_msg = get_std_save_message($retval); + if ($retval === 0) { + // 0 is success + $severity = "success"; + } else { + // non-zero means there was some problem + $severity = "warning"; + } + + if (strlen($extra_text) > 0) { + $result_msg .= " " . $extra_text; + } + print_info_box($result_msg, $severity); +} + /* * Print Bootstrap callout * @@ -350,10 +371,16 @@ function print_callout($msg, $class = 'info', $heading = '') { echo $callout; } -function get_std_save_message($ok) { +function get_std_save_message($retval) { $filter_related = false; $filter_pages = array("nat", "filter"); - $to_return = gettext("The changes have been applied successfully."); + if ($retval === 0) { + // 0 is success + $to_return = gettext("The changes have been applied successfully."); + } else { + // non-zero means there was some problem + $to_return = gettext("There was a problem applying the changes. See the System Logs."); + } foreach ($filter_pages as $fp) { if (stristr($_SERVER['SCRIPT_FILENAME'], $fp)) { $filter_related = true; @@ -508,7 +535,7 @@ function genhtmltitle($title) { $bc = ""; } - return $heading . $bc; + return $bc; } /* update the changedesc and changecount(er) variables */ diff --git a/src/usr/local/www/head.inc b/src/usr/local/www/head.inc index 24bf835a3b..6205772a0e 100644 --- a/src/usr/local/www/head.inc +++ b/src/usr/local/www/head.inc @@ -425,7 +425,7 @@ $allow_clear_notices = false; if (are_notices_pending()) { // Evaluate user privs to determine if notices should be displayed, and if the user can clear them. $user_entry = getUserEntry($_SESSION['Username']); - if (userHasPrivilege($user_entry, "user-view-clear-notices") || userHasPrivilege($user_entry, "page-all")) { + if (isAdminUID($_SESSION['Username']) || userHasPrivilege($user_entry, "user-view-clear-notices") || userHasPrivilege($user_entry, "page-all")) { $display_notices = true; $allow_clear_notices = true; } elseif (userHasPrivilege($user_entry, "user-view-notices")) { diff --git a/src/usr/local/www/interfaces.php b/src/usr/local/www/interfaces.php index a63144d7b9..8391461b0c 100755 --- a/src/usr/local/www/interfaces.php +++ b/src/usr/local/www/interfaces.php @@ -407,11 +407,14 @@ if (isset($wancfg['wireless'])) { } +$changes_applied = false; + if ($_POST['apply']) { unset($input_errors); if (!is_subsystem_dirty('interfaces')) { $input_errors[] = gettext("The settings have already been applied!"); } else { + $retval = 0; unlink_if_exists("{$g['tmp_path']}/config.cache"); clear_subsystem_dirty('interfaces'); @@ -440,24 +443,24 @@ if ($_POST['apply']) { } } /* restart snmp so that it binds to correct address */ - services_snmpd_configure(); + $retval |= services_snmpd_configure(); /* sync filter configuration */ setup_gateways_monitor(); clear_subsystem_dirty('interfaces'); - filter_configure(); + $retval |= filter_configure(); enable_rrd_graphing(); + $changes_applied = true; + if (is_subsystem_dirty('staticroutes') && (system_routing_configure() == 0)) { clear_subsystem_dirty('staticroutes'); } } @unlink("{$g['tmp_path']}/.interfaces.apply"); - header("Location: interfaces.php?if={$if}"); - exit; } else if ($_POST) { unset($input_errors); @@ -1611,7 +1614,7 @@ function check_wireless_mode() { if (!interface_wireless_clone("{$wlanif}_", $wancfg)) { $input_errors[] = sprintf(gettext("Unable to change mode to %s. The maximum number of wireless clones supported in this mode may have been reached."), $wlan_modes[$wancfg['wireless']['mode']]); } else { - mwexec("/sbin/ifconfig " . escapeshellarg($wlanif) . "_ destroy"); + pfSense_interface_destroy("{$wlanif}_"); } $wancfg['wireless']['mode'] = $old_wireless_mode; } @@ -1695,11 +1698,10 @@ if (is_subsystem_dirty('interfaces')) { gettext("Don't forget to adjust the DHCP Server range if needed after applying.")); } -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($changes_applied) { + print_apply_result_box($retval); } - $form = new Form(); $section = new Form_Section('General Configuration'); diff --git a/src/usr/local/www/interfaces_assign.php b/src/usr/local/www/interfaces_assign.php index b647feaab4..26b7a88fa1 100644 --- a/src/usr/local/www/interfaces_assign.php +++ b/src/usr/local/www/interfaces_assign.php @@ -244,7 +244,7 @@ if (isset($_POST['add']) && isset($_POST['if_add'])) { write_config(); - $savemsg = gettext("Interface has been added."); + $action_msg = gettext("Interface has been added."); $class = "success"; } @@ -255,15 +255,9 @@ if (isset($_POST['add']) && isset($_POST['if_add'])) { } else { write_config(); - $retval = filter_configure(); - - if (stristr($retval, "error") <> true) { - $savemsg = get_std_save_message($retval); - $class = "success"; - } else { - $savemsg = $retval; - $class = "danger"; - } + $changes_applied = true; + $retval = 0; + $retval |= filter_configure(); } } else if (isset($_POST['Submit'])) { @@ -438,7 +432,7 @@ if (isset($_POST['add']) && isset($_POST['if_add'])) { link_interface_to_vlans($realid, "update"); - $savemsg = gettext("Interface has been deleted."); + $action_msg = gettext("Interface has been deleted."); $class = "success"; } } @@ -464,14 +458,14 @@ include("head.inc"); if (file_exists("/var/run/interface_mismatch_reboot_needed")) { if ($_POST) { if ($rebootingnow) { - $savemsg = gettext("The system is now rebooting. Please wait."); + $action_msg = gettext("The system is now rebooting. Please wait."); $class = "success"; } else { $applymsg = gettext("Reboot is needed. Please apply the settings in order to reboot."); $class = "warning"; } } else { - $savemsg = gettext("Interface mismatch detected. Please resolve the mismatch, save and then click 'Apply Changes'. The firewall will reboot afterwards."); + $action_msg = gettext("Interface mismatch detected. Please resolve the mismatch, save and then click 'Apply Changes'. The firewall will reboot afterwards."); $class = "warning"; } } @@ -482,8 +476,10 @@ if (file_exists("/tmp/reload_interfaces")) { echo "

\n"; } elseif ($applymsg) { print_apply_box($applymsg); -} elseif ($savemsg) { - print_info_box($savemsg, $class); +} elseif ($action_msg) { + print_info_box($action_msg, $class); +} elseif ($changes_applied) { + print_apply_result_box($retval); } pfSense_handle_custom_code("/usr/local/pkg/interfaces_assign/pre_input_errors"); diff --git a/src/usr/local/www/interfaces_bridge.php b/src/usr/local/www/interfaces_bridge.php index c9631d76f7..359af1c93c 100644 --- a/src/usr/local/www/interfaces_bridge.php +++ b/src/usr/local/www/interfaces_bridge.php @@ -60,7 +60,7 @@ if ($_GET['act'] == "del") { if (!does_interface_exist($a_bridges[$_GET['id']]['bridgeif'])) { log_error("Bridge interface does not exist, skipping ifconfig destroy."); } else { - mwexec("/sbin/ifconfig " . $a_bridges[$_GET['id']]['bridgeif'] . " destroy"); + pfSense_interface_destroy($a_bridges[$_GET['id']]['bridgeif']); } unset($a_bridges[$_GET['id']]); diff --git a/src/usr/local/www/interfaces_gif.php b/src/usr/local/www/interfaces_gif.php index 1797092b69..b0581ec15f 100644 --- a/src/usr/local/www/interfaces_gif.php +++ b/src/usr/local/www/interfaces_gif.php @@ -56,7 +56,7 @@ if ($_GET['act'] == "del") { } else if (gif_inuse($_GET['id'])) { $input_errors[] = gettext("This gif TUNNEL cannot be deleted because it is still being used as an interface."); } else { - mwexec("/sbin/ifconfig " . $a_gifs[$_GET['id']]['gifif'] . " destroy"); + pfSense_interface_destroy($a_gifs[$_GET['id']]['gifif']); unset($a_gifs[$_GET['id']]); write_config(); diff --git a/src/usr/local/www/interfaces_gre.php b/src/usr/local/www/interfaces_gre.php index a69edd62aa..9f2d8c0849 100644 --- a/src/usr/local/www/interfaces_gre.php +++ b/src/usr/local/www/interfaces_gre.php @@ -57,7 +57,7 @@ if ($_GET['act'] == "del") { } else if (gre_inuse($_GET['id'])) { $input_errors[] = gettext("This GRE tunnel cannot be deleted because it is still being used as an interface."); } else { - mwexec("/sbin/ifconfig " . $a_gres[$_GET['id']]['greif'] . " destroy"); + pfSense_interface_destroy($a_gres[$_GET['id']]['greif']); unset($a_gres[$_GET['id']]); write_config(); diff --git a/src/usr/local/www/interfaces_lagg.php b/src/usr/local/www/interfaces_lagg.php index c521558abc..23deb7d36b 100644 --- a/src/usr/local/www/interfaces_lagg.php +++ b/src/usr/local/www/interfaces_lagg.php @@ -63,7 +63,7 @@ if ($_GET['act'] == "del") { } else if (lagg_inuse($_GET['id'])) { $input_errors[] = gettext("This LAGG interface cannot be deleted because it is still being used."); } else { - mwexec_bg("/sbin/ifconfig " . $a_laggs[$_GET['id']]['laggif'] . " destroy"); + pfSense_interface_destroy($a_laggs[$_GET['id']]['laggif']); unset($a_laggs[$_GET['id']]); write_config(); diff --git a/src/usr/local/www/interfaces_qinq.php b/src/usr/local/www/interfaces_qinq.php index 63fa1b4c13..1997c19f79 100644 --- a/src/usr/local/www/interfaces_qinq.php +++ b/src/usr/local/www/interfaces_qinq.php @@ -67,7 +67,7 @@ if ($_GET['act'] == "del") { } mwexec("/usr/sbin/ngctl shutdown {$qinq['vlanif']}qinq:"); mwexec("/usr/sbin/ngctl shutdown {$qinq['vlanif']}:"); - mwexec("/sbin/ifconfig {$qinq['vlanif']} destroy"); + pfSense_interface_destroy($qinq['vlanif']); unset($a_qinqs[$id]); write_config(); diff --git a/src/usr/local/www/interfaces_wireless.php b/src/usr/local/www/interfaces_wireless.php index dafe49da65..304eca2a4c 100644 --- a/src/usr/local/www/interfaces_wireless.php +++ b/src/usr/local/www/interfaces_wireless.php @@ -57,7 +57,7 @@ if ($_GET['act'] == "del") { if (clone_inuse($_GET['id'])) { $input_errors[] = gettext("This wireless clone cannot be deleted because it is assigned as an interface."); } else { - mwexec("/sbin/ifconfig " . $a_clones[$_GET['id']]['cloneif'] . " destroy"); + pfSense_interface_destroy($a_clones[$_GET['id']]['cloneif']); unset($a_clones[$_GET['id']]); write_config(); diff --git a/src/usr/local/www/interfaces_wireless_edit.php b/src/usr/local/www/interfaces_wireless_edit.php index 419f9c683d..d30b5c433f 100644 --- a/src/usr/local/www/interfaces_wireless_edit.php +++ b/src/usr/local/www/interfaces_wireless_edit.php @@ -125,7 +125,7 @@ if ($_POST) { } else { if (isset($id) && $a_clones[$id]) { if ($clone['if'] != $a_clones[$id]['if']) { - mwexec("/sbin/ifconfig " . $a_clones[$id]['cloneif'] . " destroy"); + pfSense_interface_destroy($a_clones[$id]['cloneif']); } $input_errors[] = sprintf(gettext("Created with id %s"), $id); $a_clones[$id] = $clone; diff --git a/src/usr/local/www/js/pfSense.js b/src/usr/local/www/js/pfSense.js index da33129db6..2a6bc168ab 100644 --- a/src/usr/local/www/js/pfSense.js +++ b/src/usr/local/www/js/pfSense.js @@ -143,7 +143,7 @@ $(function() { // Use element title in the confirmation message, or if not available // the element value $('.btn-danger, .fa-trash').on('click', function(e){ - if (!($(this).hasClass('no-confirm'))) { + if (!($(this).hasClass('no-confirm')) && !($(this).hasClass('icon-embed-btn'))) { var msg = $.trim(this.textContent).toLowerCase(); if (!msg) @@ -230,7 +230,7 @@ $(function() { $('.table-rowdblclickedit>tbody>tr').dblclick(function () { $(this).find(".fa-pencil")[0].click(); }); - + // Focus first input $(':input:enabled:visible:first').focus(); @@ -238,7 +238,7 @@ $(function() { $(this).css('height', 80).resizable({minHeight: 80, minWidth: 200}).parent().css('padding-bottom', 0); $(this).css('height', 78); }); - + // Run in-page defined events while (func = window.events.shift()) func(); diff --git a/src/usr/local/www/js/pfSenseHelpers.js b/src/usr/local/www/js/pfSenseHelpers.js index b77ec1ffc1..2eac30a58c 100644 --- a/src/usr/local/www/js/pfSenseHelpers.js +++ b/src/usr/local/www/js/pfSenseHelpers.js @@ -353,9 +353,9 @@ function add_row() { $('[id^=delete]').click(function(event) { if ($('.repeatable').length > 1) { if ((typeof retainhelp) == "undefined") - moveHelpText(event.target.id); + moveHelpText($(this).attr("id")); - delete_row(event.target.id); + delete_row($(this).attr("id")); } else { alert('The last row may not be deleted.'); } @@ -375,9 +375,9 @@ $('[id^=addrow]').click(function() { $('[id^=delete]').click(function(event) { if ($('.repeatable').length > 1) { if ((typeof retainhelp) == "undefined") - moveHelpText(event.target.id); + moveHelpText($(this).attr("id")); - delete_row(event.target.id); + delete_row($(this).attr("id")); } else { alert('The last row may not be deleted.'); } diff --git a/src/usr/local/www/load_balancer_monitor.php b/src/usr/local/www/load_balancer_monitor.php index a6875cabfa..f85f972811 100644 --- a/src/usr/local/www/load_balancer_monitor.php +++ b/src/usr/local/www/load_balancer_monitor.php @@ -43,7 +43,6 @@ if ($_POST) { $retval |= filter_configure(); $retval |= relayd_configure(); - $savemsg = get_std_save_message($retval); clear_subsystem_dirty('loadbalancer'); } } @@ -79,8 +78,8 @@ if ($input_errors) { print_input_errors($input_errors); } -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('loadbalancer')) { diff --git a/src/usr/local/www/load_balancer_pool.php b/src/usr/local/www/load_balancer_pool.php index d9788cd919..48b33eede7 100644 --- a/src/usr/local/www/load_balancer_pool.php +++ b/src/usr/local/www/load_balancer_pool.php @@ -47,7 +47,6 @@ if ($_POST) { $retval |= filter_configure(); $retval |= relayd_configure(); - $savemsg = get_std_save_message($retval); clear_subsystem_dirty('loadbalancer'); } } @@ -93,8 +92,8 @@ if ($input_errors) { print_input_errors($input_errors); } -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('loadbalancer')) { diff --git a/src/usr/local/www/load_balancer_setting.php b/src/usr/local/www/load_balancer_setting.php index 9ae4a951c5..a8470c3ef9 100644 --- a/src/usr/local/www/load_balancer_setting.php +++ b/src/usr/local/www/load_balancer_setting.php @@ -46,7 +46,6 @@ if ($_POST) { $retval |= filter_configure(); $retval |= relayd_configure(); - $savemsg = get_std_save_message($retval); clear_subsystem_dirty('loadbalancer'); } else { unset($input_errors); @@ -92,8 +91,8 @@ if ($input_errors) { print_input_errors($input_errors); } -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('loadbalancer')) { diff --git a/src/usr/local/www/load_balancer_virtual_server.php b/src/usr/local/www/load_balancer_virtual_server.php index f07c7acb87..808220360f 100644 --- a/src/usr/local/www/load_balancer_virtual_server.php +++ b/src/usr/local/www/load_balancer_virtual_server.php @@ -45,7 +45,6 @@ if ($_POST) { $retval = 0; $retval |= filter_configure(); $retval |= relayd_configure(); - $savemsg = get_std_save_message($retval); /* Wipe out old relayd anchors no longer in use. */ cleanup_lb_marked(); clear_subsystem_dirty('loadbalancer'); @@ -113,8 +112,8 @@ if ($input_errors) { print_input_errors($input_errors); } -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (is_subsystem_dirty('loadbalancer')) { diff --git a/src/usr/local/www/pkg_edit.php b/src/usr/local/www/pkg_edit.php index bfb4514506..ba8815d99d 100644 --- a/src/usr/local/www/pkg_edit.php +++ b/src/usr/local/www/pkg_edit.php @@ -1500,6 +1500,10 @@ if ($pkg['custom_php_after_form_command']) { eval($pkg['custom_php_after_form_command']); } + +$hidemsg = gettext("Show Advanced Options"); +$showmsg = gettext("Hide Advanced Options"); + if ($pkg['fields']['field'] != "") { ?> " . gettext("The changes must be applied for them to take effect.")); diff --git a/src/usr/local/www/vpn_ipsec_settings.php b/src/usr/local/www/vpn_ipsec_settings.php index 43608375a9..9e21937a69 100644 --- a/src/usr/local/www/vpn_ipsec_settings.php +++ b/src/usr/local/www/vpn_ipsec_settings.php @@ -33,16 +33,7 @@ require_once("shaper.inc"); require_once("ipsec.inc"); require_once("vpn.inc"); -$def_loglevel = '1'; - -foreach (array_keys($ipsec_log_cats) as $cat) { - if (isset($config['ipsec']['logging'][$cat])) { - $pconfig[$cat] = $config['ipsec']['logging'][$cat]; - } else { - $pconfig[$cat] = $def_loglevel; - } -} - +$pconfig['logging'] = ipsec_get_loglevels(); $pconfig['unityplugin'] = isset($config['ipsec']['unityplugin']); $pconfig['strictcrlpolicy'] = isset($config['ipsec']['strictcrlpolicy']); $pconfig['makebeforebreak'] = isset($config['ipsec']['makebeforebreak']); @@ -59,8 +50,10 @@ if ($_POST) { $pconfig = $_POST; foreach ($ipsec_log_cats as $cat => $desc) { - if (!in_array(intval($pconfig[$cat]), array_keys($ipsec_log_sevs), true)) { + if (!in_array(intval($pconfig['logging_' . $cat]), array_keys($ipsec_log_sevs), true)) { $input_errors[] = sprintf(gettext("A valid value must be specified for %s debug."), $desc); + } else { + $pconfig['logging'][$cat] = $pconfig['logging_' . $cat]; } } @@ -79,12 +72,12 @@ if ($_POST) { * get set when we save, even if it's to the default level. */ foreach (array_keys($ipsec_log_cats) as $cat) { - if (!isset($pconfig[$cat])) { + if (!isset($pconfig['logging'][$cat])) { continue; } - if ($pconfig[$cat] != $config['ipsec']['logging'][$cat]) { - $config['ipsec']['logging'][$cat] = $pconfig[$cat]; - vpn_update_daemon_loglevel($cat, $pconfig[$cat]); + if ($pconfig['logging'][$cat] != $config['ipsec']['logging'][$cat]) { + $config['ipsec']['logging'][$cat] = $pconfig['logging'][$cat]; + vpn_update_daemon_loglevel($cat, $pconfig['logging'][$cat]); } } @@ -172,20 +165,11 @@ if ($_POST) { write_config(); + $changes_applied = true; $retval = 0; - $retval = filter_configure(); - if (stristr($retval, "error") <> true) { - $savemsg = get_std_save_message(gettext($retval)); - $class = 'success'; - } else { - $savemsg = gettext($retval); - $class = 'warning'; - } + $retval |= filter_configure(); vpn_ipsec_configure($needsrestart); - - header("Location: vpn_ipsec_settings.php"); - return; } // The logic value sent by $POST for autoexcludelanaddress is opposite to @@ -220,8 +204,8 @@ function maxmss_checked(obj) { $desc) { $section->addInput(new Form_Select( - $cat, + 'logging_' . $cat, $desc, - $pconfig[$cat], + $pconfig['logging'][$cat], $ipsec_log_sevs ))->setWidth(2); } diff --git a/src/usr/local/www/vpn_l2tp.php b/src/usr/local/www/vpn_l2tp.php index 1adf21b742..29cddc1bca 100644 --- a/src/usr/local/www/vpn_l2tp.php +++ b/src/usr/local/www/vpn_l2tp.php @@ -159,14 +159,9 @@ if ($_POST) { write_config(); + $changes_applied = true; $retval = 0; - $retval = vpn_l2tp_configure(); - $savemsg = get_std_save_message($retval); - - /* if ajax is calling, give them an update message */ - if (isAjax()) { - print_info_box($savemsg, 'success'); - } + $retval |= vpn_l2tp_configure(); } } @@ -178,8 +173,8 @@ if ($input_errors) { print_input_errors($input_errors); } -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($changes_applied) { + print_apply_result_box($retval); } $tab_array = array(); diff --git a/src/usr/local/www/vpn_l2tp_users.php b/src/usr/local/www/vpn_l2tp_users.php index 3bfaec16fd..4c31eb8269 100644 --- a/src/usr/local/www/vpn_l2tp_users.php +++ b/src/usr/local/www/vpn_l2tp_users.php @@ -44,9 +44,8 @@ if ($_POST) { if ($_POST['apply']) { $retval = 0; if (!is_subsystem_dirty('rebootreq')) { - $retval = vpn_l2tp_configure(); + $retval |= vpn_l2tp_configure(); } - $savemsg = get_std_save_message($retval); if ($retval == 0) { if (is_subsystem_dirty('l2tpusers')) { clear_subsystem_dirty('l2tpusers'); @@ -67,8 +66,8 @@ if ($_GET['act'] == "del") { include("head.inc"); -if ($savemsg) { - print_info_box($savemsg, 'success'); +if ($_POST['apply']) { + print_apply_result_box($retval); } if (isset($config['l2tp']['radius']['enable'])) { diff --git a/src/usr/local/www/vpn_openvpn_client.php b/src/usr/local/www/vpn_openvpn_client.php index 399d099fda..e3bc9f1d7c 100644 --- a/src/usr/local/www/vpn_openvpn_client.php +++ b/src/usr/local/www/vpn_openvpn_client.php @@ -31,7 +31,7 @@ require_once("guiconfig.inc"); require_once("openvpn.inc"); require_once("pkg-utils.inc"); -global $openvpn_topologies; +global $openvpn_topologies, $openvpn_tls_modes; if (!is_array($config['openvpn']['openvpn-client'])) { $config['openvpn']['openvpn-client'] = array(); @@ -90,6 +90,8 @@ if ($_GET['act'] == "del") { } if ($_GET['act'] == "new") { + $pconfig['ncp_enable'] = "enabled"; + $pconfig['ncp-ciphers'] = "AES-256-GCM,AES-128-GCM"; $pconfig['autokey_enable'] = "yes"; $pconfig['tlsauth_enable'] = "yes"; $pconfig['autotls_enable'] = "yes"; @@ -129,6 +131,16 @@ if ($_GET['act'] == "edit") { $pconfig['description'] = $a_client[$id]['description']; $pconfig['custom_options'] = $a_client[$id]['custom_options']; $pconfig['ns_cert_type'] = $a_client[$id]['ns_cert_type']; + if (isset($a_client[$id]['ncp-ciphers'])) { + $pconfig['ncp-ciphers'] = $a_client[$id]['ncp-ciphers']; + } else { + $pconfig['ncp-ciphers'] = "AES-256-GCM,AES-128-GCM"; + } + if (isset($a_client[$id]['ncp_enable'])) { + $pconfig['ncp_enable'] = $a_client[$id]['ncp_enable']; + } else { + $pconfig['ncp_enable'] = "enabled"; + } $pconfig['dev_mode'] = $a_client[$id]['dev_mode']; if ($pconfig['mode'] != "p2p_shared_key") { @@ -137,6 +149,7 @@ if ($_GET['act'] == "edit") { if ($a_client[$id]['tls']) { $pconfig['tlsauth_enable'] = "yes"; $pconfig['tls'] = base64_decode($a_client[$id]['tls']); + $pconfig['tls_type'] = $a_client[$id]['tls_type']; } } else { $pconfig['shared_key'] = base64_decode($a_client[$id]['shared_key']); @@ -180,6 +193,11 @@ if ($_POST) { $vpnid = 0; } + $cipher_validation_list = array_keys(openvpn_get_cipherlist()); + if (!in_array($pconfig['crypto'], $cipher_validation_list)) { + $input_errors[] = gettext("The selected Encryption Algorithm is not valid."); + } + list($iv_iface, $iv_ip) = explode ("|", $pconfig['interface']); if (is_ipaddrv4($iv_ip) && (stristr($pconfig['protocol'], "6") !== false)) { $input_errors[] = gettext("Protocol and IP address families do not match. An IPv6 protocol and an IPv4 IP address cannot be selected."); @@ -289,12 +307,26 @@ if ($_POST) { if ($tls_mode && $pconfig['tlsauth_enable'] && !$pconfig['autotls_enable']) { if (!strstr($pconfig['tls'], "-----BEGIN OpenVPN Static key V1-----") || !strstr($pconfig['tls'], "-----END OpenVPN Static key V1-----")) { - $input_errors[] = gettext("The field 'TLS Authentication Key' does not appear to be valid"); + $input_errors[] = gettext("The field 'TLS Key' does not appear to be valid"); } + if (!in_array($pconfig['tls_type'], array_keys($openvpn_tls_modes))) { + $input_errors[] = gettext("The field 'TLS Key Usage Mode' is not valid"); + } + } + + if (($pconfig['mode'] == "p2p_shared_key") && strstr($pconfig['crypto'], "GCM")) { + $input_errors[] = gettext("GCM Encryption Algorithms cannot be used with Shared Key mode."); } /* If we are not in shared key mode, then we need the CA/Cert. */ if ($pconfig['mode'] != "p2p_shared_key") { + if (($pconfig['ncp_enable'] != "disabled") && !empty($pconfig['ncp-ciphers']) && is_array($pconfig['ncp-ciphers'])) { + foreach ($pconfig['ncp-ciphers'] as $ncpc) { + if (!in_array(trim($ncpc), $cipher_validation_list)) { + $input_errors[] = gettext("One or more of the selected NCP Algorithms is not valid."); + } + } + } $reqdfields = explode(" ", "caref"); $reqdfieldsn = array(gettext("Certificate Authority")); } elseif (!$pconfig['autokey_enable']) { @@ -317,6 +349,15 @@ if ($_POST) { $client = array(); + if (isset($id) && $a_client[$id] && + $pconfig['dev_mode'] <> $a_client[$id]['dev_mode']) { + /* + * delete old interface so a new TUN or TAP interface + * can be created. + */ + openvpn_delete('client', $a_client[$id]); + } + foreach ($simplefields as $stat) { if (($stat == 'auth_pass') && ($_POST[$stat] == DMYPWD)) { $client[$stat] = $a_client[$id]['auth_pass']; @@ -361,6 +402,7 @@ if ($_POST) { $pconfig['tls'] = openvpn_create_key(); } $client['tls'] = base64_encode($pconfig['tls']); + $client['tls_type'] = $pconfig['tls_type']; } } else { $client['shared_key'] = base64_encode($pconfig['shared_key']); @@ -381,6 +423,12 @@ if ($_POST) { $client['route_no_exec'] = $pconfig['route_no_exec']; $client['verbosity_level'] = $pconfig['verbosity_level']; + if (!empty($pconfig['ncp-ciphers'])) { + $client['ncp-ciphers'] = implode(",", $pconfig['ncp-ciphers']); + } + + $client['ncp_enable'] = $pconfig['ncp_enable'] ? "enabled":"disabled"; + if (isset($id) && $a_client[$id]) { $a_client[$id] = $client; } else { @@ -393,6 +441,10 @@ if ($_POST) { header("Location: vpn_openvpn_client.php"); exit; } + + if (!empty($pconfig['ncp-ciphers'])) { + $pconfig['ncp-ciphers'] = implode(",", $pconfig['ncp-ciphers']); + } } $pgtitle = array(gettext("VPN"), gettext("OpenVPN"), gettext("Clients")); @@ -447,22 +499,23 @@ if ($act=="new" || $act=="edit"): 'protocol', 'Protocol', $pconfig['protocol'], - array_combine($openvpn_prots, $openvpn_prots) + $openvpn_prots )); $section->addInput(new Form_Select( 'dev_mode', 'Device mode', empty($pconfig['dev_mode']) ? 'tun':$pconfig['dev_mode'], - array_combine($openvpn_dev_mode, $openvpn_dev_mode) - )); + $openvpn_dev_mode + ))->setHelp("\"tun\" mode carries IPv4 and IPv6 (OSI layer 3) and is the most common and compatible mode across all platforms." . + "
\"tap\" mode is capable of carrying 802.3 (OSI Layer 2.)"); $section->addInput(new Form_Select( 'interface', 'Interface', $pconfig['interface'], openvpn_build_if_list() - )); + ))->setHelp("The interface used by the firewall to originate this OpenVPN client connection"); $section->addInput(new Form_Input( 'local_port', @@ -477,21 +530,30 @@ if ($act=="new" || $act=="edit"): 'Server host or address', 'text', $pconfig['server_addr'] - )); + ))->setHelp("The IP address or hostname of the OpenVPN server."); + + $section->addInput(new Form_Checkbox( + 'resolve_retry', + 'Server hostname resolution', + 'Infinitely resolve server ', + $pconfig['resolve_retry'] + ))->setHelp('Continuously attempt to resolve the server host name. ' . + 'Useful when communicating with a server that is not permanently connected to the Internet.'); $section->addInput(new Form_Input( 'server_port', 'Server port', 'number', $pconfig['server_port'] - )); + ))->setHelp("The port used by the server to receive client connections."); $section->addInput(new Form_Input( 'proxy_addr', 'Proxy host or address', 'text', $pconfig['proxy_addr'] - )); + ))->setHelp("The address for an HTTP Proxy this client can use to connect to a remote server." . + "
TCP must be used for the client and server protocol."); $section->addInput(new Form_Input( 'proxy_port', @@ -502,10 +564,10 @@ if ($act=="new" || $act=="edit"): $section->addInput(new Form_Select( 'proxy_authtype', - 'Proxy Auth. - Extra options', + 'Proxy Authentication', $pconfig['proxy_authtype'], array('none' => gettext('none'), 'basic' => gettext('basic'), 'ntlm' => gettext('ntlm')) - )); + ))->setHelp("The type of authentication used by the proxy server."); $section->addInput(new Form_Input( 'proxy_user', @@ -521,14 +583,6 @@ if ($act=="new" || $act=="edit"): $pconfig['proxy_passwd'] )); - $section->addInput(new Form_Checkbox( - 'resolve_retry', - 'Server hostname resolution', - 'Infinitely resolve server ', - $pconfig['resolve_retry'] - ))->setHelp('Continuously attempt to resolve the server host name. ' . - 'Useful when communicating with a server that is not permanently connected to the Internet.'); - $section->addInput(new Form_Input( 'description', 'Description', @@ -560,25 +614,38 @@ if ($act=="new" || $act=="edit"): $section->addInput(new Form_Checkbox( 'tlsauth_enable', - 'TLS authentication', - 'Enable authentication of TLS packets.', + 'TLS Configuration', + 'Use a TLS Key', $pconfig['tlsauth_enable'] - )); + ))->setHelp("A TLS key enhances security of an OpenVPN connection by requiring both parties to have a common key before a peer can perform a TLS handshake. " . + "This layer of HMAC authentication allows control channel packets without the proper key to be dropped, protecting the peers from attack or unauthorized connections." . + "The TLS Key does not have any effect on tunnel data."); if (!$pconfig['tls']) { $section->addInput(new Form_Checkbox( 'autotls_enable', null, - 'Automatically generate a shared TLS authentication key.', + 'Automatically generate a TLS Key.', $pconfig['autotls_enable'] )); } $section->addInput(new Form_Textarea( 'tls', - 'Key', + 'TLS Key', $pconfig['tls'] - ))->setHelp('Paste the shared key here'); + ))->setHelp("Paste the TLS key here." . + "
" . + "This key is used to sign control channel packets with an HMAC signature for authentication when establishing the tunnel. "); + + $section->addInput(new Form_Select( + 'tls_type', + 'TLS Key Usage Mode', + empty($pconfig['tls_type']) ? 'auth':$pconfig['tls_type'], + $openvpn_tls_modes + ))->setHelp("In Authentication mode the TLS key is used only as HMAC authentication for the control channel, protecting the peers from unauthorized connections. " . + "
" . + "Encryption and Authentication mode also encrypts control channel communication, providing more privacy and traffic control channel obfuscation."); if (count($a_ca)) { $list = array(); @@ -640,14 +707,60 @@ if ($act=="new" || $act=="edit"): 'Encryption Algorithm', $pconfig['crypto'], openvpn_get_cipherlist() - )); + ))->setHelp('The Encryption Algorithm used for data channel packets when Negotiable Cryptographic Parameter (NCP) support is not available.'); + + $section->addInput(new Form_Checkbox( + 'ncp_enable', + 'Enable NCP', + 'Enable Negotiable Cryptographic Parameters', + ($pconfig['ncp_enable'] == "enabled") + ))->setHelp( 'Check this option to allow OpenVPN clients and servers to negotiate a compatible set of acceptable cryptographic ' . + 'Encryption Algorithms from those selected in the NCP Algorithms list below.' . + '
' . sprint_info_box('When both peers support NCP and have it enabled, NCP overrides the Encryption Algorithm above.' . '
' . + 'When disabled, only the selected Encryption Algorithm is allowed.', 'info', false) . '
'); + + foreach (explode(",", $pconfig['ncp-ciphers']) as $cipher) { + $ncp_ciphers_list[$cipher] = $cipher; + } + $group = new Form_Group('NCP Algorithms'); + + $group->add(new Form_Select( + 'availciphers', + null, + array(), + openvpn_get_cipherlist(), + true + ))->setAttribute('size', '10') + ->setHelp('Available NCP Encryption Algorithms
Click to add or remove an algorithm from the list'); + + $group->add(new Form_Select( + 'ncp-ciphers', + null, + array(), + $ncp_ciphers_list, + true + ))->setReadonly() + ->setAttribute('size', '10') + ->setHelp('Allowed NCP Encryption Algorithms. Click an algorithm name to remove it from the list'); + + $group->setHelp( 'The order of the selected NCP Encryption Algorithms is respected by OpenVPN.' . + '
' . sprint_info_box( + 'For backward compatibility, when an older peer connects that does not support NCP, OpenVPN will use the Encryption Algorithm ' . + 'requested by the peer so long as it is selected in this list or chosen as the Encryption Algorithm.', 'info', false) . + '
'); + + $section->add($group); $section->addInput(new Form_Select( 'digest', 'Auth digest algorithm', $pconfig['digest'], openvpn_get_digestlist() - ))->setHelp('Leave this set to SHA1 unless all clients are set to match. SHA1 is the default for OpenVPN. '); + ))->setHelp('The algorithm used to authenticate data channel packets, and control channel packets if a TLS Key is present.' . + '
' . + 'When an AEAD Encryption Algorithm mode is used, such as AES-GCM, this digest is used for the control channel only, not the data channel.' . + '
' . + 'Leave this set to SHA1 unless the server uses a different value. SHA1 is the default for OpenVPN. '); $section->addInput(new Form_Select( 'engine', @@ -768,7 +881,7 @@ if ($act=="new" || $act=="edit"): $act )); - if (isset($id) && $a_server[$id]) { + if (isset($id) && $a_client[$id]) { $section->addInput(new Form_Input( 'id', null, @@ -896,6 +1009,7 @@ events.push(function() { // Process "Automatically generate a shared TLS authentication key" checkbox function autotls_change() { hideInput('tls', $('#autotls_enable').prop('checked') || !$('#tlsauth_enable').prop('checked')); + hideInput('tls_type', $('#autotls_enable').prop('checked') || !$('#tlsauth_enable').prop('checked')); } // ---------- Monitor elements for change and call the appropriate display functions ------------------------------ @@ -930,6 +1044,45 @@ events.push(function() { autotls_change(); }); + function updateCiphers(mem) { + var found = false; + + // If the cipher exists, remove it + $('[id="ncp-ciphers[]"] option').each(function() { + if($(this).val() == mem) { + $(this).remove(); + found = true; + } + }); + + // If not, add it + if (!found) { + $('[id="ncp-ciphers[]"]').append(new Option(mem , mem)); + } + + // Unselect all options + $('[id="availciphers[]"] option:selected').removeAttr("selected"); + } + + // On click, update the ciphers list + $('[id="availciphers[]"]').click(function () { + updateCiphers($(this).val()); + }); + + // On click, remove the cipher from the list + $('[id="ncp-ciphers[]"]').click(function () { + if ($(this).val() != null) { + updateCiphers($(this).val()); + } + }); + + // Make sure the "Available ciphers" selector is not submitted with the form, + // and select all of the chosen ciphers so that they are submitted + $('form').submit(function() { + $("#availciphers" ).prop( "disabled", true); + $('[id="ncp-ciphers[]"] option').attr("selected", "selected"); + }); + // ---------- Set initial page display state ---------------------------------------------------------------------- mode_change(); autokey_change(); diff --git a/src/usr/local/www/vpn_openvpn_csc.php b/src/usr/local/www/vpn_openvpn_csc.php index 16ba076f0c..65932c2a99 100644 --- a/src/usr/local/www/vpn_openvpn_csc.php +++ b/src/usr/local/www/vpn_openvpn_csc.php @@ -74,6 +74,7 @@ if ($_GET['act'] == "edit") { $pconfig['description'] = $a_csc[$id]['description']; $pconfig['tunnel_network'] = $a_csc[$id]['tunnel_network']; + $pconfig['tunnel_networkv6'] = $a_csc[$id]['tunnel_networkv6']; $pconfig['local_network'] = $a_csc[$id]['local_network']; $pconfig['local_networkv6'] = $a_csc[$id]['local_networkv6']; $pconfig['remote_network'] = $a_csc[$id]['remote_network']; @@ -132,7 +133,10 @@ if ($_POST) { $pconfig = $_POST; /* input validation */ - if ($result = openvpn_validate_cidr($pconfig['tunnel_network'], 'Tunnel network')) { + if ($result = openvpn_validate_cidr($pconfig['tunnel_network'], 'IPv4 Tunnel Network')) { + $input_errors[] = $result; + } + if ($result = openvpn_validate_cidr($pconfig['tunnel_networkv6'], 'IPv6 Tunnel Network', false, "ipv6")) { $input_errors[] = $result; } @@ -219,6 +223,7 @@ if ($_POST) { $csc['block'] = $pconfig['block']; $csc['description'] = $pconfig['description']; $csc['tunnel_network'] = $pconfig['tunnel_network']; + $csc['tunnel_networkv6'] = $pconfig['tunnel_networkv6']; $csc['local_network'] = $pconfig['local_network']; $csc['local_networkv6'] = $pconfig['local_networkv6']; $csc['remote_network'] = $pconfig['remote_network']; @@ -320,7 +325,7 @@ if ($act == "new" || $act == "edit"): $pconfig['server_list'], $serveroptionlist, true - ))->setHelp('Select the servers for which the override will apply. Selecting no servers will also apply the override to all servers.'); + ))->setHelp('Select the servers that will utilize this override. When no servers are selected, the override will apply to all servers.'); $section->addInput(new Form_Checkbox( @@ -332,24 +337,24 @@ if ($act == "new" || $act == "edit"): $section->addInput(new Form_Input( 'common_name', - 'Common name', + 'Common Name', 'text', $pconfig['common_name'] - ))->setHelp('Enter the client\'s X.509 common name.'); + ))->setHelp('Enter the X.509 common name for the client certificate, or the username for VPNs utilizing password authentication. This match is case sensitive.'); $section->addInput(new Form_Input( 'description', 'Description', 'text', $pconfig['description'] - ))->setHelp('A description may be entered here for administrative reference (not parsed). '); + ))->setHelp('A description for administrative reference (not parsed).'); $section->addInput(new Form_Checkbox( 'block', 'Connection blocking', - 'Block this client connection based on its common name. ', + 'Block this client connection based on its common name.', $pconfig['block'] - ))->setHelp('Don\'t use this option to permanently disable a client due to a compromised key or password. Use a CRL (certificate revocation list) instead. '); + ))->setHelp('Prevents the client from connecting to this server. Do not use this option to permanently disable a client due to a compromised key or password. Use a CRL (certificate revocation list) instead.'); $form->add($section); @@ -357,45 +362,57 @@ if ($act == "new" || $act == "edit"): $section->addInput(new Form_Input( 'tunnel_network', - 'Tunnel Network', + 'IPv4 Tunnel Network', 'text', $pconfig['tunnel_network'] - ))->setHelp('This is the virtual network used for private communications between this client and the server expressed using CIDR (e.g. 10.0.8.0/24). ' . - 'The first network address is assumed to be the server address and the second network address will be assigned to the client virtual interface. '); + ))->setHelp('The virtual IPv4 network used for private communications between this client and the server expressed using CIDR (e.g. 10.0.8.5/24). ' . + '
' . + 'With subnet topology, enter the client IP address and the subnet mask must match the IPv4 Tunnel Network on the server. ' . + '
' . + 'With net30 topology, the first network address of the /30 is assumed to be the server address and the second network address will be assigned to the client.'); + + $section->addInput(new Form_Input( + 'tunnel_networkv6', + 'IPv6 Tunnel Network', + 'text', + $pconfig['tunnel_networkv6'] + ))->setHelp('The virtual IPv6 network used for private communications between this client and the server expressed using prefix (e.g. 2001:db9:1:1::100/64). ' . + '
' . + 'Enter the client IPv6 address and prefix. The prefix must match the IPv6 Tunnel Network prefix on the server. '); $section->addInput(new Form_Input( 'local_network', 'IPv4 Local Network/s', 'text', $pconfig['local_network'] - ))->setHelp('These are the IPv4 networks that will be accessible from this particular client. Expressed as a comma-separated list of one or more CIDR ranges. ' . '
' . - 'NOTE: Networks do not need to be specified here if they have already been defined on the main server configuration.'); + ))->setHelp('These are the IPv4 server-side networks that will be accessible from this particular client. Expressed as a comma-separated list of one or more CIDR networks. ' . '
' . + 'NOTE: Networks do not need to be specified here if they have already been defined on the main server configuration.'); $section->addInput(new Form_Input( 'local_networkv6', 'IPv6 Local Network/s', 'text', $pconfig['local_networkv6'] - ))->setHelp('These are the IPv4 networks that will be accessible from this particular client. Expressed as a comma-separated list of one or more IP/PREFIX networks.' . '
' . - 'NOTE: Networks do not need to be specified here if they have already been defined on the main server configuration.'); + ))->setHelp('These are the IPv6 server-side networks that will be accessible from this particular client. Expressed as a comma-separated list of one or more IP/PREFIX networks.' . '
' . + 'NOTE: Networks do not need to be specified here if they have already been defined on the main server configuration.'); $section->addInput(new Form_Input( 'remote_network', 'IPv4 Remote Network/s', 'text', $pconfig['remote_network'] - ))->setHelp('These are the IPv4 networks that will be routed to this client specifically using iroute, so that a site-to-site VPN can be established. ' . - 'Expressed as a comma-separated list of one or more CIDR ranges. May be left blank if there are no client-side networks to be routed.' . '
' . - 'NOTE: Remember to add these subnets to the IPv4 Remote Networks list on the corresponding OpenVPN server settings.'); + ))->setHelp('These are the IPv4 client-side networks that will be routed to this client specifically using iroute, so that a site-to-site VPN can be established. ' . + 'Expressed as a comma-separated list of one or more CIDR ranges. May be left blank if there are no client-side networks to be routed.' . '
' . + 'NOTE: Remember to add these subnets to the IPv4 Remote Networks list on the corresponding OpenVPN server settings.'); $section->addInput(new Form_Input( 'remote_networkv6', 'IPv6 Remote Network/s', 'text', $pconfig['remote_networkv6'] - ))->setHelp('These are the IPv6 networks that will be routed to this client specifically using iroute, so that a site-to-site VPN can be established. ' . - 'Expressed as a comma-separated list of one or more IP/PREFIX networks. May be left blank if there are no client-side networks to be routed.' . '
' . - 'NOTE: Remember to add these subnets to the IPv6 Remote Networks list on the corresponding OpenVPN server settings.'); + ))->setHelp('These are the IPv6 client-side networks that will be routed to this client specifically using iroute, so that a site-to-site VPN can be established. ' . + 'Expressed as a comma-separated list of one or more IP/PREFIX networks. May be left blank if there are no client-side networks to be routed.' . '
' . + 'NOTE: Remember to add these subnets to the IPv6 Remote Networks list on the corresponding OpenVPN server settings.'); $section->addInput(new Form_Checkbox( 'gwredir', diff --git a/src/usr/local/www/vpn_openvpn_server.php b/src/usr/local/www/vpn_openvpn_server.php index 433b689b17..efd3b26508 100644 --- a/src/usr/local/www/vpn_openvpn_server.php +++ b/src/usr/local/www/vpn_openvpn_server.php @@ -31,7 +31,7 @@ require_once("guiconfig.inc"); require_once("openvpn.inc"); require_once("pkg-utils.inc"); -global $openvpn_topologies; +global $openvpn_topologies, $openvpn_tls_modes; if (!is_array($config['openvpn']['openvpn-server'])) { $config['openvpn']['openvpn-server'] = array(); @@ -96,6 +96,8 @@ if ($_GET['act'] == "del") { } if ($_GET['act'] == "new") { + $pconfig['ncp_enable'] = "enabled"; + $pconfig['ncp-ciphers'] = "AES-256-GCM,AES-128-GCM"; $pconfig['autokey_enable'] = "yes"; $pconfig['tlsauth_enable'] = "yes"; $pconfig['autotls_enable'] = "yes"; @@ -117,6 +119,16 @@ if ($_GET['act'] == "edit") { $pconfig['mode'] = $a_server[$id]['mode']; $pconfig['protocol'] = $a_server[$id]['protocol']; $pconfig['authmode'] = $a_server[$id]['authmode']; + if (isset($a_server[$id]['ncp-ciphers'])) { + $pconfig['ncp-ciphers'] = $a_server[$id]['ncp-ciphers']; + } else { + $pconfig['ncp-ciphers'] = "AES-256-GCM,AES-128-GCM"; + } + if (isset($a_server[$id]['ncp_enable'])) { + $pconfig['ncp_enable'] = $a_server[$id]['ncp_enable']; + } else { + $pconfig['ncp_enable'] = "enabled"; + } $pconfig['dev_mode'] = $a_server[$id]['dev_mode']; $pconfig['interface'] = $a_server[$id]['interface']; @@ -132,6 +144,7 @@ if ($_GET['act'] == "edit") { if ($a_server[$id]['tls']) { $pconfig['tlsauth_enable'] = "yes"; $pconfig['tls'] = base64_decode($a_server[$id]['tls']); + $pconfig['tls_type'] = $a_server[$id]['tls_type']; } $pconfig['caref'] = $a_server[$id]['caref']; @@ -165,6 +178,7 @@ if ($_GET['act'] == "edit") { $pconfig['local_networkv6'] = $a_server[$id]['local_networkv6']; $pconfig['maxclients'] = $a_server[$id]['maxclients']; $pconfig['compression'] = $a_server[$id]['compression']; + $pconfig['compression_push'] = $a_server[$id]['compression_push']; $pconfig['passtos'] = $a_server[$id]['passtos']; $pconfig['client2client'] = $a_server[$id]['client2client']; @@ -240,8 +254,8 @@ if ($_GET['act'] == "edit") { $pconfig['push_register_dns'] = $a_server[$id]['push_register_dns']; } } -if ($_POST) { +if ($_POST) { unset($input_errors); $pconfig = $_POST; @@ -251,6 +265,11 @@ if ($_POST) { $vpnid = 0; } + $cipher_validation_list = array_keys(openvpn_get_cipherlist()); + if (!in_array($pconfig['crypto'], $cipher_validation_list)) { + $input_errors[] = gettext("The selected Encryption Algorithm is not valid."); + } + list($iv_iface, $iv_ip) = explode ("|", $pconfig['interface']); if (is_ipaddrv4($iv_ip) && (stristr($pconfig['protocol'], "6") !== false)) { $input_errors[] = gettext("Protocol and IP address families do not match. An IPv6 protocol and an IPv4 IP address cannot be selected."); @@ -328,7 +347,10 @@ if ($_POST) { if ($tls_mode && $pconfig['tlsauth_enable'] && !$pconfig['autotls_enable']) { if (!strstr($pconfig['tls'], "-----BEGIN OpenVPN Static key V1-----") || !strstr($pconfig['tls'], "-----END OpenVPN Static key V1-----")) { - $input_errors[] = gettext("The field 'TLS Authentication Key' does not appear to be valid"); + $input_errors[] = gettext("The field 'TLS Key' does not appear to be valid"); + } + if (!in_array($pconfig['tls_type'], array_keys($openvpn_tls_modes))) { + $input_errors[] = gettext("The field 'TLS Key Usage Mode' is not valid"); } } @@ -406,6 +428,14 @@ if ($_POST) { $input_errors[] = gettext("The specified ECDH Curve is invalid."); } + if (($pconfig['ncp_enable'] != "disabled") && !empty($pconfig['ncp-ciphers']) && is_array($pconfig['ncp-ciphers'])) { + foreach ($pconfig['ncp-ciphers'] as $ncpc) { + if (!in_array(trim($ncpc), $cipher_validation_list)) { + $input_errors[] = gettext("One or more of the selected NCP Algorithms is not valid."); + } + } + } + $reqdfields = explode(" ", "caref certref"); $reqdfieldsn = array(gettext("Certificate Authority"), gettext("Certificate")); } elseif (!$pconfig['autokey_enable']) { @@ -414,6 +444,10 @@ if ($_POST) { $reqdfieldsn = array(gettext('Shared key')); } + if (($pconfig['mode'] == "p2p_shared_key") && strstr($pconfig['crypto'], "GCM")) { + $input_errors[] = gettext("GCM Encryption Algorithms cannot be used with Shared Key mode."); + } + if ($pconfig['dev_mode'] != "tap") { $reqdfields[] = 'tunnel_network'; $reqdfieldsn[] = gettext('Tunnel network'); @@ -435,14 +469,20 @@ if ($_POST) { $input_errors[] = gettext("The Server Bridge DHCP range is invalid (start higher than end)."); } } + do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors); if (!$input_errors) { $server = array(); - if ($id && $pconfig['dev_mode'] <> $a_server[$id]['dev_mode']) { - openvpn_delete('server', $a_server[$id]);// delete(rename) old interface so a new TUN or TAP interface can be created. + if (isset($id) && $a_server[$id] && + $pconfig['dev_mode'] <> $a_server[$id]['dev_mode']) { + /* + * delete old interface so a new TUN or TAP interface + * can be created. + */ + openvpn_delete('server', $a_server[$id]); } if ($vpnid) { @@ -471,6 +511,7 @@ if ($_POST) { $pconfig['tls'] = openvpn_create_key(); } $server['tls'] = base64_encode($pconfig['tls']); + $server['tls_type'] = $pconfig['tls_type']; } $server['caref'] = $pconfig['caref']; $server['crlref'] = $pconfig['crlref']; @@ -498,6 +539,7 @@ if ($_POST) { $server['local_networkv6'] = $pconfig['local_networkv6']; $server['maxclients'] = $pconfig['maxclients']; $server['compression'] = $pconfig['compression']; + $server['compression_push'] = $pconfig['compression_push']; $server['passtos'] = $pconfig['passtos']; $server['client2client'] = $pconfig['client2client']; @@ -559,6 +601,12 @@ if ($_POST) { $server['duplicate_cn'] = true; } + if (!empty($pconfig['ncp-ciphers'])) { + $server['ncp-ciphers'] = implode(",", $pconfig['ncp-ciphers']); + } + + $server['ncp_enable'] = $pconfig['ncp_enable'] ? "enabled":"disabled"; + if (isset($id) && $a_server[$id]) { $a_server[$id] = $server; } else { @@ -572,6 +620,11 @@ if ($_POST) { header("Location: vpn_openvpn_server.php"); exit; } + + if (!empty($pconfig['ncp-ciphers'])) { + $pconfig['ncp-ciphers'] = implode(",", $pconfig['ncp-ciphers']); + } + if (!empty($pconfig['authmode'])) { $pconfig['authmode'] = implode(",", $pconfig['authmode']); } @@ -629,9 +682,14 @@ if ($act=="new" || $act=="edit"): $options = array(); $authmodes = array(); - $authmodes = explode(",", $pconfig['authmode']); + $auth_servers = auth_get_authserver_list(); + + foreach (explode(",", $pconfig['ncp-ciphers']) as $cipher) { + $ncp_ciphers_list[$cipher] = $cipher; + } + // If no authmodes set then default to selecting the first entry in auth_servers if (empty($authmodes[0]) && !empty(key($auth_servers))) { $authmodes[0] = key($auth_servers); @@ -660,15 +718,16 @@ if ($act=="new" || $act=="edit"): 'dev_mode', 'Device mode', empty($pconfig['dev_mode']) ? 'tun':$pconfig['dev_mode'], - array_combine($openvpn_dev_mode, $openvpn_dev_mode) - )); + $openvpn_dev_mode + ))->setHelp("\"tun\" mode carries IPv4 and IPv6 (OSI layer 3) and is the most common and compatible mode across all platforms." . + "
\"tap\" mode is capable of carrying 802.3 (OSI Layer 2.)"); $section->addInput(new Form_Select( 'interface', 'Interface', $pconfig['interface'], openvpn_build_if_list() - )); + ))->setHelp("The interface or Virtual IP address where OpenVPN will receive client connections."); $section->addInput(new Form_Input( 'local_port', @@ -676,7 +735,7 @@ if ($act=="new" || $act=="edit"): 'number', $pconfig['local_port'], ['min' => '0'] - )); + ))->setHelp("The port used by OpenVPN to receive client connections."); $section->addInput(new Form_Input( 'description', @@ -691,25 +750,38 @@ if ($act=="new" || $act=="edit"): $section->addInput(new Form_Checkbox( 'tlsauth_enable', - 'TLS authentication', - 'Enable authentication of TLS packets.', + 'TLS Configuration', + 'Use a TLS Key', $pconfig['tlsauth_enable'] - )); + ))->setHelp("A TLS key enhances security of an OpenVPN connection by requiring both parties to have a common key before a peer can perform a TLS handshake. " . + "This layer of HMAC authentication allows control channel packets without the proper key to be dropped, protecting the peers from attack or unauthorized connections." . + "The TLS Key does not have any effect on tunnel data."); if (!$pconfig['tls']) { $section->addInput(new Form_Checkbox( 'autotls_enable', null, - 'Automatically generate a shared TLS authentication key.', + 'Automatically generate a TLS Key.', $pconfig['autotls_enable'] )); } $section->addInput(new Form_Textarea( 'tls', - 'Key', + 'TLS Key', $pconfig['tls'] - ))->setHelp('Paste the shared key here'); + ))->setHelp("Paste the TLS key here." . + "
" . + "This key is used to sign control channel packets with an HMAC signature for authentication when establishing the tunnel. "); + + $section->addInput(new Form_Select( + 'tls_type', + 'TLS Key Usage Mode', + empty($pconfig['tls_type']) ? 'auth':$pconfig['tls_type'], + $openvpn_tls_modes + ))->setHelp("In Authentication mode the TLS key is used only as HMAC authentication for the control channel, protecting the peers from unauthorized connections. " . + "
" . + "Encryption and Authentication mode also encrypts control channel communication, providing more privacy and traffic control channel obfuscation."); if (count($a_ca)) { @@ -775,14 +847,24 @@ if ($act=="new" || $act=="edit"): 'DH Parameter Length', $pconfig['dh_length'], $openvpn_dh_lengths - ))->setHelp(count($a_cert) ? '':sprintf('No Certificates defined. One may be created here: %s', 'System > Cert. Manager')); + ))->setHelp('Diffie-Hellman (DH) parameter set used for key exchange.' . + '
' . + sprint_info_box('Only DH parameter sets which exist in /etc/ are shown. ' . + '
' . + 'Generating new or stronger DH parameters is CPU-intensive and must be performed manually. ' . + 'Consult the doc wiki article on DH Parameters ' . + 'for information on generating new or stronger paramater sets.', 'info', false) . + '
'); $section->addInput(new Form_Select( 'ecdh_curve', 'ECDH Curve', $pconfig['ecdh_curve'], openvpn_get_curvelist() - )); + ))->setHelp('The Elliptic Curve to use for key exchange. ' . + '
' . + 'The curve from the server certificate is used by default when the server uses an ECDSA certificate. ' . + 'Otherwise, secp384r1 is used as a fallback.'); if (!$pconfig['shared_key']) { $section->addInput(new Form_Checkbox( @@ -804,14 +886,57 @@ if ($act=="new" || $act=="edit"): 'Encryption Algorithm', $pconfig['crypto'], openvpn_get_cipherlist() - )); + ))->setHelp('The Encryption Algorithm used for data channel packets when Negotiable Cryptographic Parameter (NCP) support is not available.'); + + $section->addInput(new Form_Checkbox( + 'ncp_enable', + 'Enable NCP', + 'Enable Negotiable Cryptographic Parameters', + ($pconfig['ncp_enable'] == "enabled") + ))->setHelp( 'Check this option to allow OpenVPN clients and servers to negotiate a compatible set of acceptable cryptographic ' . + 'Encryption Algorithms from those selected in the NCP Algorithms list below.' . + '
' . sprint_info_box('When both peers support NCP and have it enabled, NCP overrides the Encryption Algorithm above.' . '
' . + 'When disabled, only the selected Encryption Algorithm is allowed.', 'info', false) . '
'); + + $group = new Form_Group('NCP Algorithms'); + + $group->add(new Form_Select( + 'availciphers', + null, + array(), + openvpn_get_cipherlist(), + true + ))->setAttribute('size', '10') + ->setHelp('Available NCP Encryption Algorithms
Click to add or remove an algorithm from the list'); + + $group->add(new Form_Select( + 'ncp-ciphers', + null, + array(), + $ncp_ciphers_list, + true + ))->setReadonly() + ->setAttribute('size', '10') + ->setHelp('Allowed NCP Encryption Algorithms. Click an algorithm name to remove it from the list'); + + $group->setHelp( 'The order of the selected NCP Encryption Algorithms is respected by OpenVPN.' . + '
' . sprint_info_box( + 'For backward compatibility, when an older peer connects that does not support NCP, OpenVPN will use the Encryption Algorithm ' . + 'requested by the peer so long as it is selected in this list or chosen as the Encryption Algorithm.', 'info', false) . + '
'); + + $section->add($group); $section->addInput(new Form_Select( 'digest', 'Auth digest algorithm', $pconfig['digest'], openvpn_get_digestlist() - ))->setHelp('Leave this set to SHA1 unless all clients are set to match. SHA1 is the default for OpenVPN. '); + ))->setHelp('The algorithm used to authenticate data channel packets, and control channel packets if a TLS Key is present.' . + '
' . + 'When an AEAD Encryption Algorithm mode is used, such as AES-GCM, this digest is used for the control channel only, not the data channel.' . + '
' . + 'Leave this set to SHA1 unless all clients are set to match. SHA1 is the default for OpenVPN. '); $section->addInput(new Form_Select( 'engine', @@ -951,6 +1076,13 @@ if ($act=="new" || $act=="edit"): 'Adaptive compression will dynamically disable compression for a period of time if OpenVPN detects that the data in the ' . 'packets is not being compressed efficiently.'); + $section->addInput(new Form_Checkbox( + 'compression_push', + 'Push Compression', + 'Push the selected Compression setting to connecting clients.', + $pconfig['compression_push'] + )); + $section->addInput(new Form_Checkbox( 'passtos', 'Type-of-Service', @@ -1290,6 +1422,7 @@ events.push(function() { case "server_tls": case "server_user": hideInput('tls', false); + hideInput('tls_type', false); hideInput('certref', false); hideInput('dh_length', false); hideInput('ecdh_curve', false); @@ -1298,9 +1431,11 @@ events.push(function() { hideCheckbox('autokey_enable', true); hideInput('shared_key', false); hideInput('topology', false); + hideCheckbox('compression_push', false); break; case "server_tls_user": hideInput('tls', false); + hideInput('tls_type', false); hideInput('certref', false); hideInput('dh_length', false); hideInput('ecdh_curve', false); @@ -1309,9 +1444,11 @@ events.push(function() { hideCheckbox('autokey_enable', true); hideInput('shared_key', true); hideInput('topology', false); + hideCheckbox('compression_push', false); break; case "p2p_shared_key": hideInput('tls', true); + hideInput('tls_type', true); hideInput('caref', true); hideInput('crlref', true); hideLabel('Peer Certificate Revocation list', true); @@ -1325,6 +1462,7 @@ events.push(function() { hideCheckbox('autokey_enable', true); hideInput('shared_key', false); hideInput('topology', true); + hideCheckbox('compression_push', true); break; } @@ -1394,10 +1532,12 @@ events.push(function() { function autotls_change() { if (($('#mode').val() == 'p2p_shared_key') || (!$('#tlsauth_enable').prop('checked'))) { hideInput('tls', true); + hideInput('tls_type', true); hideInput('autotls_enable', true); } else { hideInput('autotls_enable', false); hideInput('tls', $('#autotls_enable').prop('checked') || !$('#tlsauth_enable').prop('checked')); + hideInput('tls_type', $('#autotls_enable').prop('checked') || !$('#tlsauth_enable').prop('checked')); } } @@ -1617,6 +1757,45 @@ events.push(function() { $('#certtype').html(errmsg); }); + function updateCiphers(mem) { + var found = false; + + // If the cipher exists, remove it + $('[id="ncp-ciphers[]"] option').each(function() { + if($(this).val() == mem) { + $(this).remove(); + found = true; + } + }); + + // If not, add it + if (!found) { + $('[id="ncp-ciphers[]"]').append(new Option(mem , mem)); + } + + // Unselect all options + $('[id="availciphers[]"] option:selected').removeAttr("selected"); + } + + // On click, update the ciphers list + $('[id="availciphers[]"]').click(function () { + updateCiphers($(this).val()); + }); + + // On click, remove the cipher from the list + $('[id="ncp-ciphers[]"]').click(function () { + if ($(this).val() != null) { + updateCiphers($(this).val()); + } + }); + + // Make sure the "Available ciphers" selector is not submitted with the form, + // and select all of the chosen ciphers so that they are submitted + $('form').submit(function() { + $("#availciphers" ).prop( "disabled", true); + $('[id="ncp-ciphers[]"] option').attr("selected", "selected"); + }); + // ---------- Set initial page display state ---------------------------------------------------------------------- mode_change(); autokey_change(); diff --git a/src/usr/local/www/widgets/widgets/gateways.widget.php b/src/usr/local/www/widgets/widgets/gateways.widget.php index 34f4d2e213..c854df5be1 100644 --- a/src/usr/local/www/widgets/widgets/gateways.widget.php +++ b/src/usr/local/www/widgets/widgets/gateways.widget.php @@ -38,12 +38,29 @@ if ($_REQUEST && $_REQUEST['ajax']) { } if ($_POST) { + + if (!is_array($user_settings["widgets"]["gateways_widget"])) { $user_settings["widgets"]["gateways_widget"] = array(); } + if (isset($_POST["display_type"])) { $user_settings["widgets"]["gateways_widget"]["display_type"] = $_POST["display_type"]; } + + if (is_array($_POST['show'])) { + $validNames = array(); + $a_gateways = return_gateways_array(); + + foreach ($a_gateways as $gname => $gateway) { + array_push($validNames, $gname); + } + + $user_settings["widgets"]["gateways_widget"]["gatewaysfilter"] = implode(',', array_diff($validNames, $_POST['show'])); + } else { + $user_settings["widgets"]["gateways_widget"]["gatewaysfilter"] = ""; + } + save_widget_settings($_SESSION['Username'], $user_settings["widgets"], gettext("Updated gateways widget settings via dashboard.")); header("Location: /"); exit(0); @@ -71,55 +88,86 @@ $widgetperiod = isset($config['widgets']['period']) ? $config['widgets']['period
-
- -