diff options
-rwxr-xr-x | config/snort/snort.xml | 2 | ||||
-rwxr-xr-x | config/snort/snort_alerts.php | 21 | ||||
-rw-r--r-- | config/snort/snort_blocked.php | 8 | ||||
-rw-r--r-- | config/snort/snort_ip_reputation.php | 8 | ||||
-rw-r--r-- | config/snort/snort_iprep_list_browser.php | 4 | ||||
-rw-r--r-- | config/squid/squid.inc | 81 | ||||
-rwxr-xr-x | config/squid3/34/squid.inc | 1485 | ||||
-rw-r--r-- | config/squid3/34/squid.xml | 52 | ||||
-rw-r--r-- | config/squid3/34/squid_antivirus.inc | 797 | ||||
-rwxr-xr-x | config/squid3/34/squid_antivirus.xml | 111 | ||||
-rwxr-xr-x | config/squid3/34/squid_auth.xml | 3 | ||||
-rwxr-xr-x | config/squid3/34/squid_cache.xml | 1 | ||||
-rw-r--r-- | config/squid3/34/squid_js.inc | 273 | ||||
-rwxr-xr-x | config/squid3/34/squid_reverse.inc | 71 | ||||
-rwxr-xr-x | config/squid3/34/squid_reverse.xml | 451 | ||||
-rwxr-xr-x | config/squid3/34/squid_reverse_general.xml | 7 | ||||
-rwxr-xr-x | config/squid3/34/squid_traffic.xml | 1 | ||||
-rwxr-xr-x | config/squid3/34/squid_users.xml | 3 | ||||
-rw-r--r-- | pkg_config.10.xml | 4 | ||||
-rw-r--r-- | pkg_config.8.xml | 2 |
20 files changed, 1878 insertions, 1507 deletions
diff --git a/config/snort/snort.xml b/config/snort/snort.xml index 612fbaa8..9d20a4ab 100755 --- a/config/snort/snort.xml +++ b/config/snort/snort.xml @@ -45,7 +45,7 @@ </copyright> <description>Snort IDS/IPS Package</description> <name>Snort</name> - <version>3.2.8.1</version> + <version>3.2.8.2</version> <title>Services: Snort IDS</title> <include_file>/usr/local/pkg/snort/snort.inc</include_file> <menu> diff --git a/config/snort/snort_alerts.php b/config/snort/snort_alerts.php index 3f3159a6..52fe0db3 100755 --- a/config/snort/snort_alerts.php +++ b/config/snort/snort_alerts.php @@ -188,7 +188,7 @@ if (is_array($config['installedpackages']['snortglobal']['alertsblocks'])) { $pconfig['alertnumber'] = $config['installedpackages']['snortglobal']['alertsblocks']['alertnumber']; } -if (empty($pconfig['alertnumber'])) +if (empty($pconfig['alertnumber']) || !is_numeric($pconfig['alertnumber'])) $pconfig['alertnumber'] = '250'; if (empty($pconfig['arefresh'])) $pconfig['arefresh'] = 'off'; @@ -242,12 +242,15 @@ if ($_POST['save']) { if (!is_array($config['installedpackages']['snortglobal']['alertsblocks'])) $config['installedpackages']['snortglobal']['alertsblocks'] = array(); $config['installedpackages']['snortglobal']['alertsblocks']['arefresh'] = $_POST['arefresh'] ? 'on' : 'off'; - $config['installedpackages']['snortglobal']['alertsblocks']['alertnumber'] = $_POST['alertnumber']; - write_config("Snort pkg: updated ALERTS tab settings."); - - header("Location: /snort/snort_alerts.php?instance={$instanceid}"); - exit; + if (is_numeric($_POST['alertnumber'])) { + $config['installedpackages']['snortglobal']['alertsblocks']['alertnumber'] = $_POST['alertnumber']; + write_config("Snort pkg: updated ALERTS tab settings."); + header("Location: /snort/snort_alerts.php?instance={$instanceid}"); + return; + } else { + $input_errors[] = gettext("Alert number must be numeric"); + } } if ($_POST['todelete']) { @@ -582,12 +585,12 @@ if ($savemsg) { </tr> <?php if ($filterlogentries) : ?> <tr> - <td colspan="2" class="listtopic"><?php printf(gettext("Last %s Alert Entries"), $anentries); ?> + <td colspan="2" class="listtopic"><?php printf(gettext("Last %s Alert Entries"), htmlspecialchars($anentries)); ?> <?php echo gettext("(Most recent listed first) ** FILTERED VIEW ** clear filter to see all entries"); ?></td> </tr> <?php else: ?> <tr> - <td colspan="2" class="listtopic"><?php printf(gettext("Last %s Alert Entries"), $anentries); ?> + <td colspan="2" class="listtopic"><?php printf(gettext("Last %s Alert Entries"), htmlspecialchars($anentries)); ?> <?php echo gettext("(Most recent entries are listed first)"); ?></td> </tr> <?php endif; ?> @@ -625,7 +628,7 @@ if ($savemsg) { /* make sure alert file exists */ if (file_exists("{$snortlogdir}/snort_{$if_real}{$snort_uuid}/alert")) { - exec("tail -{$anentries} -r {$snortlogdir}/snort_{$if_real}{$snort_uuid}/alert > {$g['tmp_path']}/alert_{$snort_uuid}"); + exec("tail -n" . escapeshellarg($anentries) . " -r " . escapeshellarg("{$snortlogdir}/snort_{$if_real}{$snort_uuid}/alert") . " > " . escapeshellarg("{$g['tmp_path']}/alert_{$snort_uuid}")); if (file_exists("{$g['tmp_path']}/alert_{$snort_uuid}")) { $tmpblocked = array_flip(snort_get_blocked_ips()); $counter = 0; diff --git a/config/snort/snort_blocked.php b/config/snort/snort_blocked.php index 39119210..055497d9 100644 --- a/config/snort/snort_blocked.php +++ b/config/snort/snort_blocked.php @@ -46,7 +46,7 @@ if (!is_array($config['installedpackages']['snortglobal']['alertsblocks'])) $pconfig['brefresh'] = $config['installedpackages']['snortglobal']['alertsblocks']['brefresh']; $pconfig['blertnumber'] = $config['installedpackages']['snortglobal']['alertsblocks']['blertnumber']; -if (empty($pconfig['blertnumber'])) +if (empty($pconfig['blertnumber']) || !is_numeric($pconfig['blertnumber'])) $bnentries = '500'; else $bnentries = $pconfig['blertnumber']; @@ -130,6 +130,10 @@ if ($_POST['download']) if ($_POST['save']) { + if (!is_numeric($_POST['blertnumber'])) { + $input_errors[] = gettext("Alert number must be numeric"); + } + /* no errors */ if (!$input_errors) { $config['installedpackages']['snortglobal']['alertsblocks']['brefresh'] = $_POST['brefresh'] ? 'on' : 'off'; @@ -219,7 +223,7 @@ if ($savemsg) { </td> </tr> <tr> - <td colspan="2" class="listtopic"><?php printf(gettext("Last %s Hosts Blocked by Snort"), $bnentries); ?></td> + <td colspan="2" class="listtopic"><?php printf(gettext("Last %s Hosts Blocked by Snort"), htmlspecialchars($bnentries)); ?></td> </tr> <tr> <td colspan="2"> diff --git a/config/snort/snort_ip_reputation.php b/config/snort/snort_ip_reputation.php index c190b0e6..58098fe2 100644 --- a/config/snort/snort_ip_reputation.php +++ b/config/snort/snort_ip_reputation.php @@ -78,7 +78,7 @@ if ($_POST['mode'] == 'blist_add' && isset($_POST['iplist'])) { // See if the file is already assigned to the interface foreach ($a_nat[$id]['blist_files']['item'] as $f) { if ($f == basename($_POST['iplist'])) { - $input_errors[] = gettext("The file {$f} is already assigned as a blacklist file."); + $input_errors[] = sprintf(gettext("The file %s is already assigned as a blacklist file."), htmlspecialchars($f)); break; } } @@ -89,7 +89,7 @@ if ($_POST['mode'] == 'blist_add' && isset($_POST['iplist'])) { } } else - $input_errors[] = gettext("The file '{$_POST['iplist']}' could not be found."); + $input_errors[] = sprintf(gettext("The file '%s' could not be found."), htmlspecialchars($_POST['iplist'])); $pconfig['blist_files'] = $a_nat[$id]['blist_files']; $pconfig['wlist_files'] = $a_nat[$id]['wlist_files']; @@ -103,7 +103,7 @@ if ($_POST['mode'] == 'wlist_add' && isset($_POST['iplist'])) { // See if the file is already assigned to the interface foreach ($a_nat[$id]['wlist_files']['item'] as $f) { if ($f == basename($_POST['iplist'])) { - $input_errors[] = gettext("The file {$f} is already assigned as a whitelist file."); + $input_errors[] = sprintf(gettext("The file %s is already assigned as a whitelist file."), htmlspecialchars($f)); break; } } @@ -114,7 +114,7 @@ if ($_POST['mode'] == 'wlist_add' && isset($_POST['iplist'])) { } } else - $input_errors[] = gettext("The file '{$_POST['iplist']}' could not be found."); + $input_errors[] = sprintf(gettext("The file '%s' could not be found."), htmlspecialchars($_POST['iplist'])); $pconfig['blist_files'] = $a_nat[$id]['blist_files']; $pconfig['wlist_files'] = $a_nat[$id]['wlist_files']; diff --git a/config/snort/snort_iprep_list_browser.php b/config/snort/snort_iprep_list_browser.php index a13a2d37..42f1d595 100644 --- a/config/snort/snort_iprep_list_browser.php +++ b/config/snort/snort_iprep_list_browser.php @@ -83,9 +83,9 @@ foreach($files as $file): <td></td> <td class="fbFile vexpl" id="<?=$fqpn;?>" align="left"> <?php $filename = str_replace("//","/", "{$path}/{$file}"); ?> - <div onClick="$('<?=$target;?>').value='<?=$filename?>'; $('<?=$container;?>').hide();"> + <div onClick="$('<?=$target;?>').value='<?=htmlspecialchars($filename)?>'; $('<?=$container;?>').hide();"> <img src="/filebrowser/images/file_<?=$type;?>.gif" alt="" title=""> - <?=$file;?> + <?=htmlspecialchars($file);?> </div> </td> <td align="right" class="vexpl"> diff --git a/config/squid/squid.inc b/config/squid/squid.inc index 4cfb9af8..fc62a587 100644 --- a/config/squid/squid.inc +++ b/config/squid/squid.inc @@ -552,24 +552,75 @@ function squid_install_cron($should_install) { return; } - parse_config(true); + $rotate_is_installed = false; + $swapstate_is_installed = false; + if(!$config['cron']['item']) + return; + $settings = $config['installedpackages']['squidcache']['config'][0]; - if (is_array($config['installedpackages']['squidcache'])) { - $settings = $config['installedpackages']['squidcache']['config'][0]; - } else { - $settings = array(); - } - $cachedir = ($settings['harddisk_cache_location'] ? $settings['harddisk_cache_location'] : '/var/squid/cache'); - $cron_cmd = "/bin/rm {$cachedir}/swap.state; " . SQUID_LOCALBASE . "/sbin/squid -k rotate"; - $swapstate_cmd = "/usr/local/pkg/swapstate_check.php"; + $x=0; + $rotate_job_id=-1; + $swapstate_job_id=-1; - if ($should_install) { - install_cron_job("{$cron_cmd}", true, "0", "0", "*", "*", "*", "root"); - install_cron_job("{$swapstate_cmd}", true, "*/15"); - } else { - install_cron_job("{$cron_cmd}", false); - install_cron_job("{$swapstate_cmd}", false); + foreach($config['cron']['item'] as $item) { + if(strstr($item['task_name'], "squid_rotate_logs")) { + $rotate_job_id = $x; + } elseif(strstr($item['task_name'], "squid_check_swapstate")) { + $swapstate_job_id = $x; + } + $x++; + } + $need_write = false; + switch($should_install) { + case true: + $cachedir =($settings['harddisk_cache_location'] ? $settings['harddisk_cache_location'] : '/var/squid/cache'); + if($rotate_job_id < 0) { + $cron_item = array(); + $cron_item['task_name'] = "squid_rotate_logs"; + $cron_item['minute'] = "0"; + $cron_item['hour'] = "0"; + $cron_item['mday'] = "*"; + $cron_item['month'] = "*"; + $cron_item['wday'] = "*"; + $cron_item['who'] = "root"; + $cron_item['command'] = "/bin/rm {$cachedir}/swap.state; " . SQUID_LOCALBASE . "/sbin/squid -k rotate"; + $config['cron']['item'][] = $cron_item; + $need_write = true; + } + if($swapstate_job_id < 0) { + $cron_item = array(); + $cron_item['task_name'] = "squid_check_swapstate"; + $cron_item['minute'] = "*/15"; + $cron_item['hour'] = "*"; + $cron_item['mday'] = "*"; + $cron_item['month'] = "*"; + $cron_item['wday'] = "*"; + $cron_item['who'] = "root"; + $cron_item['command'] = "/usr/local/pkg/swapstate_check.php"; + $config['cron']['item'][] = $cron_item; + $need_write = true; + } + if ($need_write) { + parse_config(true); + write_config("Adding Squid Cron Jobs"); + } + break; + case false: + if($rotate_job_id >= 0) { + unset($config['cron']['item'][$rotate_job_id]); + $need_write = true; + } + if($swapstate_job_id >= 0) { + unset($config['cron']['item'][$swapstate_job_id]); + $need_write = true; + } + if ($need_write) { + parse_config(true); + write_config("Removing Squid Cron Jobs"); + } + break; } + configure_cron(); } function squid_resync_general() { diff --git a/config/squid3/34/squid.inc b/config/squid3/34/squid.inc index db5f1b0c..15854317 100755 --- a/config/squid3/34/squid.inc +++ b/config/squid3/34/squid.inc @@ -41,6 +41,12 @@ require_once('service-utils.inc'); if (!function_exists("filter_configure")) { require_once("filter.inc"); } +/* Squid reverse proxy */ +require_once('/usr/local/pkg/squid_reverse.inc'); +/* Squid javascript helpers */ +require_once('/usr/local/pkg/squid_js.inc'); +/* Squid antivirus intergration features helpers */ +require_once('/usr/local/pkg/squid_antivirus.inc'); $shortcut_section = "squid"; @@ -71,10 +77,16 @@ if ($uname['machine'] == 'amd64') { ini_set('memory_limit', '250M'); } +/* + * Utility functions + */ + +/* Handle base64 encoding and linebreaks in textarea configuration fields */ function sq_text_area_decode($text) { return preg_replace('/\r\n/', "\n", base64_decode($text)); } +/* Get interface IP and netmask for Squid interfaces */ function squid_get_real_interface_address($iface) { if (!function_exists("get_interface_ip")) { require_once("interfaces.inc"); @@ -83,52 +95,136 @@ function squid_get_real_interface_address($iface) { return array(get_interface_ip($iface), gen_subnet_mask(get_interface_subnet($iface))); } +/* Check whether ACL is valid */ +function squid_is_valid_acl($acl) { + global $valid_acls; + + if (!is_array($valid_acls)) { + return; + } + + return in_array($acl, $valid_acls); +} + +/* Recursively change ownership of directories */ function squid_chown_recursive($dir, $user, $group) { if (empty($dir) || ($dir == '/') || ($dir == '/usr/local') || !is_dir($dir)) { - log_error(gettext("Squid attempted to chown an invalid directory: {$dir}")); + log_error(gettext("[squid] Attempted to chown an invalid directory: '{$dir}'")); return; } chown($dir, $user); chgrp($dir, $group); - $handle = opendir($dir) ; - while (($item = readdir($handle)) !== false) { - if (!empty($item) && ($item != ".") && ($item != "..")) { - $path = "{$dir}/{$item}"; - // Recurse unless it's the cache dir, that is slow and rarely necessary. - if (is_dir($path) && (basename($dir) != "cache")) { - squid_chown_recursive($path, $user, $group); - } elseif (is_file($path)) { - chown($path, $user); - chgrp($path, $group); + $handle = opendir($dir); + if ($handle) { + while (($item = readdir($handle)) !== false) { + if (!empty($item) && ($item != ".") && ($item != "..")) { + $path = "{$dir}/{$item}"; + // Recurse unless it's the cache dir, that is slow and rarely necessary. + if (is_dir($path) && (basename($dir) != "cache")) { + squid_chown_recursive($path, $user, $group); + } elseif (is_file($path)) { + chown($path, $user); + chgrp($path, $group); + } } } + } else { + log_error(gettext("[squid] squid_chown_recursive() call failed; permissions not set for directory: '{$dir}'")); } } -function squid_check_clamav_user($user) { - if (SQUID_BASE == '/usr/local') { - return; +/* Check whether Squid is enabled */ +function squid_enabled() { + global $config, $proxy_enabled; + $proxy_enabled = false; + + if (is_array($config['installedpackages']['squid']['config'])) { + // check whether Squid is enabled ... + if ($config['installedpackages']['squid']['config'][0]['enable_squid'] == "on") { + // ... and has at least one interface configured ... + if ($config['installedpackages']['squid']['config'][0]['active_interface'] != "") { + $proxy_enabled = true; + } else { + // ... or has at least one reverse interface configured + if (is_array($config['installedpackages']['squidreversegeneral']['config'])) { + if ($config['installedpackages']['squidreversegeneral']['config'][0]['reverse_interface'] != "") { + $proxy_enabled = true; + } + } + } + } } + return $proxy_enabled; +} - $_gc = exec("/usr/sbin/pw usershow {$user}", $sq_ex_output, $sq_ex_return); - $user_arg = ($sq_ex_return == 0 ? "mod" : "add"); - $_gc = exec("/usr/sbin/pw user{$user_arg} {$user} -G wheel -u 9595 -s /sbin/nologin", $sq_ex_output, $sq_ex_return); - if ($sq_ex_return != 0) { - log_error("Squid - Could not change clamav user settings. " . serialize($sq_ex_output)); +/* Get list of certificates for SSL proxy */ +function squid_get_server_certs() { + global $config; + $cert_arr = array(); + $cert_arr[] = array('refid' => 'none', 'descr' => 'none'); + foreach ($config['cert'] as $cert) { + $cert_arr[] = array('refid' => $cert['refid'], 'descr' => $cert['descr']); } + return $cert_arr; } -function squid_update_clamav() { - log_error("Updating ClamAV definitions now... This will take a while. Check /var/log/clamav/freshclam.log for progress information."); - mwexec_bg(SQUID_BASE . "/bin/freshclam --config-file=" . SQUID_BASE . "/etc/freshclam.conf"); +/* Handle root CA certificates bundle */ +function squid_check_ca_hashes() { + global $config, $g; + + // check certificates + $cert_count = 0; + if (is_dir(SQUID_LOCALBASE . '/share/certs')) { + if ($handle = opendir(SQUID_LOCALBASE . '/share/certs')) { + while (false !== ($file = readdir($handle))) { + if (preg_match ("/\d+.0/", $file)) { + $cert_count++; + } + } + closedir($handle); + } + } + if ($cert_count < 10) { + conf_mount_rw(); + // create ca-root hashes from ca-root-nss package + log_error("[squid] Creating root certificate bundle hashes from the Mozilla Project..."); + $cas = file(SQUID_LOCALBASE . '/share/certs/ca-root-nss.crt'); + $cert = 0; + foreach ($cas as $ca) { + if (preg_match("/--BEGIN CERTIFICATE--/", $ca)) { + $cert = 1; + } + if ($cert == 1) { + $crt .= $ca; + } + if (preg_match("/-END CERTIFICATE-/", $ca)) { + file_put_contents("/tmp/cert.pem", $crt, LOCK_EX); + $cert_hash = array(); + exec("/usr/bin/openssl x509 -hash -noout -in /tmp/cert.pem", $cert_hash); + file_put_contents(SQUID_LOCALBASE . "/share/certs/" . $cert_hash[0] . ".0", $crt, LOCK_EX); + $crt = ""; + $cert = 0; + } + } + } } -/* setup cache */ +/* + * Squid cache setup + */ + + /* Create Squid disk cache directories */ function squid_dash_z($cache_action = 'none') { global $config; - // We need cache created on package install + // We need cache configured after initial package install + if (!is_array($config['installedpackages']['squidcache']['config'])) { + log_error("[squid] 'Local Cache' not configured, disk cache will be disabled."); + log_error("[squid] Please, configure and save 'Local Cache' settings before enabling Squid proxy."); + return; + } + if (is_array($config['installedpackages']['squidcache'])) { $cachesettings = $config['installedpackages']['squidcache']['config'][0]; } else { @@ -147,18 +243,18 @@ function squid_dash_z($cache_action = 'none') { if ($cachesettings['harddisk_cache_system'] == "null") { if (is_dir($cachedir)) { if (substr($cachedir, 0, 11) === "/var/squid/") { - log_error("Deleting Squid cache dir {$cachedir} since 'Hard Disk Cache System' is set to null."); + log_error("[squid] Deleting cache dir '{$cachedir}' since 'Hard Disk Cache System' is set to null..."); // cannot nuke disk cache while Squid is running squid_stop_monitor(); if (is_service_running('squid')) { stop_service("squid"); } - rename($cachedir, "{$cachedir}.old"); + @rename($cachedir, "{$cachedir}.old"); mwexec_bg("/bin/rm -rf {$cachedir}.old"); squid_restart_services(); } else { - log_error("'Hard Disk Cache System' is set to null."); - log_error("Will NOT delete Squid cache dir '{$cachedir}' since it is not located under /var/squid. Delete manually if required."); + log_error("[squid] 'Hard Disk Cache System' is set to null."); + log_error("[squid] Will NOT delete cache dir '{$cachedir}' since it is not located under /var/squid. Delete manually if required."); } } return; @@ -166,7 +262,7 @@ function squid_dash_z($cache_action = 'none') { // Re-create the cachedir if clean is forced by cronjob/manually, // or if the cachedir changed, or level1_subdirs don't exist or the number of level1_subdirs changed - if ($cache_action == "clean" || ((!is_dir($cachedir)) || (!is_dir($cachedir . '/00'))) || ($numdirs !== $currentdirs)) { + if ($cache_action == "clean" || !is_dir($cachedir) || !is_dir($cachedir . '/00') || $numdirs != $currentdirs) { // cannot nuke disk cache while Squid is running squid_stop_monitor(); if (is_service_running('squid')) { @@ -174,10 +270,10 @@ function squid_dash_z($cache_action = 'none') { } if (is_dir($cachedir)) { if (substr($cachedir, 0, 11) === "/var/squid/") { - rename($cachedir, "{$cachedir}.old"); + @rename($cachedir, "{$cachedir}.old"); mwexec_bg("/bin/rm -rf {$cachedir}.old"); } else { - log_error("Will NOT delete Squid cache dir '{$cachedir}' since it is not located under /var/squid. Delete manually if required."); + log_error("[squid] Will NOT delete cache dir '{$cachedir}' since it is not located under /var/squid. Delete manually if required."); } } squid_create_cachedir(); @@ -185,6 +281,7 @@ function squid_dash_z($cache_action = 'none') { } } +/* Helper function for squid_dash_z() */ function squid_create_cachedir() { global $config; if (is_array($config['installedpackages']['squidcache'])) { @@ -195,17 +292,17 @@ function squid_create_cachedir() { $cachedir = ($cachesettings['harddisk_cache_location'] ? $cachesettings['harddisk_cache_location'] : '/var/squid/cache'); if (!is_dir($cachedir)) { - log_error("Creating Squid cache dir {$cachedir}"); + log_error("[squid] Creating cache dir '{$cachedir}' ..."); safe_mkdir($cachedir, 0755); @chown($cachedir, SQUID_UID); @chgrp($cachedir, SQUID_GID); } if (!is_dir($cachedir . '/00')) { - log_error("Creating Squid cache subdirs in $cachedir"); + log_error("[squid] Creating Squid cache subdirs in {$cachedir} ..."); + mwexec(SQUID_BASE. "/sbin/squid -z -f " . SQUID_CONFFILE); // Double check permissions here, should be safe to recurse cache dir if it's small here. squid_chown_recursive($cachedir, SQUID_UID, SQUID_GID); - mwexec(SQUID_BASE. "/sbin/squid -z -f " . SQUID_CONFFILE); } if (file_exists("/var/squid/cache/swap.state")) { @@ -215,20 +312,315 @@ function squid_create_cachedir() { } } -function squid_is_valid_acl($acl) { - global $valid_acls; - if (!is_array($valid_acls)) { +/* + * rc scripts, services and cronjobs + */ + +/* Handle cronjob install/uninstall */ +function squid_install_cron($should_install) { + global $config; + + if (platform_booting()) { return; } - return in_array($acl, $valid_acls); + parse_config(true); + if (is_array($config['installedpackages']['squidcache'])) { + $settings = $config['installedpackages']['squidcache']['config'][0]; + } else { + $settings = array(); + } + + $cron_cmd = ($settings['clear_cache'] == 'on' ? "/usr/local/pkg/swapstate_check.php clean; " : ""); + $cron_cmd .= SQUID_BASE . "/sbin/squid -k rotate -f " . SQUID_CONFFILE; + install_cron_job("{$cron_cmd}", $should_install, "0", "0", "*", "*", "*", "root"); + + $swapstate_cmd = "/usr/local/pkg/swapstate_check.php clean; "; + if (($should_install) && (squid_enabled())) { + if ($settings['clear_cache'] == 'on' ) { + install_cron_job("{$swapstate_cmd}", true, "*/360"); + } else { + install_cron_job("{$swapstate_cmd}", false); + } + } else { + install_cron_job("{$swapstate_cmd}", false); + } } +/* Create /usr/local/etc/rc.d/squid.sh rc script */ +function squid_write_rcfile() { + /* Declare a variable for the SQUID_CONFFILE constant. */ + /* Then the variable can be referenced easily in the heredoc text that generates the rc file. */ + $squid_conffile_var = SQUID_CONFFILE; + $squid_base = SQUID_BASE; + $rc = array(); + $rc['file'] = 'squid.sh'; + $rc['start'] = <<< EOD +#/sbin/sysctl net.inet.ip.portrange.reservedhigh=0 +if [ -z "`/bin/ps auxw | /usr/bin/grep "[s]quid " | /usr/bin/awk '{print $2}'`" ]; then + {$squid_base}/sbin/squid -f {$squid_conffile_var} +fi + +EOD; + + $rc['stop'] = <<< EOD +{$squid_base}/sbin/squid -k shutdown -f {$squid_conffile_var} +# Just to be sure... +sleep 5 +if [ -n "`/bin/ps auxw | /usr/bin/grep "[s]quid " | /usr/bin/awk '{print $2}'`" ]; then + {$squid_base}/sbin/squid -k kill -f {$squid_conffile_var} +fi + +if [ -x /usr/bin/ipcs ]; then +# http://man.chinaunix.net/newsoft/squid/Squid_FAQ/FAQ-22.html#ss22.8 +/usr/bin/ipcs | /usr/bin/grep '^[mq]' | /usr/bin/awk '{printf "ipcrm -%s %s\\n", $1, $2}' | /bin/sh +fi + +/usr/bin/killall -9 squid 2>/dev/null +/usr/bin/killall pinger 2>/dev/null + +EOD; + + conf_mount_rw(); + write_rcfile($rc); + conf_mount_ro(); +} + +/* Start sqp_monitor.sh watchdog script */ +function squid_start_monitor() { + if (squid_enabled()) { + if (!exec("/bin/ps auxw | /usr/bin/grep '[s]qpmon'")) { + log_error("[squid] Starting a proxy monitor script"); + mwexec_bg("/usr/local/etc/rc.d/sqp_monitor.sh start"); + } + sleep(1); + } else { + log_error("[squid] Squid is disabled. Not starting a proxy monitor script"); + } +} + +/* Stop sqp_monitor.sh watchdog script */ +function squid_stop_monitor() { + /* kill any running proxy alarm scripts */ + if (exec("/bin/ps auxw | /usr/bin/grep '[s]qpmon'")) { + log_error("[squid] Stopping any running proxy monitors"); + mwexec("/usr/local/etc/rc.d/sqp_monitor.sh stop"); + } + sleep(1); +} + +/* Start and/or stop services according to Squid configuration */ +function squid_restart_services() { + global $config; + + // do not (re)start squid services on boot + if (platform_booting()) { + return; + } + + if (squid_enabled()) { + /* kill any running proxy alarm scripts */ + squid_stop_monitor(); + + if (!is_service_running('squid')) { + log_error("[squid] Starting service..."); + mwexec(SQUID_BASE . "/sbin/squid -f " . SQUID_CONFFILE); + } else { + log_error("[squid] Reloading for configuration sync..."); + mwexec(SQUID_BASE . "/sbin/squid -k reconfigure -f " . SQUID_CONFFILE); + } + // sleep for a couple seconds to give squid a chance to fire up fully. + for ($i = 0; $i < 10; $i++) { + if (!is_service_running('squid')) { + sleep(1); + } + } + /* restart proxy alarm scripts */ + squid_start_monitor(); + + } else { + /* Squid is disabled - kill any running proxy alarm scripts and stop Squid services */ + squid_stop_monitor(); + if (is_service_running('squid')) { + log_error("[squid] Stopping service..."); + stop_service("squid"); + } + } +} + + +/* + * Squid package install/uninstall + */ + function squid_install_command() { global $config, $g; - update_status("Checking if there is configuration to migrate... One moment please..."); + update_output_window("This operation may take quite some time, please be patient. Do not press stop or attempt to navigate away from this page during this process."); + update_output_window("Checking if there is configuration to migrate... One moment please..."); + + /* Set storage system for nanobsd */ + if (!is_array($config['installedpackages']['squidcache'])) { + $config['installedpackages']['squidcache'] = array(); + } + if ($g['platform'] == "nanobsd") { + $config['installedpackages']['squidcache']['config'][0]['harddisk_cache_system'] = 'null'; + } + + // migrate configuration from old versions + squid_upgrade_config(); + + /* make sure pinger is executable and suid root */ + // XXX: Bug #5114 + if (file_exists(SQUID_LOCALBASE . "/libexec/squid/pinger")) { + chgrp(SQUID_LOCALBASE . "/libexec/squid/pinger", SQUID_GID); + } + + // another PBI hack + if (SQUID_BASE != '/usr/local' && file_exists('/usr/local/bin/check_ip.php') && !file_exists(SQUID_BASE . '/bin/check_ip.php')) { + symlink("/usr/local/bin/check_ip.php", SQUID_BASE . "/bin/check_ip.php"); + } + + // create squid rcfile + squid_write_rcfile(); + + // create squid monitor rcfile + write_rcfile(array( + "file" => "sqp_monitor.sh", + "start" => "/usr/local/pkg/sqpmon.sh &", + "stop" => "/bin/ps awux | /usr/bin/grep \"sqpmon\" | /usr/bin/grep -v \"grep\" | /usr/bin/grep -v \"php\" | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill") + ); + + // antivirus intergration + squid_antivirus_install_command(); + + foreach (array(SQUID_CONFBASE, SQUID_ACLDIR, SQUID_SSL_DB) as $dir) { + safe_mkdir($dir, 0755); + squid_chown_recursive($dir, SQUID_UID, SQUID_GID); + } + + if (!file_exists(SQUID_CONFBASE . '/mime.conf') && file_exists(SQUID_CONFBASE . '/mime.conf.default')) { + copy(SQUID_CONFBASE . '/mime.conf.default', SQUID_CONFBASE . '/mime.conf'); + } + + // remove unwanted PBI rc script + unlink_if_exists("/usr/local/etc/rc.d/squid"); + +} + +function squid_deinstall_command() { + global $config, $g, $keep; + + /* remove cronjobs */ + squid_install_cron(false); + + /* kill all running services */ + update_output_window("Stopping and removing services..."); + mwexec('/usr/local/etc/rc.d/sqp_monitor.sh stop'); + mwexec("/bin/ps awux | /usr/bin/grep '[s]quid' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); + mwexec("/bin/ps awux | /usr/bin/grep '[d]nsserver' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); + mwexec("/bin/ps awux | /usr/bin/grep '[u]nlinkd' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); + + /* delete rc scripts */ + unlink_if_exists('/usr/local/etc/rc.d/sqp_monitor.sh'); + + /* clean up created directories if 'Keep Settings/Data' is disabled */ + if (is_array($config['installedpackages']['squidcache'])) { + $cachesettings = $config['installedpackages']['squidcache']['config'][0]; + } else { + $cachesettings = array(); + } + $cachedir = ($cachesettings['harddisk_cache_location'] ? $cachesettings['harddisk_cache_location'] : '/var/squid/cache'); + if (is_array($config['installedpackages']['squid'])) { + $squidsettings = $config['installedpackages']['squid']['config'][0]; + } else { + $squidsettings = array(); + } + $logdir = ($squidsettings['log_dir'] ? $squidsettings['log_dir'] : '/var/squid/logs'); + $keep = ($squidsettings['keep_squid_data'] ? true : false); + + if (!$keep) { + update_output_window("Removing cache and logs ... One moment please..."); + update_output_window("This operation may take quite some time, please be patient. Do not press stop or attempt to navigate away from this page during this process."); + if (is_dir("{$cachedir}")) { + if (substr($cachedir, 0, 11) === "/var/squid/") { + mwexec_bg("/bin/rm -rf {$cachedir}"); + } else { + log_error("[squid] Will NOT delete Squid cache dir '{$cachedir}' since it is not located under /var/squid. Delete manually if required."); + } + } + if (is_dir("{$logdir}")) { + if (substr($logdir, 0, 11) === "/var/squid/") { + mwexec("/bin/rm -rf {$logdir}"); + } else { + log_error("[squid] Will NOT delete Squid log dir '{$logdir}' since it is not located under /var/squid. Delete manually if required."); + } + } + update_output_window("Removing remaining Squid directories ... One moment please..."); + $dirs = array("/var/run/squid", "/var/squid"); + foreach ($dirs as $dir) { + if (is_dir("{$dir}")) { + mwexec("/bin/rm -rf {$dir}"); + } + } + } + + // remove antivirus integration features + squid_antivirus_deinstall_command(); + + update_output_window("Reloading filter..."); + filter_configure(); + + /* Remove package settings from config if 'Keep Settings/Data' is disabled */ + if (!$keep) { + log_error("[squid] Removing all Squid settings since 'Keep Settings/Data' is disabled..."); + if (is_array($config['installedpackages']['squid'])) { + unset($config['installedpackages']['squid']); + } + if (is_array($config['installedpackages']['squidantivirus'])) { + unset($config['installedpackages']['squidantivirus']); + } + if (is_array($config['installedpackages']['squidauth'])) { + unset($config['installedpackages']['squidauth']); + } + if (is_array($config['installedpackages']['squidcache'])) { + unset($config['installedpackages']['squidcache']); + } + if (is_array($config['installedpackages']['squidnac'])) { + unset($config['installedpackages']['squidnac']); + } + if (is_array($config['installedpackages']['squidreverse'])) { + unset($config['installedpackages']['squidreverse']); + } + if (is_array($config['installedpackages']['squidreversegeneral'])) { + unset($config['installedpackages']['squidreversegeneral']); + } + if (is_array($config['installedpackages']['squidreversepeer'])) { + unset($config['installedpackages']['squidreversepeer']); + } + if (is_array($config['installedpackages']['squidreverseredir'])) { + unset($config['installedpackages']['squidreverseredir']); + } + if (is_array($config['installedpackages']['squidsync'])) { + unset($config['installedpackages']['squidsync']); + } + if (is_array($config['installedpackages']['squidtraffic'])) { + unset($config['installedpackages']['squidtraffic']); + } + if (is_array($config['installedpackages']['squidremote'])) { + unset($config['installedpackages']['squidremote']); + } + if (is_array($config['installedpackages']['squidusers'])) { + unset($config['installedpackages']['squidusers']); + } + } + update_output_window("Squid3 has been uninstalled."); +} + +/* Migrate configuration from god knows which Squid package versions */ +/* None of these ever existed with Squid 3.4 package and this cruft should be most likely just removed */ +function squid_upgrade_config() { /* migrate existing csv config fields */ if (is_array($config['installedpackages']['squidauth']['config'])) { $settingsauth = $config['installedpackages']['squidauth']['config'][0]; @@ -243,15 +635,6 @@ function squid_install_command() { $settingsgen = $config['installedpackages']['squid']['config'][0]; } - if (SQUID_BASE != '/usr/local' && file_exists('/usr/local/bin/check_ip.php') && !file_exists(SQUID_BASE . '/bin/check_ip.php')) { - symlink("/usr/local/bin/check_ip.php", SQUID_BASE . "/bin/check_ip.php"); - } - - /* Set storage system */ - if ($g['platform'] == "nanobsd") { - $config['installedpackages']['squidcache']['config'][0]['harddisk_cache_system'] = 'null'; - } - /* migrate auth settings */ if (!empty($settingsauth['no_auth_hosts']) && strstr($settingsauth['no_auth_hosts'], ",")) { $settingsauth['no_auth_hosts'] = base64_encode(implode("\n", explode(",", $settingsauth['no_auth_hosts']))); @@ -341,7 +724,7 @@ function squid_install_command() { if (!is_array($config['installedpackages']['squidreverseuri'])) { foreach (explode("\n", sq_text_area_decode($old_reverse_settings['reverse_acl'])) as $acls) { foreach (explode(";", $acls) as $acl) { - array_push(${'peer_'.$acl[0]},$acl[1]); + array_push(${'peer_'.$acl[0]}, $acl[1]); } } foreach (explode("\n", sq_text_area_decode($old_reverse_settings['reverse_uri'])) as $uris) { @@ -359,180 +742,25 @@ function squid_install_command() { } } } - - update_status("Writing configuration... One moment please..."); - write_config(); - - /* make sure pinger is executable and suid root */ - // XXX: Bug #5114 - if (file_exists(SQUID_LOCALBASE . "/libexec/squid/pinger")) { - chgrp(SQUID_LOCALBASE . "/libexec/squid/pinger", SQUID_GID); - } - - // create squid rcfile - squid_write_rcfile(); - - // XXX: Is it really necessary? mode is set to 0755 in squid.xml - if (file_exists("/usr/local/pkg/swapstate_check.php")) { - @chmod("/usr/local/pkg/swapstate_check.php", 0755); - } - - // create squid monitor rcfile - write_rcfile(array( - "file" => "sqp_monitor.sh", - "start" => "/usr/local/pkg/sqpmon.sh &", - "stop" => "/bin/ps awux | /usr/bin/grep \"sqpmon\" | /usr/bin/grep -v \"grep\" | /usr/bin/grep -v \"php\" | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill") - ); - // create c-icap rcfile - squid_write_cicap_rcfile(); - - // make a backup of default c-icap config file on install; also see squid_resync_antivirus() function below - if (!file_exists(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.default")) { - if (file_exists(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.sample")) { - copy(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.sample", SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.default"); - } - } - - foreach (array(SQUID_CONFBASE, SQUID_ACLDIR, SQUID_SSL_DB) as $dir) { - safe_mkdir($dir, 0755); - squid_chown_recursive($dir, SQUID_UID, SQUID_GID); - } - - if (!file_exists(SQUID_CONFBASE . '/mime.conf') && file_exists(SQUID_CONFBASE . '/mime.conf.default')) { - copy(SQUID_CONFBASE . '/mime.conf.default', SQUID_CONFBASE . '/mime.conf'); - } - -} - -function squid_deinstall_command() { - global $config, $g; - - /* remove cronjobs */ - squid_install_cron(false); - squid_install_freshclam_cron(false); - - update_status("Stopping services..."); - /* kill all running services */ - mwexec('/usr/local/etc/rc.d/sqp_monitor.sh stop'); - if (is_process_running("c-icap")) { - mwexec('/bin/echo -n "stop" > /var/run/c-icap/c-icap.ctl'); - } - mwexec("/bin/ps awux | /usr/bin/grep '[c]lamd' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); - mwexec("/bin/ps awux | /usr/bin/grep '[f]reshclam' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); - mwexec("/bin/ps awux | /usr/bin/grep '[s]quid' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); - mwexec("/bin/ps awux | /usr/bin/grep '[d]nsserver' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); - mwexec("/bin/ps awux | /usr/bin/grep '[u]nlinkd' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); - /* delete rc scripts */ - unlink_if_exists('/usr/local/etc/rc.d/sqp_monitor.sh'); - unlink_if_exists('/usr/local/etc/rc.d/c-icap'); - unlink_if_exists("/usr/local/etc/rc.d/c-icap.sh"); - unlink_if_exists('/usr/local/etc/rc.d/clamav-clamd'); - unlink_if_exists('/usr/local/etc/rc.d/clamav-freshclam'); - - /* clean up created directories */ - update_status("Removing cache and logs ... One moment please..."); - update_output_window("This operation may take quite some time, please be patient. Do not press stop or attempt to navigate away from this page during this process."); - if (is_array($config['installedpackages']['squidcache'])) { - $cachesettings = $config['installedpackages']['squidcache']['config'][0]; - } else { - $cachesettings = array(); - } - $cachedir = ($cachesettings['harddisk_cache_location'] ? $cachesettings['harddisk_cache_location'] : '/var/squid/cache'); - if (is_array($config['installedpackages']['squid'])) { - $squidsettings = $config['installedpackages']['squid']['config'][0]; - } else { - $squidsettings = array(); - } - $logdir = ($squidsettings['log_dir'] ? $squidsettings['log_dir'] : '/var/squid/logs'); - // XXX: Is it ok to remove cache and logs? It's going to happen every time package is updated - if (is_dir("{$cachedir}")) { - if (substr($cachedir, 0, 11) === "/var/squid/") { - mwexec_bg("/bin/rm -rf {$cachedir}"); - } else { - log_error("Will NOT delete Squid cache dir '{$cachedir}' since it is not located under /var/squid. Delete manually if required."); - } - } - if (is_dir("{$logdir}")) { - if (substr($logdir, 0, 11) === "/var/squid/") { - mwexec("/bin/rm -rf {$logdir}"); - } else { - log_error("Will NOT delete Squid log dir '{$logdir}' since it is not located under /var/squid. Delete manually if required."); - } - } - $dirs = array("/var/run/c-icap", "/var/log/c-icap", "/var/log/clamav", "/var/run/clamav", "/var/db/clamav", "/var/run/squid", "/var/squid"); - foreach ($dirs as $dir) { - if (is_dir("{$dir}")) { - mwexec("/bin/rm -rf {$dir}"); - } - } - - /* clean up created PBI symlinks */ - update_status("Finishing package cleanup."); - if (SQUID_LOCALBASE != '/usr/local') { - $ln_icap = array('bin/c-icap', 'bin/c-icap-client', 'c-icap-config', 'c-icap-libicapapi-config', 'c-icap-stretch', 'lib/c_icap', 'share/c_icap', 'etc/c-icap'); - foreach ($ln_icap as $ln) { - if (is_link("/usr/local/{$ln}")) { - unlink("/usr/local/{$ln}"); - } - } - if (is_link("/usr/local/lib/libicapapi.so.3")) { - unlink("/usr/local/lib/libicapapi.so.3"); - } - } - - /* check if clamav/c_icap is enabled in rc.conf.local */ - if (file_exists("/etc/rc.conf.local")) { - update_status("Removing antivirus services from /etc/rc.conf.local..."); - $sample_file = file_get_contents("/etc/rc.conf.local"); - $rcconf_local_m[0] = "@c_icap_enable(.*)\n@"; - $rcconf_local_m[1] = "@clamav_clamd_enable(.*)\n@"; - $rcconf_local_r[0] = ""; - $rcconf_local_r[1] = ""; - file_put_contents("/etc/rc.conf.local", preg_replace($rcconf_local_m, $rcconf_local_r, $sample_file), LOCK_EX); + /* unset broken antivirus settings */ + if (is_array($config['installedpackages']['squidantivirus'])) { + unset($config['installedpackages']['squidantivirus']['config'][0]['squidclamav']); + unset($config['installedpackages']['squidantivirus']['config'][0]['c-icap_conf']); + unset($config['installedpackages']['squidantivirus']['config'][0]['c-icap_magic']); + unset($config['installedpackages']['squidantivirus']['config'][0]['freshclam_conf']); } - update_status("Reloading filter..."); - filter_configure(); + update_output_window("Writing configuration... One moment please..."); + write_config(); } -function squid_validate_antivirus($post, &$input_errors) { - global $config; - /* Manual ClamAV database update */ - if ($post['submit'] == 'Update AV') { - squid_update_clamav(); - return; - } - - if ($post['enable'] != "on") { - return; - } - - if ($post['squidclamav'] && preg_match("/(\S+proxy.domain\S+)/", $post['squidclamav'], $a_match)) { - $input_errors[] = "SquidClamav warnings redirect points to sample config domain ({$a_match[1]})"; - $input_errors[] = "Change redirect info on 'squidclamav.conf' field to pfSense GUI or an external host."; - } - if ($post['c-icap_conf']) { - if (!preg_match("/squid_clamav/", $post['c-icap_conf'])) { - $input_errors[] = "c-icap Squidclamav service definition is not present."; - $input_errors[] = "Add 'Service squid_clamav squidclamav.so'(without quotes) to 'c-icap.conf' field in order to get it working."; - } - if (preg_match("/(Manager:Apassword\S+)/", $post['c-icap_conf'], $c_match)) { - $input_errors[] = "Remove ldap configuration'{$c_match[1]}' from 'c-icap.conf' field."; - } - } - - if ($post['clamav_dbservers']) { - foreach (explode(";", $post['clamav_dbservers']) as $dbserver) { - $dbserver = trim($dbserver); - if (!empty($dbserver) && !is_ipaddr($dbserver) && !is_hostname($dbserver)) { - $input_errors[] = "'Optional ClamAV Database Update Servers' entry '$dbserver' is not a valid IP address or hostname."; - } - } - } -} +/* + * Squid input validation + */ +/* Proxy Server: General Settings input validation */ function squid_validate_general($post, &$input_errors) { global $config; @@ -542,6 +770,11 @@ function squid_validate_general($post, &$input_errors) { $settings = array(); } + // force users to configure cache + if (!is_array($config['installedpackages']['squidcache']['config'])) { + $input_errors[] = 'Please, configure and save \'Local Cache\' settings first.'; + } + $port = ($settings['proxy_port'] ? $settings['proxy_port'] : 3128); $port = $post['proxy_port'] ? $post['proxy_port'] : $port; @@ -613,6 +846,7 @@ function squid_validate_general($post, &$input_errors) { } } +/* Proxy Server: Remote Proxy Settings input validation */ function squid_validate_upstream($post, &$input_errors) { if ($post['enabled'] != 'on') { return; @@ -639,6 +873,7 @@ function squid_validate_upstream($post, &$input_errors) { } } +/* Proxy Server: Cache Management input validation */ function squid_validate_cache($post, &$input_errors) { $num_fields = array( 'harddisk_cache_size' => 'Hard disk cache size', @@ -694,6 +929,7 @@ function squid_validate_cache($post, &$input_errors) { } } +/* Proxy Server: Access Control input validation */ function squid_validate_nac($post, &$input_errors) { $allowed_subnets = explode("\n", $post['allowed_subnets']); foreach ($allowed_subnets as $subnet) { @@ -745,6 +981,7 @@ function squid_validate_nac($post, &$input_errors) { } } +/* Proxy server: Traffic Management input validation */ function squid_validate_traffic($post, &$input_errors) { $num_fields = array( 'max_download_size' => 'Maximum download size', @@ -782,75 +1019,7 @@ function squid_validate_traffic($post, &$input_errors) { } } -function squid_validate_reverse($post, &$input_errors) { - global $config; - - if (!empty($post['reverse_ip'])) { - $reverse_ip = explode(";", ($post['reverse_ip'])); - foreach ($reverse_ip as $reip) { - if (!is_ipaddr(trim($reip))) { - $input_errors[] = "You must enter a valid IP address in the 'User-defined reverse-proxy IPs' field. '$reip' is invalid."; - } - } - } - - $fqdn = trim($post['reverse_external_fqdn']); - if (!empty($fqdn) && !is_domain($fqdn)) { - $input_errors[] = "'External FQDN' field must contain a valid domain name."; - } - - $port = trim($post['reverse_http_port']); - preg_match("/(\d+)/", shell_exec("/sbin/sysctl net.inet.ip.portrange.reservedhigh"), $portrange); - if (!empty($port) && !is_port($port)) { - $input_errors[] = "'Reverse HTTP port' must contain a valid port number."; - } - if (!empty($port) && is_port($port) && $port <= $portrange[1]) { - $input_errors[] = "'Reverse HTTP port' must contain a port number higher than net.inet.ip.portrange.reservedhigh sysctl value({$portrange[1]})."; - $input_errors[] = "To listen on low ports, change portrange.reservedhigh sysctl value to 0 in system tunable options and restart Squid daemon."; - } - $port = trim($post['reverse_https_port']); - if (!empty($port) && !is_port($port)) { - $input_errors[] = "'Reverse HTTPS port' must contain a valid port number."; - } - if (!empty($port) && is_port($port) && $port <= $portrange[1]) { - $input_errors[] = "'Reverse HTTPS port' must contain a port number higher than net.inet.ip.portrange.reservedhigh sysctl value({$portrange[1]})."; - $input_errors[] = "To listen on low ports, change portrange.reservedhigh sysctl value to 0 in system tunable options and restart Squid daemon."; - } - if ($post['reverse_ssl_cert'] == 'none') { - $input_errors[] = 'A valid certificate for the external interface must be selected'; - } - - if (($post['reverse_https'] != 'on') && ($post['reverse_owa'] == 'on')) { - $input_errors[] = "You have to enable reverse HTTPS before enabling OWA support."; - } - - if (!empty($post['reverse_owa_ip'])) { - $reverse_owa_ip = explode(";", ($post['reverse_owa_ip'])); - foreach ($reverse_owa_ip as $reowaip) { - if (!is_ipaddr(trim($reowaip))) { - $input_errors[] = "You must enter a valid IP address in the 'CAS-Array / OWA frontend IP address' field. '$reowaip' is invalid."; - } - } - } - - $contents = $post['reverse_cache_peer']; - if (!empty($contents)) { - $defs = explode("\r\n", ($contents)); - foreach ($defs as $def) { - $cfg = explode(";", ($def)); - if (!is_ipaddr($cfg[1])) { - $input_errors[] = "Please choose a valid IP in the cache peer configuration."; - } - if (!is_port($cfg[2])) { - $input_errors[] = "Please choose a valid port in the cache peer configuration."; - } - if (($cfg[3] != 'HTTPS') && ($cfg[3] != 'HTTP')) { - $input_errors[] = "Please choose HTTP or HTTPS in the cache peer configuration."; - } - } - } -} - +/* Proxy Server: Authentication input validation */ function squid_validate_auth($post, &$input_errors) { $num_fields = array( array('auth_processes', 'Authentication processes', 1), @@ -912,102 +1081,7 @@ function squid_validate_auth($post, &$input_errors) { } } -function squid_install_cron($should_install) { - global $config; - - if (platform_booting()) { - return; - } - - parse_config(true); - if (is_array($config['installedpackages']['squidcache'])) { - $settings = $config['installedpackages']['squidcache']['config'][0]; - } else { - $settings = array(); - } - - $cron_cmd = ($settings['clear_cache'] == 'on' ? "/usr/local/pkg/swapstate_check.php clean; " : ""); - $cron_cmd .= SQUID_BASE . "/sbin/squid -k rotate -f " . SQUID_CONFFILE; - install_cron_job("{$cron_cmd}", $should_install, "0", "0", "*", "*", "*", "root"); - - $swapstate_cmd = "/usr/local/pkg/swapstate_check.php clean; "; - if ($should_install) { - if ($settings['clear_cache'] == 'on' ) { - install_cron_job("{$swapstate_cmd}", true, "*/360"); - } else { - install_cron_job("{$swapstate_cmd}", false); - } - } else { - install_cron_job("{$swapstate_cmd}", false); - } -} - -function squid_install_freshclam_cron($should_install) { - global $config; - - if (platform_booting()) { - return; - } - - if (is_array($config['installedpackages']['squidantivirus'])) { - $antivirus_config = $config['installedpackages']['squidantivirus']['config'][0]; - } else { - $antivirus_config = array(); - } - - $freshclam_cmd = (SQUID_BASE . "/bin/freshclam --config-file=" . SQUID_BASE . "/etc/freshclam.conf"); - if ($should_install) { - if ($antivirus_config['clamav_update'] != "0") { - $minutes = ($antivirus_config['clamav_update'] * 60); - install_cron_job("{$freshclam_cmd}", true, "*/{$minutes}", "*", "*", "*", "*", "clamav"); - } else { - install_cron_job("{$freshclam_cmd}", false); - } - } else { - install_cron_job("{$freshclam_cmd}", false); - } -} - -function squid_check_ca_hashes() { - global $config, $g; - - // check certificates - $cert_count = 0; - if (is_dir(SQUID_LOCALBASE . '/share/certs')) { - if ($handle = opendir(SQUID_LOCALBASE . '/share/certs')) { - while (false !== ($file = readdir($handle))) { - if (preg_match ("/\d+.0/",$file)) { - $cert_count++; - } - } - closedir($handle); - } - } - if ($cert_count < 10) { - conf_mount_rw(); - // create ca-root hashes from ca-root-nss package - log_error("Creating root certificate bundle hashes from the Mozilla Project"); - $cas = file(SQUID_LOCALBASE . '/share/certs/ca-root-nss.crt'); - $cert = 0; - foreach ($cas as $ca) { - if (preg_match("/--BEGIN CERTIFICATE--/", $ca)) { - $cert = 1; - } - if ($cert == 1) { - $crt .= $ca; - } - if (preg_match("/-END CERTIFICATE-/", $ca)) { - file_put_contents("/tmp/cert.pem", $crt, LOCK_EX); - $cert_hash = array(); - exec("/usr/bin/openssl x509 -hash -noout -in /tmp/cert.pem", $cert_hash); - file_put_contents(SQUID_LOCALBASE . "/share/certs/" . $cert_hash[0] . ".0", $crt, LOCK_EX); - $crt = ""; - $cert = 0; - } - } - } -} - +/* Proxy Server: General Settings configuration handler */ function squid_resync_general() { global $g, $config, $valid_acls; @@ -1098,7 +1172,7 @@ function squid_resync_general() { $iface_ip = squid_get_real_interface_address($iface); if ($iface_ip[0]) { $real_ifaces[] = $iface_ip; - if (in_array($iface,$ssl_ifaces)) { + if (in_array($iface, $ssl_ifaces)) { $conf .= "http_port {$iface_ip[0]}:{$port} {$ssl_interception}\n"; } else { $conf .= "http_port {$iface_ip[0]}:{$port}\n"; @@ -1129,7 +1203,7 @@ function squid_resync_general() { $logdir = ($settings['log_dir'] ? $settings['log_dir'] : '/var/squid/logs'); if (!is_dir($logdir)) { - log_error("Creating Squid log dir $logdir"); + log_error("[squid] Creating Squid log dir '{$logdir}' ..."); safe_mkdir($logdir, 0755); squid_chown_recursive($logdir, SQUID_UID, SQUID_GID); } @@ -1220,6 +1294,7 @@ EOD; return $conf; } +/* Proxy Server: Cache Management configuration handler */ function squid_resync_cache() { global $config, $g; @@ -1242,8 +1317,11 @@ function squid_resync_cache() { $offline_mode = ($settings['enable_offline'] == 'on' ? 'on' : 'off'); $conf = ''; if (!isset($settings['harddisk_cache_system'])) { - if ($g['platform'] == "nanobsd" || !is_array ($config['installedpackages']['squidcache']['config'])) { + if ($g['platform'] == "nanobsd") { $disk_cache_system = 'null'; + } elseif (!is_array($config['installedpackages']['squidcache']['config'])) { + log_error("[squid] 'Local Cache' not configured, disk cache will be disabled."); + log_error("[squid] Please, configure and save 'Local Cache' settings before enabling Squid proxy."); } else { $disk_cache_system = 'ufs'; } @@ -1358,6 +1436,7 @@ EOD; return $conf.$refresh_conf; } +/* Proxy Server: Remote Proxy Settings configuration handler */ function squid_resync_upstream() { global $config; @@ -1399,20 +1478,7 @@ function squid_resync_upstream() { return $conf; } -function squid_resync_redirector() { - global $config; - - // XXX: What port provide squirm binary? It's not present - $httpav_enabled = ($config['installedpackages']['clamav']['config'][0]['scan_http'] == 'on'); - $redirector = "/usr/local/bin/squirm"; - if (($httpav_enabled) && is_executable($redirector)) { - $conf = "url_rewrite_program /usr/local/bin/squirm\n"; - } else { - $conf = "# No redirector configured\n"; - } - return $conf; -} - +/* Proxy Server: Access Control configuration handler */ function squid_resync_nac() { global $config, $valid_acls; @@ -1509,272 +1575,7 @@ EOD; return $conf; } -function squid_resync_antivirus() { - global $config; - - if (is_array($config['installedpackages']['squidantivirus'])) { - $antivirus_config = $config['installedpackages']['squidantivirus']['config'][0]; - } else { - $antivirus_config = array(); - } - - if ($antivirus_config['enable'] == "on") { - switch ($antivirus_config['client_info']) { - case "both": - default: - $icap_send_client_ip = "on"; - $icap_send_client_username = "on"; - break; - case "ip": - $icap_send_client_ip = "on"; - $icap_send_client_username = "off"; - break; - case "username": - $icap_send_client_ip = "off"; - $icap_send_client_username = "on"; - break; - case "none": - $icap_send_client_ip = "off"; - $icap_send_client_username = "off"; - break; - } - - $conf = <<< EOF -icap_enable on -icap_send_client_ip {$icap_send_client_ip} -icap_send_client_username {$icap_send_client_username} -icap_client_username_encode off -icap_client_username_header X-Authenticated-User -icap_preview_enable on -icap_preview_size 1024 - -icap_service service_avi_req reqmod_precache icap://[::1]:1344/squid_clamav bypass=off -adaptation_access service_avi_req allow all -icap_service service_avi_resp respmod_precache icap://[::1]:1344/squid_clamav bypass=on -adaptation_access service_avi_resp allow all - -EOF; - - // check if clamav is enabled in rc.conf.local - // XXX: This whole thing sucks and should be redone to install/enable services in pfSense way - if (file_exists("/etc/rc.conf.local")) { - $rc_old_file = file("/etc/rc.conf.local"); - foreach ($rc_old_file as $rc_line) { - if (preg_match("/^clamav_clamd_enable/", $rc_line, $matches)) { - $rc_file .= $matches[1] . '="YES"' . "\n"; - ${$matches[1]} = "ok"; - } else { - $rc_file .= $rc_line; - } - } - } - if (!isset($clamav_clamd_enable)) { - $rc_file .= 'clamav_clamd_enable="YES"' . "\n"; - } - file_put_contents("/etc/rc.conf.local", $rc_file, LOCK_EX); - squid_check_clamav_user('clamav'); - // patch sample files to pfsense dirs - // squidclamav.conf - if (file_exists(SQUID_LOCALBASE . "/etc/c-icap/squidclamav.conf.default")) { - $sample_file = file_get_contents(SQUID_LOCALBASE . "/etc/c-icap/squidclamav.conf.default"); - $clamav_m[0] = "@/var/run/clamav/clamd.ctl@"; - $clamav_m[1] = "@http\://proxy.domain.dom/cgi-bin/clwarn.cgi@"; - $clamav_r[0] = "/var/run/clamav/clamd.sock"; - $clamav_r[1] = "{$config['system']['webgui']['protocol']}://{$config['system']['hostname']}.{$config['system']['domain']}/squid_clwarn.php"; - if ($antivirus_config['clamav_safebrowsing'] == "on") { - $clamav_m[2] = "@safebrowsing\s0@"; - $clamav_r[2] = "safebrowsing 1"; - } - file_put_contents(SQUID_LOCALBASE . "/etc/c-icap/squidclamav.conf.sample", preg_replace($clamav_m, $clamav_r, $sample_file), LOCK_EX); - } - // c-icap.conf - // make a backup of default c-icap.conf.sample first - // unlike with other config files, the file distributed in package is called c-icap.conf.sample, not c-icap.conf.default - if (!file_exists(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.default")) { - copy(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.sample", SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.default"); - } - if (file_exists(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.default")) { - $sample_file = file_get_contents(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.default"); - if (!preg_match("/squid_clamav/", $sample_file)) { - $sample_file .= "\nService squid_clamav squidclamav.so\n"; - } - $cicap_m[0] = "@Manager:Apassword\S+@"; - $cicap_r[0] = ""; - // XXX: Bug #4615 - if (is_array($config['installedpackages']['squid'])) { - $squidsettings = $config['installedpackages']['squid']['config'][0]; - } else { - $squidsettings = array(); - } - $logdir = ($squidsettings['log_dir'] ? $squidsettings['log_dir'] : '/var/squid/logs'); - $cicap_m[1] = "@DebugLevel\s1@"; - $cicap_r[1] = "DebugLevel 0"; - $cicap_m[2] = "@AccessLog /var/log/c-icap/access.log@"; - $cicap_r[2] = "AccessLog $logdir/c-icap-access.log"; - $cicap_m[3] = "@ServerLog /var/log/c-icap/server.log@"; - $cicap_r[3] = "ServerLog $logdir/c-icap-server.log"; - file_put_contents(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.sample", preg_replace($cicap_m, $cicap_r, $sample_file), LOCK_EX); - } - // freshclam.conf - // make a backup of default freshclam.conf.sample first - if (!file_exists(SQUID_LOCALBASE . "/etc/freshclam.conf.default")) { - copy(SQUID_LOCALBASE . "/etc/freshclam.conf.sample", SQUID_LOCALBASE . "/etc/freshclam.conf.default"); - } - if (file_exists(SQUID_LOCALBASE . "/etc/freshclam.conf.default")) { - $sample_file = file_get_contents(SQUID_LOCALBASE . "/etc/freshclam.conf.default"); - $freshclam_m[0] = "@#Example@"; - $freshclam_r[0] = ""; - $clamav_mirrors = ""; - if ($antivirus_config['clamav_dbregion'] != "") { - $clamav_mirrors .= "DatabaseMirror db.{$antivirus_config['clamav_dbregion']}.clamav.net\n"; - } - if ($antivirus_config['clamav_dbservers'] != "") { - foreach (explode(";", $antivirus_config['clamav_dbservers']) as $dbserver) { - $clamav_mirrors .= "DatabaseMirror {$dbserver}\n"; - } - } - if ($clamav_mirrors != "") { - $freshclam_m[1] = "@#DatabaseMirror db.XY.clamav.net@"; - $freshclam_r[1] = "{$clamav_mirrors}"; - } - if ($antivirus_config['clamav_safebrowsing'] == "on") { - $freshclam_m[2] = "@#SafeBrowsing yes@"; - $freshclam_r[2] = "SafeBrowsing yes"; - } - file_put_contents(SQUID_LOCALBASE . "/etc/freshclam.conf.sample", preg_replace($freshclam_m, $freshclam_r, $sample_file), LOCK_EX); - } - // freshclam cronjob - squid_install_freshclam_cron(true); - - // check squidclamav files until PBIs are gone (https://redmine.pfsense.org/issues/4197) - $ln_icap = array('bin/c-icap', 'bin/c-icap-client', 'c-icap-config', 'c-icap-libicapapi-config', 'c-icap-stretch', 'lib/c_icap', 'share/c_icap', 'etc/c-icap'); - foreach ($ln_icap as $ln) { - if (SQUID_LOCALBASE != '/usr/local' && !file_exists("/usr/local/{$ln}") && file_exists(SQUID_LOCALBASE . "/{$ln}")) { - symlink(SQUID_LOCALBASE . "/{$ln}", "/usr/local/{$ln}"); - } - } - if (SQUID_LOCALBASE != '/usr/local' && !file_exists("/usr/local/lib/libicapapi.so.3") && file_exists(SQUID_LOCALBASE . "/lib/libicapapi.so.3.0.5")) { - symlink(SQUID_LOCALBASE . "/lib/libicapapi.so.3.0.5", "/usr/local/lib/libicapapi.so.3"); - } - - $loadsample = 0; - if ($antivirus_config['squidclamav'] == "" && file_exists(SQUID_LOCALBASE . "/etc/c-icap/squidclamav.conf.sample")) { - $config['installedpackages']['squidantivirus']['config'][0]['squidclamav'] = base64_encode(str_replace("\r", "", file_get_contents(SQUID_LOCALBASE . "/etc/c-icap/squidclamav.conf.sample"))); - $loadsample++; - } - if ($antivirus_config['c-icap_conf'] == "" && file_exists(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.sample")) { - $config['installedpackages']['squidantivirus']['config'][0]['c-icap_conf'] = base64_encode(str_replace("\r", "", file_get_contents(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf.sample"))); - $loadsample++; - } - if ($antivirus_config['c-icap_magic'] == "" && file_exists(SQUID_LOCALBASE . "/etc/c-icap/c-icap.magic.sample")) { - $config['installedpackages']['squidantivirus']['config'][0]['c-icap_magic'] = base64_encode(str_replace("\r", "", file_get_contents(SQUID_LOCALBASE . "/etc/c-icap/c-icap.magic.sample"))); - $loadsample++; - } - if ($antivirus_config['freshclam_conf'] == "" && file_exists(SQUID_LOCALBASE . "/etc/freshclam.conf.sample")) { - $config['installedpackages']['squidantivirus']['config'][0]['freshclam_conf'] = base64_encode(str_replace("\r", "", file_get_contents(SQUID_LOCALBASE . "/etc/freshclam.conf.sample"))); - $loadsample++; - } - if ($loadsample > 0) { - write_config(); - $antivirus_config = $config['installedpackages']['squidantivirus']['config'][0]; - } - // check dirs - $dirs = array( - "/var/run/c-icap" => "clamav", - "/var/log/c-icap" => "clamav", - "/var/log/clamav" => "clamav", - "/var/run/clamav" => "clamav", - "/var/db/clamav" => "clamav" - ); - foreach ($dirs as $dir_path => $dir_user) { - safe_mkdir($dir_path, 0755); - squid_chown_recursive($dir_path, $dir_user, "wheel"); - } - - $rcd_files = scandir(SQUID_LOCALBASE."/etc/rc.d"); - foreach ($rcd_files as $rcd_file) { - if (SQUID_LOCALBASE != '/usr/local' && !file_exists("/usr/local/etc/rc.d/{$rcd_file}")) { - symlink(SQUID_LOCALBASE . "/etc/rc.d/{$rcd_file}", "/usr/local/etc/rc.d/{$rcd_file}"); - } - } - - // write advanced clamav/icap config files - file_put_contents(SQUID_LOCALBASE . "/etc/c-icap/squidclamav.conf", base64_decode($antivirus_config['squidclamav']), LOCK_EX); - file_put_contents(SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf", base64_decode($antivirus_config['c-icap_conf']), LOCK_EX); - file_put_contents(SQUID_LOCALBASE . "/etc/c-icap/c-icap.magic", base64_decode($antivirus_config['c-icap_magic']), LOCK_EX); - file_put_contents(SQUID_LOCALBASE . "/etc/freshclam.conf", base64_decode($antivirus_config['freshclam_conf']), LOCK_EX); - - // Check clamav database - if (count(glob("/var/db/clamav/*d")) == 0) { - log_error("Squid - Missing /var/db/clamav/*.cvd or *.cld files. Running freshclam in background."); - mwexec_bg(SQUID_BASE . "/bin/freshclam --config-file=" . SQUID_BASE . "/etc/freshclam.conf"); - } elseif (($antivirus_config['clamav_safebrowsing'] == "on") && (!is_file("/var/db/clamav/safebrowsing.cvd"))) { - log_error("Squid - Google Safe Browsing is enabled but missing safebrowsing.cvd definitions. Running freshclam in background."); - mwexec_bg(SQUID_BASE . "/bin/freshclam --config-file=" . SQUID_BASE . "/etc/freshclam.conf"); - } - - // check antivirus daemons - // check icap - $c_icap_rcfile = "/usr/local/etc/rc.d/c-icap.sh"; - if (!file_exists($c_icap_rcfile)) { - squid_write_cicap_rcfile(); - } - if (is_process_running("c-icap")) { - mwexec_bg('/bin/echo -n "reconfigure" > /var/run/c-icap/c-icap.ctl'); - } else { - mwexec_bg("{$c_icap_rcfile} start"); - } - // check clamav/freshclam - $rc_files = array("clamav-freshclam", "clamav-clamd"); - $clamm[0] = "@/usr/local/(bin|sbin)@"; - $clamm[1] = "@/local/(bin|sbin)@"; - $clamm[2] = "@/usr/local/etc@"; - $clamm[3] = "@enable:=NO@"; - $clamr[0] = SQUID_BASE . "/bin"; - $clamr[1] = "/bin"; - $clamr[2] = SQUID_LOCALBASE . "/etc"; - $clamr[3] = "enable:=YES"; - foreach ($rc_files as $rc_file) { - $clamav_rcfile = "/usr/local/etc/rc.d/{$rc_file}"; - if (file_exists($clamav_rcfile)) { - $sample_file = file_get_contents($clamav_rcfile); - file_put_contents($clamav_rcfile, preg_replace($clamm, $clamr, $sample_file), LOCK_EX); - } - } - if (is_process_running("clamd")) { - mwexec_bg("/usr/local/etc/rc.d/clamav-clamd reload"); - } else { - mwexec_bg("/usr/local/etc/rc.d/clamav-clamd start"); - } - } else { - // stop AV services and disable all C-ICAP/AV features - log_error("Squid antivirus features disabled."); - if (is_process_running("clamd")) { - log_error("Stopping ClamAV..."); - mwexec("/bin/ps awux | /usr/bin/grep '[c]lamd' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); - } - if (is_process_running("c-icap")) { - log_error("Stopping C-ICAP..."); - mwexec_bg("/usr/local/etc/rc.d/c-icap.sh stop"); - } - // freshclam cronjob - log_error("Removing freshclam cronjob..."); - squid_install_freshclam_cron(false); - - // check if clamav is enabled in rc.conf.local - // XXX: This whole thing sucks and should be redone to install/enable services in pfSense way - if (file_exists("/etc/rc.conf.local")) { - log_error("Removing antivirus services from /etc/rc.conf.local..."); - $sample_file = file_get_contents("/etc/rc.conf.local"); - $rcconf_local_m[0] = "@clamav_clamd_enable(.*)\n@"; - $rcconf_local_r[0] = ""; - file_put_contents("/etc/rc.conf.local", preg_replace($rcconf_local_m, $rcconf_local_r, $sample_file), LOCK_EX); - } - } - - return $conf; -} - +/* Proxy server: Traffic Management configuration handler */ function squid_resync_traffic() { global $config, $valid_acls; @@ -1871,19 +1672,7 @@ EOD; return $conf; } -function squid_get_server_certs() { - global $config; - $cert_arr = array(); - $cert_arr[] = array('refid' => 'none', 'descr' => 'none'); - foreach ($config['cert'] as $cert) { - $cert_arr[] = array('refid' => $cert['refid'], 'descr' => $cert['descr']); - } - return $cert_arr; -} - -// squid reverse -include('/usr/local/pkg/squid_reverse.inc'); - +/* Proxy Server: Authentication configuration handler */ function squid_resync_auth() { global $config, $valid_acls; $write_config = 0; @@ -2106,6 +1895,7 @@ EOD; return $conf; } +/* Proxy server: Local users configuration handler */ function squid_resync_users() { global $config; @@ -2121,6 +1911,7 @@ function squid_resync_users() { chmod(SQUID_PASSWD, 0600); } +/* Proxy server: NT Domain configuration handler */ function squid_resync_msnt() { global $config; @@ -2138,6 +1929,7 @@ function squid_resync_msnt() { chmod(SQUID_CONFBASE . "/msntauth.conf", 0600); } +/* Wrapper function to sync whole Squid configuration */ function squid_resync($via_rpc = "no") { global $config; @@ -2150,7 +1942,7 @@ function squid_resync($via_rpc = "no") { } } - log_error("[Squid] - Squid_resync function call pr:" . is_process_running('squid') . " bp:" . isset($boot_process) . " rpc:" . $via_rpc); + log_error("[squid] - squid_resync function call pr:" . is_process_running('squid') . " bp:" . isset($boot_process) . " rpc:" . $via_rpc); if (is_process_running('squid') && isset($boot_process) && $via_rpc == "no") { return; @@ -2163,7 +1955,6 @@ function squid_resync($via_rpc = "no") { } $conf = squid_resync_general() . "\n"; $conf .= squid_resync_cache() . "\n"; - $conf .= squid_resync_redirector() . "\n"; $conf .= squid_resync_upstream() . "\n"; $conf .= squid_resync_nac() . "\n"; $conf .= squid_resync_traffic() . "\n"; @@ -2195,223 +1986,9 @@ function squid_resync($via_rpc = "no") { conf_mount_ro(); } -function squid_stop_monitor() { - /* kill any running proxy alarm scripts */ - if (exec("/bin/ps auxw | /usr/bin/grep '[s]qpmon'")) { - log_error("Stopping any running proxy monitors"); - mwexec("/usr/local/etc/rc.d/sqp_monitor.sh stop"); - } - sleep(1); -} - -function squid_start_monitor() { - if (!exec("/bin/ps auxw | /usr/bin/grep '[s]qpmon'")) { - log_error("Starting a proxy monitor script"); - mwexec_bg("/usr/local/etc/rc.d/sqp_monitor.sh start"); - } - sleep(1); -} - -function squid_restart_services() { - global $config; - // reconfigure and (re)start service as needed if enabled, otherwise stop them - // do not (re)start squid services on boot - if (platform_booting()) { - return; - } - $squid_enabled = false; - if (is_array($config['installedpackages']['squid']['config'])) { - // check if Squid is enabled - if ($config['installedpackages']['squid']['config'][0]['active_interface'] != "") { - $squid_enabled = true; - } - } elseif (is_array($config['installedpackages']['squidreversegeneral']['config'])) { - // check if squidreverse is enabled - if ($config['installedpackages']['squidreversegeneral']['config'][0]['reverse_interface'] != "") { - $squid_enabled = true; - } - } - - if ($squid_enabled) { - /* kill any running proxy alarm scripts */ - squid_stop_monitor(); - - if (!is_service_running('squid')) { - log_error("Starting Squid"); - mwexec(SQUID_BASE . "/sbin/squid -f " . SQUID_CONFFILE); - } else { - log_error("Reloading Squid for configuration sync"); - mwexec(SQUID_BASE . "/sbin/squid -k reconfigure -f " . SQUID_CONFFILE); - } - // sleep for a couple seconds to give squid a chance to fire up fully. - for ($i = 0; $i < 10; $i++) { - if (!is_service_running('squid')) { - sleep(1); - } - } - /* restart proxy alarm scripts */ - squid_start_monitor(); - - } else { - /* Squid is disabled - kill any running proxy alarm scripts and stop Squid services */ - squid_stop_monitor(); - if (is_service_running('squid')) { - log_error("Stopping Squid"); - stop_service("squid"); - } - } -} - -function squid_print_javascript_auth() { - global $config; - $transparent_proxy = ($config['installedpackages']['squid']['config'][0]['transparent_proxy'] == 'on'); - - // No authentication for transparent proxy - if ($transparent_proxy and preg_match("/(local|ldap|radius|msnt|ntlm)/",$config['installedpackages']['squidauth']['config'][0]['auth_method'])) { - $javascript = <<< EOD -<script type="text/javascript"> -<!-- -function on_auth_method_changed() { - document.iform.auth_method.disabled = 1; - document.iform.auth_server.disabled = 1; - document.iform.auth_ntdomain.disabled = 1; - document.iform.auth_server_port.disabled = 1; - document.iform.ldap_user.disabled = 1; - document.iform.ldap_version.disabled = 1; - document.iform.ldap_userattribute.disabled = 1; - document.iform.ldap_filter.disabled = 1; - document.iform.ldap_pass.disabled = 1; - document.iform.ldap_basedomain.disabled = 1; - document.iform.radius_secret.disabled = 1; - document.iform.msnt_secondary.disabled = 1; - document.iform.auth_prompt.disabled = 1; - document.iform.auth_processes.disabled = 1; - document.iform.auth_ttl.disabled = 1; - document.iform.unrestricted_auth.disabled = 1; - document.iform.no_auth_hosts.disabled = 1; -} ---> -</script> - -EOD; - } else { - $javascript = <<< EOD -<script type="text/javascript"> -<!-- -function on_auth_method_changed() { - var field = document.iform.auth_method; - var auth_method = field.options[field.selectedIndex].value; - - if (auth_method == 'none') { - document.iform.auth_server.disabled = 1; - document.iform.auth_server_port.disabled = 1; - document.iform.auth_ntdomain.disabled = 1; - document.iform.ldap_user.disabled = 1; - document.iform.ldap_version.disabled = 1; - document.iform.ldap_userattribute.disabled = 1; - document.iform.ldap_filter.disabled = 1; - document.iform.ldap_pass.disabled = 1; - document.iform.ldap_basedomain.disabled = 1; - document.iform.radius_secret.disabled = 1; - document.iform.msnt_secondary.disabled = 1; - document.iform.auth_prompt.disabled = 1; - document.iform.auth_processes.disabled = 1; - document.iform.auth_ttl.disabled = 1; - document.iform.unrestricted_auth.disabled = 1; - document.iform.no_auth_hosts.disabled = 1; - } else { - document.iform.auth_prompt.disabled = 0; - document.iform.auth_processes.disabled = 0; - document.iform.auth_ttl.disabled = 0; - document.iform.unrestricted_auth.disabled = 0; - document.iform.no_auth_hosts.disabled = 0; - } - - switch (auth_method) { - case 'local': - document.iform.auth_server.disabled = 1; - document.iform.auth_server_port.disabled = 1; - document.iform.auth_ntdomain.disabled = 1; - document.iform.ldap_user.disabled = 1; - document.iform.ldap_pass.disabled = 1; - document.iform.ldap_version.disabled = 1; - document.iform.ldap_userattribute.disabled = 1; - document.iform.ldap_filter.disabled = 1; - document.iform.ldap_basedomain.disabled = 1; - document.iform.radius_secret.disabled = 1; - document.iform.msnt_secondary.disabled = 1; - break; - case 'ldap': - document.iform.auth_server.disabled = 0; - document.iform.auth_server_port.disabled = 0; - document.iform.ldap_user.disabled = 0; - document.iform.ldap_pass.disabled = 0; - document.iform.ldap_version.disabled = 0; - document.iform.ldap_userattribute.disabled = 0; - document.iform.ldap_filter.disabled = 0; - document.iform.ldap_basedomain.disabled = 0; - document.iform.radius_secret.disabled = 1; - document.iform.msnt_secondary.disabled = 1; - document.iform.auth_ntdomain.disabled = 1; - break; - case 'radius': - document.iform.auth_server.disabled = 0; - document.iform.auth_server_port.disabled = 0; - document.iform.ldap_user.disabled = 1; - document.iform.ldap_pass.disabled = 1; - document.iform.ldap_version.disabled = 1; - document.iform.ldap_userattribute.disabled = 1; - document.iform.ldap_filter.disabled = 1; - document.iform.ldap_basedomain.disabled = 1; - document.iform.radius_secret.disabled = 0; - document.iform.msnt_secondary.disabled = 1; - document.iform.auth_ntdomain.disabled = 1; - break; - case 'msnt': - document.iform.auth_server.disabled = 0; - document.iform.auth_server_port.disabled = 1; - document.iform.auth_ntdomain.disabled = 0; - document.iform.ldap_user.disabled = 1; - document.iform.ldap_pass.disabled = 1; - document.iform.ldap_version.disabled = 1; - document.iform.ldap_userattribute.disabled = 1; - document.iform.ldap_filter.disabled = 1; - document.iform.ldap_basedomain.disabled = 1; - document.iform.radius_secret.disabled = 1; - document.iform.msnt_secondary.disabled = 0; - break; - case 'cp': - document.iform.auth_server.disabled = 1; - document.iform.auth_server_port.disabled = 1; - document.iform.auth_ntdomain.disabled = 1; - document.iform.ldap_user.disabled = 1; - document.iform.ldap_version.disabled = 1; - document.iform.ldap_userattribute.disabled = 1; - document.iform.ldap_filter.disabled = 1; - document.iform.ldap_pass.disabled = 1; - document.iform.ldap_basedomain.disabled = 1; - document.iform.radius_secret.disabled = 1; - document.iform.msnt_secondary.disabled = 1; - document.iform.auth_prompt.disabled = 1; - document.iform.auth_processes.disabled = 0; - document.iform.auth_ttl.disabled = 0; - document.iform.unrestricted_auth.disabled = 1; - document.iform.no_auth_hosts.disabled = 1; - break; - } -} ---> -</script> - -EOD; - } - - print($javascript); -} - -function squid_print_javascript_auth2() { - print("<script type=\"text/javascript\">on_auth_method_changed()</script>\n"); -} +/* + * Squid firewall rules configuration + */ function squid_generate_rules($type) { global $config, $pfs_version; @@ -2422,7 +1999,7 @@ function squid_generate_rules($type) { $port = ($settings['proxy_port'] ? $settings['proxy_port'] : 3128); $cp_inc = file($cp_file); $new_cp_inc = ""; - $found_rule=0; + $found_rule = 0; foreach ($cp_inc as $line) { $new_line = $line; //remove applied squid patch @@ -2444,13 +2021,20 @@ function squid_generate_rules($type) { if ($found_rule > 0) { file_put_contents($cp_file, $new_cp_inc, LOCK_EX); } + + // do not install any firewall rules if Squid is disabled + if (!squid_enabled()) { + log_error("[squid] Installed but disabled. Not installing '{$type}' rules."); + return; + } + // normal squid rule check if (($squid_conf['transparent_proxy'] != 'on') || ($squid_conf['allow_interface'] != 'on')) { return; } if (!is_service_running('squid')) { - log_error("Squid is installed but not started. Not installing \"{$type}\" rules."); + log_error("[squid] Installed but not started. Not installing '{$type}' rules."); return; } // Read assigned interfaces @@ -2460,13 +2044,13 @@ function squid_generate_rules($type) { $transparent_ifaces = explode(",", $squid_conf['transparent_active_interface']); $transparent_ifaces = array_map('convert_friendly_interface_to_real_interface_name', $transparent_ifaces); } else { - $transparent_ifaces=array(); + $transparent_ifaces = array(); } if ($squid_conf['ssl_proxy'] == "on") { $ssl_ifaces = explode(",", $squid_conf['ssl_active_interface']); $ssl_ifaces = array_map('convert_friendly_interface_to_real_interface_name', $ssl_ifaces); } else { - $ssl_ifaces=array(); + $ssl_ifaces = array(); } $port = ($squid_conf['proxy_port'] ? $squid_conf['proxy_port'] : 3128); @@ -2595,73 +2179,11 @@ function squid_generate_rules($type) { return $rules; } -function squid_write_rcfile() { - /* Declare a variable for the SQUID_CONFFILE constant. */ - /* Then the variable can be referenced easily in the heredoc text that generates the rc file. */ - $squid_conffile_var = SQUID_CONFFILE; - $squid_base = SQUID_BASE; - $rc = array(); - $rc['file'] = 'squid.sh'; - $rc['start'] = <<< EOD -#/sbin/sysctl net.inet.ip.portrange.reservedhigh=0 -if [ -z "`/bin/ps auxw | /usr/bin/grep "[s]quid " | /usr/bin/awk '{print $2}'`" ]; then - {$squid_base}/sbin/squid -f {$squid_conffile_var} -fi - -EOD; - - $rc['stop'] = <<< EOD -{$squid_base}/sbin/squid -k shutdown -f {$squid_conffile_var} -# Just to be sure... -sleep 5 -if [ -n "`/bin/ps auxw | /usr/bin/grep "[s]quid " | /usr/bin/awk '{print $2}'`" ]; then - {$squid_base}/sbin/squid -k kill -f {$squid_conffile_var} -fi - -if [ -x /usr/bin/ipcs ]; then -# http://man.chinaunix.net/newsoft/squid/Squid_FAQ/FAQ-22.html#ss22.8 -/usr/bin/ipcs | /usr/bin/grep '^[mq]' | /usr/bin/awk '{printf "ipcrm -%s %s\\n", $1, $2}' | /bin/sh -fi - -/usr/bin/killall -9 squid 2>/dev/null -/usr/bin/killall pinger 2>/dev/null - -EOD; - $rc['restart'] = <<< EOD -if [ -z "`ps auxw | /usr/bin/grep "[s]quid " | /usr/bin/awk '{print $2}'`" ]; then - {$squid_base}/sbin/squid -f {$squid_conffile_var} - else - {$squid_base}/sbin/squid -k reconfigure -f {$squid_conffile_var} - fi - -EOD; - conf_mount_rw(); - write_rcfile($rc); - // force delete the PBI initscript that keeps creeping back - unlink_if_exists("/usr/local/etc/rc.d/squid"); - conf_mount_ro(); -} - -function squid_write_cicap_rcfile() { - $c_icap_rcfile = "c-icap.sh"; - $cicap_libdir = SQUID_LOCALBASE . "/lib"; - $cicap_bin = SQUID_LOCALBASE . "/bin/c-icap"; - $cicap_conf = SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf"; - $cicap_start_cmd = "LD_LIBRARY_PATH={$cicap_libdir} {$cicap_bin} -f {$cicap_conf}"; - $cicap_stop_cmd = '/bin/echo -n "stop" > /var/run/c-icap/c-icap.ctl'; - conf_mount_rw(); - write_rcfile(array( - "file" => "{$c_icap_rcfile}", - "start" => "{$cicap_start_cmd}", - "stop" => "{$cicap_stop_cmd}" - ) - ); - // force delete the PBI initscript that keeps creeping back - unlink_if_exists("/usr/local/etc/rc.d/c-icap"); - conf_mount_ro(); -} +/* + * Squid XMLRPC sync + */ -/* Uses XMLRPC to synchronize the changes to a remote node */ +/* XMLRPC sync configuration */ function squid_sync_on_changes() { global $config, $g; if (is_array($config['installedpackages']['squidsync']['config'])) { @@ -2710,19 +2232,12 @@ function squid_sync_on_changes() { } } } -/* Do the actual XMLRPC sync */ + +/* Perform the actual XMLRPC sync */ function squid_do_xmlrpc_sync($sync_to_ip, $username, $password, $synctimeout) { global $config, $g; - if (!$username) { - return; - } - - if (!$password) { - return; - } - - if (!$sync_to_ip) { + if (!$username || !$password || !$sync_to_ip) { return; } @@ -2730,7 +2245,6 @@ function squid_do_xmlrpc_sync($sync_to_ip, $username, $password, $synctimeout) { $synctimeout = 250; } - $xmlrpc_sync_neighbor = $sync_to_ip; if ($config['system']['webgui']['protocol'] != "") { $synchronizetoip = $config['system']['webgui']['protocol']; @@ -2739,10 +2253,7 @@ function squid_do_xmlrpc_sync($sync_to_ip, $username, $password, $synctimeout) { $port = $config['system']['webgui']['port']; /* If port is empty let's rely on the protocol selection */ if ($port == "") { - if ($config['system']['webgui']['protocol'] == "http") - $port = "80"; - else - $port = "443"; + $port = $config['system']['webgui']['protocol'] == "http" ? "80" : "443"; } $synchronizetoip .= $sync_to_ip; @@ -2767,7 +2278,7 @@ function squid_do_xmlrpc_sync($sync_to_ip, $username, $password, $synctimeout) { /* Set a few variables needed for sync */ $url = $synchronizetoip; - log_error("[squid] Beginning Squid XMLRPC sync to {$url}:{$port}."); + log_error("[squid] Beginning XMLRPC sync to {$url}:{$port}."); $method = 'pfsense.merge_installedpackages_section_xmlrpc'; $msg = new XML_RPC_Message($method, $params); $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port); @@ -2778,13 +2289,13 @@ function squid_do_xmlrpc_sync($sync_to_ip, $username, $password, $synctimeout) { /* Send our XMLRPC message and timeout after defined sync timeout value*/ $resp = $cli->send($msg, $synctimeout); if (!$resp) { - $error = "A communication error occurred while attempting Squid XMLRPC sync with {$url}:{$port}."; + $error = "[squid] Communication error occurred while attempting XMLRPC sync with {$url}:{$port}."; log_error($error); file_notice("sync_settings", $error, "Squid Settings Sync", ""); } elseif ($resp->faultCode()) { $cli->setDebug(1); $resp = $cli->send($msg, $synctimeout); - $error = "An error code was received while attempting Squid XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); + $error = "[squid] An error code was received while attempting XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); log_error($error); file_notice("sync_settings", $error, "Squid Settings Sync", ""); } else { @@ -2807,17 +2318,17 @@ function squid_do_xmlrpc_sync($sync_to_ip, $username, $password, $synctimeout) { $cli->setCredentials($username, $password); $resp = $cli->send($msg, $synctimeout); if (!$resp) { - $error = "A communication error occurred while attempting Squid XMLRPC sync with {$url}:{$port} (pfsense.exec_php)."; + $error = "[squid] Communication error occurred while attempting XMLRPC sync with {$url}:{$port} (pfsense.exec_php)."; log_error($error); file_notice("sync_settings", $error, "Squid Settings Sync", ""); } elseif ($resp->faultCode()) { $cli->setDebug(1); $resp = $cli->send($msg, $synctimeout); - $error = "[Squid] An error code was received while attempting Squid XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); + $error = "[squid] An error code was received while attempting XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); log_error($error); file_notice("sync_settings", $error, "Squid Settings Sync", ""); } else { - log_error("Squid XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php)."); + log_error("[squid] XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php)."); } } diff --git a/config/squid3/34/squid.xml b/config/squid3/34/squid.xml index dda924f8..ccaca843 100644 --- a/config/squid3/34/squid.xml +++ b/config/squid3/34/squid.xml @@ -42,7 +42,7 @@ ]]> </copyright> <name>squid</name> - <version>0.3.7</version> + <version>0.3.9</version> <title>Proxy Server: General Settings</title> <include_file>/usr/local/pkg/squid.inc</include_file> <menu> @@ -65,7 +65,7 @@ </service> <service> <name>clamd</name> - <rcfile>clamav-clamd</rcfile> + <rcfile>clamd.sh</rcfile> <executable>clamd</executable> <description>ClamAV Antivirus</description> </service> @@ -125,6 +125,14 @@ </additional_files_needed> <additional_files_needed> <prefix>/usr/local/pkg/</prefix> + <item>https://packages.pfsense.org/packages/config/squid3/34/squid_antivirus.inc</item> + </additional_files_needed> + <additional_files_needed> + <prefix>/usr/local/pkg/</prefix> + <item>https://packages.pfsense.org/packages/config/squid3/34/squid_js.inc</item> + </additional_files_needed> + <additional_files_needed> + <prefix>/usr/local/pkg/</prefix> <item>https://packages.pfsense.org/packages/config/squid3/34/squid_reverse.inc</item> </additional_files_needed> <additional_files_needed> @@ -155,10 +163,6 @@ </additional_files_needed> <additional_files_needed> <prefix>/usr/local/pkg/</prefix> - <item>https://packages.pfsense.org/packages/config/squid3/34/squid_reverse.xml</item> - </additional_files_needed> - <additional_files_needed> - <prefix>/usr/local/pkg/</prefix> <item>https://packages.pfsense.org/packages/config/squid3/34/squid_reverse_general.xml</item> </additional_files_needed> <additional_files_needed> @@ -237,6 +241,29 @@ <type>listtopic</type> </field> <field> + <fielddescr>Enable Squid Proxy</fielddescr> + <fieldname>enable_squid</fieldname> + <description> + <![CDATA[ + Check to enable the Squid proxy.<br/> + Note: If unchecked, <strong>all</strong> Squid services will be disabled and stopped.<br/> + ]]> + </description> + <type>checkbox</type> + </field> + <field> + <fielddescr>Keep Settings/Data</fielddescr> + <fieldname>keep_squid_data</fieldname> + <description> + <![CDATA[ + If enabled, the settings, logs, cache, AV defs and other data will be preserved across package reinstalls.<br/> + <strong><span class="errmsg">Note:</span> If disabled, all settings and data will be wiped on package uninstall/reinstall/upgrade.</strong> + ]]> + </description> + <type>checkbox</type> + <default_value>on</default_value> + </field> + <field> <fielddescr>Proxy Interface(s)</fielddescr> <fieldname>active_interface</fieldname> <description> @@ -496,23 +523,23 @@ <type>listtopic</type> </field> <field> - <fielddescr>Enable Logging</fielddescr> + <fielddescr>Enable Access Logging</fielddescr> <fieldname>log_enabled</fieldname> <description> <![CDATA[ - This will enable the access log. + This will enable the <strong>access</strong> log. <strong>Warning:</strong> Do not switch this on if you don't have much disk space left. ]]> </description> <type>checkbox</type> - <enablefields>log_dir,log_rotate</enablefields> + <enablefields>log_rotate</enablefields> </field> <field> <fielddescr>Log Store Directory</fielddescr> <fieldname>log_dir</fieldname> <description> <![CDATA[ - The directory where the log will be stored.<br/> + The directory where the logs will be stored. This is also used for logs other than the Access Log above.<br/> Default: /var/squid/logs<br/> <strong>Note: Do NOT include the trailing / when setting a custom location.</strong> ]]> @@ -724,12 +751,7 @@ squid_resync(); </custom_php_resync_config_command> <custom_php_install_command> - <![CDATA[ - update_output_window("This operation may take quite some time, please be patient. Do not press stop or attempt to navigate away from this page during this process."); squid_install_command(); - unlink_if_exists("/usr/local/etc/rc.d/squid"); - unlink_if_exists("/usr/local/etc/rc.d/c-icap"); - ]]> </custom_php_install_command> <custom_php_deinstall_command> squid_deinstall_command(); diff --git a/config/squid3/34/squid_antivirus.inc b/config/squid3/34/squid_antivirus.inc new file mode 100644 index 00000000..e047db93 --- /dev/null +++ b/config/squid3/34/squid_antivirus.inc @@ -0,0 +1,797 @@ +<?php +/* + squid_antivirus.inc + part of pfSense (https://www.pfSense.org/) + Copyright (C) 2015 ESF, LLC + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +/* Functions for Squid C-ICAP/ClamAV integration */ +require_once('globals.inc'); +require_once('config.inc'); +/* This file is currently only being included in squid.inc and not used separately */ +// require_once('squid.inc'); + +/* + * Utility functions + */ + +/* clamav user account hadling (only needed for PBI/pfSense <2.3) */ +function squid_check_clamav_user($user) { + if (SQUID_BASE == '/usr/local') { + return; + } + + $_gc = exec("/usr/sbin/pw usershow {$user}", $sq_ex_output, $sq_ex_return); + $user_arg = ($sq_ex_return == 0 ? "mod" : "add"); + $_gc = exec("/usr/sbin/pw user{$user_arg} {$user} -G wheel -u 9595 -s /sbin/nologin", $sq_ex_output, $sq_ex_return); + if ($sq_ex_return != 0) { + log_error("[squid] Could not change clamav user settings. " . serialize($sq_ex_output)); + } +} + +/* Antivirus definitions updates via cron */ +function squid_install_freshclam_cron($should_install) { + global $config; + + if (platform_booting()) { + return; + } + + if (is_array($config['installedpackages']['squidantivirus'])) { + $antivirus_config = $config['installedpackages']['squidantivirus']['config'][0]; + } else { + $antivirus_config = array(); + } + + $freshclam_cmd = (SQUID_BASE . "/bin/freshclam --config-file=" . SQUID_BASE . "/etc/freshclam.conf"); + if (($should_install) && (squid_enabled())) { + if ($antivirus_config['clamav_update'] != "0") { + log_error("[squid] Adding freshclam cronjob."); + $minutes = ($antivirus_config['clamav_update'] * 60); + install_cron_job("{$freshclam_cmd}", true, "*/{$minutes}", "*", "*", "*", "*", "clamav"); + } else { + log_error("[squid] Removing freshclam cronjob."); + install_cron_job("{$freshclam_cmd}", false); + } + } else { + log_error("[squid] Removing freshclam cronjob."); + install_cron_job("{$freshclam_cmd}", false); + } +} + +/* Manually update ClamAV virus definitions via the GUI button */ +function squid_update_clamav() { + log_error("[squid] Updating ClamAV definitions now... This will take a while. Check /var/log/clamav/freshclam.log for progress information."); + mwexec_bg(SQUID_BASE . "/bin/freshclam --config-file=" . SQUID_BASE . "/etc/freshclam.conf"); +} + +/* + * Squid package install/uninstall + */ + +/* Run on Squid package install */ +function squid_antivirus_install_command() { + // antivirus rc scripts + squid_write_cicap_rcfile(); + squid_write_clamd_rcfile(); + + // antivirus config files + squid_antivirus_install_config_files(); + + // check squidclamav files until PBIs are gone (https://redmine.pfsense.org/issues/4197) + $ln_icap = array('bin/c-icap', 'bin/c-icap-client', 'c-icap-config', 'c-icap-libicapapi-config', 'c-icap-stretch', 'lib/c_icap', 'share/c_icap', 'etc/c-icap'); + foreach ($ln_icap as $ln) { + if (SQUID_LOCALBASE != '/usr/local' && !file_exists("/usr/local/{$ln}") && file_exists(SQUID_LOCALBASE . "/{$ln}")) { + symlink(SQUID_LOCALBASE . "/{$ln}", "/usr/local/{$ln}"); + } + } + if (SQUID_LOCALBASE != '/usr/local' && !file_exists("/usr/local/lib/libicapapi.so.3") && file_exists(SQUID_LOCALBASE . "/lib/libicapapi.so.3.0.5")) { + symlink(SQUID_LOCALBASE . "/lib/libicapapi.so.3.0.5", "/usr/local/lib/libicapapi.so.3"); + } + + // check dirs + $dirs = array( + "/var/run/c-icap" => "clamav", + "/var/log/c-icap" => "clamav", + "/var/log/clamav" => "clamav", + "/var/run/clamav" => "clamav", + "/var/db/clamav" => "clamav" + ); + foreach ($dirs as $dir_path => $dir_user) { + safe_mkdir($dir_path, 0755); + squid_chown_recursive($dir_path, $dir_user, "wheel"); + } + + // remove unwanted PBI rc scripts + unlink_if_exists("/usr/local/etc/rc.d/c-icap"); + unlink_if_exists("/usr/local/etc/rc.d/clamav-clamd"); + unlink_if_exists("/usr/local/etc/rc.d/clamav-freshclam"); +} + +/* Run on Squid package uninstall */ +function squid_antivirus_deinstall_command() { + /* kill all running services */ + if (is_process_running("c-icap")) { + mwexec('/bin/echo -n "stop" > /var/run/c-icap/c-icap.ctl'); + } + mwexec("/bin/ps awux | /usr/bin/grep '[c]lamd' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); + mwexec("/bin/ps awux | /usr/bin/grep '[f]reshclam' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); + + /* remove cronjobs */ + squid_install_freshclam_cron(false); + + /* delete rc scripts */ + unlink_if_exists('/usr/local/etc/rc.d/squid.sh'); + unlink_if_exists("/usr/local/etc/rc.d/c-icap.sh"); + unlink_if_exists('/usr/local/etc/rc.d/clamd.sh'); + + /* clean up created PBI symlinks */ + update_output_window("Finishing package cleanup."); + if (SQUID_LOCALBASE != '/usr/local') { + $ln_icap = array('bin/c-icap', 'bin/c-icap-client', 'c-icap-config', 'c-icap-libicapapi-config', 'c-icap-stretch', 'lib/c_icap', 'share/c_icap', 'etc/c-icap'); + foreach ($ln_icap as $ln) { + if (is_link("/usr/local/{$ln}")) { + unlink("/usr/local/{$ln}"); + } + } + if (is_link("/usr/local/lib/libicapapi.so.3")) { + unlink("/usr/local/lib/libicapapi.so.3"); + } + } + + /* clean up created directories if 'Keep Settings/Data' is disabled */ + if (is_array($config['installedpackages']['squid'])) { + $squidsettings = $config['installedpackages']['squid']['config'][0]; + } else { + $squidsettings = array(); + } + $keep = ($squidsettings['keep_squid_data'] ? true : false); + + if (!$keep) { + update_output_window("Removing antivirus definitions and logs ... One moment please..."); + $dirs = array("/var/run/c-icap", "/var/log/c-icap", "/var/log/clamav", "/var/run/clamav", "/var/db/clamav"); + foreach ($dirs as $dir) { + if (is_dir("{$dir}")) { + mwexec("/bin/rm -rf {$dir}"); + } + } + } + + /* check if clamav/c_icap is enabled in rc.conf.local */ + // XXX: This hasn't been used since 0.3.7; to be removed in future + if (file_exists("/etc/rc.conf.local")) { + update_output_window("Removing antivirus services from /etc/rc.conf.local..."); + $sample_file = file_get_contents("/etc/rc.conf.local"); + $rcconf_local_m[0] = "@c_icap_enable(.*)\n@"; + $rcconf_local_m[1] = "@clamav_clamd_enable(.*)\n@"; + $rcconf_local_r[0] = ""; + $rcconf_local_r[1] = ""; + file_put_contents("/etc/rc.conf.local", preg_replace($rcconf_local_m, $rcconf_local_r, $sample_file), LOCK_EX); + } +} + +/* + * Antivirus features configuration + * + * <file>.conf is the actual configuration file used for services. + * <file>.conf.pfsense is a template file patched for pfSense; should be never altered beyond initial install. + * <file>.conf.{sample,default} are templates distributed directly with PBI/package; + * If <file>.conf.default does not exist, a backup copy is made from another distributed files before patching it for pfSense. + * + * Configuration via the GUI options: + * <file>.conf is always (re)generated from the <file>.conf.pfsense on package resync, + * with additional patches depending on the GUI configuration options configured by user. + * Directly editing files via 'Advanced Features' is disabled in the GUI. + * + * Manual Configuration + * When the user enables 'Manual Configuration' for the first time, the config.xml settings are + * serialized from <file>.conf.pfsense template patched for pfSense. After this initial configuration, + * <file>.conf is always (re)generated from config.xml as long as 'Manual Configuration' is enabled in settings. + * In this case, any additional configuration made in the Antivirus GUI outside of 'Advanced Features' + * is unset on saving settings; after that, those options are disabled in the GUI and have no effect any more. + */ + +/* Proxy Server: Antivirus configuration handler */ +function squid_resync_antivirus() { + global $config; + + if (is_array($config['installedpackages']['squidantivirus'])) { + $antivirus_config = $config['installedpackages']['squidantivirus']['config'][0]; + } else { + $antivirus_config = array(); + } + + // squid.conf antivirus integration + if (squid_enabled() && ($antivirus_config['enable'] == "on")) { + switch ($antivirus_config['client_info']) { + case "both": + default: + $icap_send_client_ip = "on"; + $icap_send_client_username = "on"; + break; + case "ip": + $icap_send_client_ip = "on"; + $icap_send_client_username = "off"; + break; + case "username": + $icap_send_client_ip = "off"; + $icap_send_client_username = "on"; + break; + case "none": + $icap_send_client_ip = "off"; + $icap_send_client_username = "off"; + break; + } + + $conf = <<< EOF +icap_enable on +icap_send_client_ip {$icap_send_client_ip} +icap_send_client_username {$icap_send_client_username} +icap_client_username_encode off +icap_client_username_header X-Authenticated-User +icap_preview_enable on +icap_preview_size 1024 + +icap_service service_avi_req reqmod_precache icap://[::1]:1344/squid_clamav bypass=off +adaptation_access service_avi_req allow all +icap_service service_avi_resp respmod_precache icap://[::1]:1344/squid_clamav bypass=on +adaptation_access service_avi_resp allow all + +EOF; + + // check clamav user + squid_check_clamav_user('clamav'); + + if ($antivirus_config['enable_advanced'] == "enabled") { + // User is managing raw configuration, so we unset the configuration options set via GUI + squid_antivirus_toggle_raw_config(true); + // Generate the raw configuration if missing + $rawopts = array("raw_squidclamav_conf", "raw_cicap_conf", "raw_cicap_magic", "raw_freshclam_conf", "raw_clamd_conf"); + foreach ($rawopts as $rawopt) { + if ($antivirus_config[$rawopt] == "") { + squid_antivirus_get_raw_config(); + } + } + // Create configuration files + squid_antivirus_put_raw_config($config['installedpackages']['squidantivirus']['config'][0]); + } else { + // unset raw configuration options + squid_antivirus_toggle_raw_config(false); + + // patch sample files to pfsense dirs + // squidclamav.conf + $cf = SQUID_LOCALBASE . "/etc/c-icap/squidclamav.conf"; + if (file_exists("{$cf}.pfsense")) { + $sample_file = file_get_contents("{$cf}.pfsense"); + if ($antivirus_config['clamav_safebrowsing'] == "on") { + $squidclamav_m[0] = "@safebrowsing\s0@"; + $squidclamav_r[0] = "safebrowsing 1"; + } + if ($antivirus_config['clamav_url'] != "") { + $squidclamav_m[1] = "@redirect http@"; + $squidclamav_r[1] = "{$antivirus_config['clamav_url']}"; + } + file_put_contents("{$cf}", preg_replace($squidclamav_m, $squidclamav_r, $sample_file), LOCK_EX); + } else { + log_error("[squid] Template not found; could not generate '{$cf}' file!"); + } + + // c-icap.conf + $cf = SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf"; + if (file_exists("{$cf}.pfsense")) { + $sample_file = file_get_contents("{$cf}.pfsense"); + if (!preg_match("/squid_clamav/", $sample_file)) { + $sample_file .= "\nService squid_clamav squidclamav.so\n"; + } + // XXX: Bug #4615 + if (is_array($config['installedpackages']['squid'])) { + $squidsettings = $config['installedpackages']['squid']['config'][0]; + } else { + $squidsettings = array(); + } + $logdir = ($squidsettings['log_dir'] ? $squidsettings['log_dir'] : '/var/squid/logs'); + $cicap_m[0] = "@DebugLevel\s1@"; + $cicap_r[0] = "DebugLevel 0"; + $cicap_m[1] = "@AccessLog /var/squid/logs/c-icap-access.log@"; + $cicap_r[1] = "AccessLog {$logdir}/c-icap-access.log"; + $cicap_m[2] = "@ServerLog /var/squid/logs/c-icap-server.log@"; + $cicap_r[2] = "ServerLog {$logdir}/c-icap-server.log"; + file_put_contents("{$cf}", preg_replace($cicap_m, $cicap_r, $sample_file), LOCK_EX); + } else { + log_error("[squid] Template not found; could not generate '{$cf}' file!"); + } + + // c-icap.magic + // just make a copy of pfSense template, nothing configurable via GUI options here + $cf = SQUID_LOCALBASE . "/etc/c-icap/c-icap.magic"; + if (file_exists("{$cf}.pfsense")) { + copy("{$cf}.pfsense", "{$cf}"); + } else { + log_error("[squid] Template not found; could not generate '{$cf}' file!"); + } + + // freshclam.conf + $cf = SQUID_LOCALBASE . "/etc/freshclam.conf"; + if (file_exists("{$cf}.pfsense")) { + $sample_file = file_get_contents("{$cf}.pfsense"); + $clamav_mirrors = ""; + if ($antivirus_config['clamav_dbregion'] != "") { + $clamav_mirrors .= "DatabaseMirror db.{$antivirus_config['clamav_dbregion']}.clamav.net\n"; + } + if ($antivirus_config['clamav_dbservers'] != "") { + foreach (explode(";", $antivirus_config['clamav_dbservers']) as $dbserver) { + $clamav_mirrors .= "DatabaseMirror {$dbserver}\n"; + } + } + if ($clamav_mirrors != "") { + $freshclam_m[0] = "@#DatabaseMirror db.XY.clamav.net@"; + $freshclam_r[0] = "{$clamav_mirrors}"; + } + if ($antivirus_config['clamav_safebrowsing'] == "on") { + $freshclam_m[1] = "@#SafeBrowsing yes@"; + $freshclam_r[1] = "SafeBrowsing yes"; + } + file_put_contents("{$cf}", preg_replace($freshclam_m, $freshclam_r, $sample_file), LOCK_EX); + } else { + log_error("[squid] Template not found; could not generate '{$cf}' file!"); + } + + // clamd.conf + // just make a copy of pfSense template, nothing configurable via GUI options here + $cf = SQUID_LOCALBASE . "/etc/clamd.conf"; + if (file_exists("{$cf}.pfsense")) { + copy("{$cf}.pfsense", "{$cf}"); + } else { + log_error("[squid] Template not found; could not generate '{$cf}' file!"); + } + unset($cf); + } + + // freshclam cronjob + squid_install_freshclam_cron(true); + + } + // this will (re)start or stop/disable services as needed + // depending on whether Squid proxy and/or antivirus features are enabled + squid_restart_antivirus(); + + return $conf; +} + +/* Patch paths and settings in configuration files template for pfSense-specific values on install */ +function squid_antivirus_install_config_files() { + global $config; + if (is_array($config['installedpackages']['squid'])) { + $squidsettings = $config['installedpackages']['squid']['config'][0]; + } else { + $squidsettings = array(); + } + // squidclamav.conf + // there is no squidclamav.conf.sample packaged, use squidclamav.conf if really needed + $cf = SQUID_LOCALBASE . "/etc/c-icap/squidclamav.conf"; + if (!file_exists("{$cf}.default")) { + copy("{$cf}", "{$cf}.default"); + } + if (file_exists("{$cf}.default")) { + $sample_file = file_get_contents("{$cf}.default"); + $squidclamav_m[0] = "@# SquidClamav default configuration file@"; + $squidclamav_r[0] = "#This file was automatically generated by pfSense"; + $squidclamav_m[1] = "@/var/run/clamav/clamd.ctl@"; + $squidclamav_r[1] = "/var/run/clamav/clamd.sock"; + $squidclamav_m[2] = "@http\://proxy.domain.dom/cgi-bin/clwarn.cgi@"; + $squidclamav_r[2] = "{$config['system']['webgui']['protocol']}://{$config['system']['hostname']}.{$config['system']['domain']}/squid_clwarn.php"; + file_put_contents("{$cf}.pfsense", preg_replace($squidclamav_m, $squidclamav_r, $sample_file), LOCK_EX); + } else { + log_error("[squid] Could not patch '{$cf}' template file!"); + } + + // c-icap.conf + // there is no c-icap.conf.sample packaged, use c-icap.conf if really needed + $cf = SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf"; + if (!file_exists("{$cf}.default")) { + copy("{$cf}", "{$cf}.default"); + } + if (file_exists("{$cf}.default")) { + $sample_file = file_get_contents("{$cf}.default"); + if (!preg_match("/squid_clamav/", $sample_file)) { + $sample_file .= "\nService squid_clamav squidclamav.so\n"; + } + $cicap_m[0] = "@# This file contains the default settings for c-icap@"; + $cicap_r[0] = "#This file was automatically generated by pfSense"; + $cicap_m[1] = "@DebugLevel\s1@"; + $cicap_r[1] = "DebugLevel 0"; + $cicap_m[2] = "@AccessLog /var/log/c-icap/access.log@"; + $cicap_r[2] = "AccessLog /var/squid/logs/c-icap-access.log"; + $cicap_m[3] = "@ServerLog /var/log/c-icap/server.log@"; + $cicap_r[3] = "ServerLog /var/squid/logs/c-icap-server.log"; + file_put_contents("{$cf}.pfsense", preg_replace($cicap_m, $cicap_r, $sample_file), LOCK_EX); + } else { + log_error("[squid] Could not patch '{$cf}' template file!"); + } + + // c-icap.magic + // just make a backup and pfSense template copies of default c-icap.magic, we are not patching anything here + $cf = SQUID_LOCALBASE . "/etc/c-icap/c-icap.magic"; + if (!file_exists("{$cf}.default")) { + copy("{$cf}.sample", "{$cf}.default"); + } + if (!file_exists("{$cf}.pfsense")) { + copy("{$cf}.sample", "{$cf}.pfsense"); + } + + // clamd.conf + // make a backup of default clamd.conf.sample first + $cf = SQUID_LOCALBASE . "/etc/clamd.conf"; + if (!file_exists("{$cf}.default")) { + copy("{$cf}.sample", "{$cf}.default"); + } + if (file_exists("{$cf}.default")) { + $sample_file = file_get_contents("{$cf}.default"); + $clamd_m[0] = "@## Example config file for the Clam AV daemon@"; + $clamd_r[0] = "#This file was automatically generated by pfSense"; + $clamd_m[1] = "@# Comment or remove the line below.@"; + $clamd_r[1] = ""; + $clamd_m[2] = "@#Example@"; + $clamd_r[2] = ""; + file_put_contents("{$cf}.pfsense", preg_replace($clamd_m, $clamd_r, $sample_file), LOCK_EX); + } else { + log_error("[squid] Could not patch '{$cf}' template file!"); + } + + // freshclam.conf + // make a backup of default freshclam.conf.sample first + $cf = SQUID_LOCALBASE . "/etc/freshclam.conf"; + if (!file_exists("{$cf}.default")) { + copy("{$cf}.sample", "{$cf}.default"); + } + if (file_exists("{$cf}.default")) { + $sample_file = file_get_contents("{$cf}.default"); + $freshclam_m[0] = "@## Example config file for freshclam@"; + $freshclam_r[0] = "#This file was automatically generated by pfSense"; + $freshclam_m[1] = "@# Comment or remove the line below.@"; + $freshclam_r[1] = ""; + $freshclam_m[2] = "@#Example@"; + $freshclam_r[2] = ""; + file_put_contents("{$cf}.pfsense", preg_replace($freshclam_m, $freshclam_r, $sample_file), LOCK_EX); + } else { + log_error("[squid] - could not patch '{$cf}' template file!"); + } + unset($cf); +} + +/* Get the raw pfSense template files for manual configuration and serialize them to config.xml */ +function squid_antivirus_get_raw_config() { + global $config; + $loaded = false; + $rawfiles = array("squidclamav.conf", "c-icap.conf", "c-icap.magic", "freshclam.conf", "clamd.conf"); + + foreach ($rawfiles as $rawfile) { + switch ($rawfile) { + case 'squidclamav.conf': + $confdir = "/c-icap"; + $confopt = "raw_squidclamav_conf"; + break; + case 'c-icap.conf': + $confdir = "/c-icap"; + $confopt = "raw_cicap_conf"; + break; + case 'c-icap.magic': + $confdir = "/c-icap"; + $confopt = "raw_cicap_magic"; + break; + case 'freshclam.conf': + $confdir = ""; + $confopt = "raw_freshclam_conf"; + break; + case 'clamd.conf': + $confdir = ""; + $confopt = "raw_clamd_conf"; + break; + default: + $confdir = ""; + $confopt = ""; + break; + } + // get the config from the files if not set (yet) in config.xml + if ($confopt) { + $conffile = SQUID_LOCALBASE . "/etc" . "{$confdir}" . "/{$rawfile}.pfsense"; + if (file_exists($conffile)) { + if ($config['installedpackages']['squidantivirus']['config'][0][$confopt] == "") { + $config['installedpackages']['squidantivirus']['config'][0][$confopt] = base64_encode(str_replace("\r", "", file_get_contents("{$conffile}"))); + log_error("[squid] Successfully loaded '{$conffile}' configuration file"); + $loaded = true; + } + // Just a fallback attempt if people do things in weird order on a completely fresh install perhaps; should not be ever needed + } else { + squid_antivirus_install_config_files(); + if (file_exists($conffile)) { + $config['installedpackages']['squidantivirus']['config'][0][$confopt] = base64_encode(str_replace("\r", "", file_get_contents("{$conffile}"))); + log_error("[squid] Successfully loaded '{$conffile}' configuration file"); + $loaded = true; + } else { + log_error("[squid] '{$conffile}' template does not exist; could not load advanced {$rawfile} configuration!"); + } + } + } + } + if ($loaded) { + write_config("Squid - Loaded raw configuration files", false); + log_error("[squid] Successfully loaded raw configuration files"); + } +} + +/* Toggle the raw config state */ +function squid_antivirus_toggle_raw_config($state) { + global $config; + if ($state) { + // manual configuration enabled + $opts = array("clamav_url", "clamav_safebrowsing", "clamav_update", "clamav_dbregion", "clamav_dbservers"); + foreach ($opts as $opt) { + if (isset($config['installedpackages']['squidantivirus']['config'][0][$opt])) { + unset($config['installedpackages']['squidantivirus']['config'][0][$opt]); + log_error("[squid] Loaded '{$opt}' raw configuration file..."); + } + } + log_error("[squid] Loading raw configuration files..."); + squid_antivirus_get_raw_config(); + } else { + // manual configuration disabled + $opts = array("raw_squidclamav_conf", "raw_cicap_conf", "raw_cicap_magic", "raw_freshclam_conf", "raw_clamd_conf"); + foreach ($opts as $opt) { + if (isset($config['installedpackages']['squidantivirus']['config'][0][$opt])) { + unset($config['installedpackages']['squidantivirus']['config'][0][$opt]); + log_error("[squid] Unloaded '{$opt}' raw configuration."); + } + } + $config['installedpackages']['squidantivirus']['config'][0]['enable_advanced'] = "disabled"; + } +} + +/* Write the raw config files to disk from config.xml configuration */ +function squid_antivirus_put_raw_config($rawfiles) { + if (is_array($rawfiles)) { + foreach ($rawfiles as $rawfile => $rawconfig) { + switch ($rawfile) { + case 'raw_squidclamav_conf': + $confdir = "/c-icap"; + $conffile = "/squidclamav.conf"; + break; + case 'raw_cicap_conf': + $confdir = "/c-icap"; + $conffile = "/c-icap.conf"; + break; + case 'raw_cicap_magic': + $confdir = "/c-icap"; + $conffile = "/c-icap.magic"; + break; + case 'raw_freshclam_conf': + $confdir = ""; + $conffile = "freshclam.conf"; + break; + case 'raw_clamd_conf': + $confdir = ""; + $conffile = "clamd.conf"; + break; + default: + $confdir = ""; + $conffile = ""; + break; + } + if ($conffile && $rawconfig) { + squid_antivirus_write_conffile($confdir, $conffile, $rawconfig); + } + } + } +} + +/* Helper function for squid_antivirus_put_raw_config() */ +function squid_antivirus_write_conffile($dir, $file, $text) { + if ($file && $text) { + file_put_contents(SQUID_LOCALBASE . "/etc" . "{$dir}" . "/{$file}", preg_replace("/\r\n/", "\n", base64_decode($text)), LOCK_EX); + log_error("[squid] Saved '{$file}' configuration file."); + } +} + +/* + * rc scripts and services + */ + +/* Create clamd.sh rc script */ +function squid_write_clamd_rcfile() { + $squid_base = SQUID_BASE; + $rc = array(); + $rc['file'] = 'clamd.sh'; + $rc['start'] = <<< EOD + +if [ ! -f /var/db/clamav/main.cvd -a ! -f /var/db/clamav/main.cld ]; then + echo "Missing /var/db/clamav/*.cvd or *.cld files. You must run freshclam first" + exit 1 +fi + +{$squid_base}/bin/clamd --config-file="{$squid_base}/local/etc/clamd.conf" + +EOD; + + $rc['stop'] = <<< EOD + +/usr/bin/killall clamd 2>/dev/null +# Just to be sure... +sleep 5 +if [ -n "`/bin/ps auxw | /usr/bin/grep "[c]lamd" | /usr/bin/awk '{print $2}'`" ]; then + /usr/bin/killall -9 clamd 2>/dev/null +fi + +EOD; + + conf_mount_rw(); + write_rcfile($rc); + conf_mount_ro(); +} + +/* Create c-icap.sh rc script */ +function squid_write_cicap_rcfile() { + $c_icap_rcfile = "c-icap.sh"; + $cicap_libdir = SQUID_LOCALBASE . "/lib"; + $cicap_bin = SQUID_LOCALBASE . "/bin/c-icap"; + $cicap_conf = SQUID_LOCALBASE . "/etc/c-icap/c-icap.conf"; + $cicap_start_cmd = "LD_LIBRARY_PATH={$cicap_libdir} {$cicap_bin} -f {$cicap_conf}"; + $cicap_stop_cmd = '/bin/echo -n "stop" > /var/run/c-icap/c-icap.ctl'; + conf_mount_rw(); + write_rcfile(array( + "file" => "{$c_icap_rcfile}", + "start" => "{$cicap_start_cmd}", + "stop" => "{$cicap_stop_cmd}" + ) + ); + conf_mount_ro(); +} + +/* (Re)start antivirus services if AV features are enabled; otherwise stop and disable them */ +function squid_restart_antivirus() { + global $config; + if (is_array($config['installedpackages']['squidantivirus'])) { + $antivirus_config = $config['installedpackages']['squidantivirus']['config'][0]; + } else { + $antivirus_config = array(); + } + + // reconfigure and (re)start service as needed if enabled, otherwise stop them + // do not (re)start antivirus services on boot + if (platform_booting()) { + return; + } + + if (squid_enabled() && ($antivirus_config['enable'] == "on")) { + // Check clamav database + if (count(glob("/var/db/clamav/*d")) == 0) { + log_error("[squid] Missing /var/db/clamav/*.cvd or *.cld files. Running freshclam in background."); + mwexec_bg(SQUID_BASE . "/bin/freshclam --config-file=" . SQUID_BASE . "/etc/freshclam.conf"); + } elseif ($antivirus_config['clamav_safebrowsing'] == "on" && !is_file("/var/db/clamav/safebrowsing.cvd")) { + log_error("[squid] Google Safe Browsing is enabled but missing safebrowsing.cvd definitions. Running freshclam in background."); + mwexec_bg(SQUID_BASE . "/bin/freshclam --config-file=" . SQUID_BASE . "/etc/freshclam.conf"); + } elseif ($antivirus_config['clamav_safebrowsing'] != "on" && is_file("/var/db/clamav/safebrowsing.cvd")) { + log_error("[squid] Google Safe Browsing is disabled. Removing safebrowsing.cvd definitions."); + mwexec("/bin/rm -f /var/db/clamav/safebrowsing.cvd"); + } + + // start/reload clamav + $clamd_rcfile = "/usr/local/etc/rc.d/clamd.sh"; + if (!file_exists($clamd_rcfile)) { + squid_write_clamd_rcfile(); + } + if (is_process_running("clamd")) { + log_error("[squid] Reloading ClamAV..."); + $reload_cmd = SQUID_BASE . "/bin/clamdscan --reload"; + mwexec_bg("{$reload_cmd}"); + } else { + log_error("[squid] Starting ClamAV..."); + mwexec_bg("{$clamd_rcfile} start"); + } + + // check c-icap rcfile + $c_icap_rcfile = "/usr/local/etc/rc.d/c-icap.sh"; + if (!file_exists($c_icap_rcfile)) { + squid_write_cicap_rcfile(); + } + if (is_process_running("c-icap")) { + mwexec_bg('/bin/echo -n "reconfigure" > /var/run/c-icap/c-icap.ctl'); + } else { + mwexec_bg("{$c_icap_rcfile} start"); + } + } else { + // stop AV services and disable all C-ICAP/AV features + log_error("[squid] Antivirus features disabled."); + if (is_process_running("clamd")) { + log_error("[squid] Stopping and disabling ClamAV..."); + mwexec("/usr/bin/killall clamd"); + } + unlink_if_exists("/usr/local/etc/rc.d/clamd.sh"); + + // freshclam cronjob + squid_install_freshclam_cron(false); + + // check c-icap rcfile + if (is_process_running("c-icap")) { + log_error("[squid] Stopping and disabling C-ICAP..."); + mwexec('/bin/echo -n "stop" > /var/run/c-icap/c-icap.ctl'); + } + unlink_if_exists("/usr/local/etc/rc.d/c-icap.sh"); + } +} + +/* + * Input validation + */ + +/* Proxy server: Antivirus input validation */ +/* Also handles manual AV updates and switching 'Manual Configuration' on/off */ +function squid_validate_antivirus($post, &$input_errors) { + global $config; + if (is_array($config['installedpackages']['squidantivirus'])) { + $antivirus_config = $config['installedpackages']['squidantivirus']['config'][0]; + } else { + $antivirus_config = array(); + } + + /* Manual ClamAV database update */ + if ($post['update_av'] == 'Update AV') { + squid_update_clamav(); + return; + } + + /* Load the raw config files if manual configuration is enabled */ + if ($post['load_advanced'] == 'Load Advanced') { + $config['installedpackages']['squidantivirus']['config'][0]['enable_advanced'] = "enabled"; + squid_antivirus_toggle_raw_config(true); + return; + } + + if ($post['raw_squidclamav_conf'] && preg_match("/(\S+proxy.domain\S+)/", $post['raw_squidclamav_conf'], $a_match)) { + $input_errors[] = "SquidClamav warnings redirect points to sample config domain ({$a_match[1]})"; + $input_errors[] = "Change redirect info on 'squidclamav.conf' field to pfSense GUI or an external host."; + } + if ($post['raw_cicap_conf']) { + if (!preg_match("/squid_clamav/", $post['raw_cicap_conf'])) { + $input_errors[] = "c-icap Squidclamav service definition is not present."; + $input_errors[] = "Add 'Service squid_clamav squidclamav.so'(without quotes) to 'c-icap.conf' field in order to get it working."; + } + } + + if ($post['clamav_dbservers']) { + foreach (explode(";", $post['clamav_dbservers']) as $dbserver) { + $dbserver = trim($dbserver); + if (!empty($dbserver) && !is_ipaddr($dbserver) && !is_hostname($dbserver)) { + $input_errors[] = "'Optional ClamAV Database Update Servers' entry '$dbserver' is not a valid IP address or hostname."; + } + } + } + + if ($post['clamav_url']) { + if (!filter_var($post['clamav_url'], FILTER_VALIDATE_URL)) { + $input_errors[] = "'Redirect URL' is not a valid URL."; + } + } +} + +?> diff --git a/config/squid3/34/squid_antivirus.xml b/config/squid3/34/squid_antivirus.xml index a257891d..e7d046f0 100755 --- a/config/squid3/34/squid_antivirus.xml +++ b/config/squid3/34/squid_antivirus.xml @@ -42,7 +42,7 @@ ]]> </copyright> <name>squidantivirus</name> - <version>0.3.7</version> + <version>0.3.9</version> <title>Proxy server: Antivirus</title> <include_file>/usr/local/pkg/squid.inc</include_file> <tabs> @@ -88,6 +88,7 @@ <url>/pkg_edit.php?xml=squid_sync.xml</url> </tab> </tabs> + <advanced_options>enabled</advanced_options> <fields> <field> <name>ClamAV Anti-Virus Integration Using C-ICAP</name> @@ -117,6 +118,40 @@ </options> </field> <field> + <fielddescr>Enable Manual Configuration</fielddescr> + <fieldname>enable_advanced</fieldname> + <description> + <![CDATA[ + When enabled, the options below no longer have any effect.<br/> + You must edit the configuration files directly in the 'Advanced Features'.<br/> + <strong><span class="errmsg">Warning:</span> Only enable this if you know what are you doing.</strong><br/><br/> + After enabling manual configuration, click <input name='load_advanced' id='load_advanced' type='submit' value='Load Advanced' /> button once to load default configuration files. + To disable manual configuration again, select 'disabled' and click 'Save' button. + ]]> + </description> + <type>select</type> + <options> + <option><value>disabled</value><name>disabled</name></option> + <option><value>enabled</value><name>enabled</name></option> + </options> + <default_value>disabled</default_value> + <onchange>on_antivirus_advanced_config_changed()</onchange> + </field> + <field> + <fielddescr>Redirect URL</fielddescr> + <fieldname>clamav_url</fieldname> + <description> + <![CDATA[ + When a virus is found then redirect the user to this URL.<br /> + Leave empty to use the default Squid/pfSense WebGUI URL.<br/> + <strong>Example:</strong> http://proxy.example.com/blocked.html + ]]> + </description> + <type>input</type> + <cols>60</cols> + + </field> + <field> <fielddescr>Google Safe Browsing</fielddescr> <fieldname>clamav_safebrowsing</fieldname> <description> @@ -136,7 +171,7 @@ <![CDATA[ Optionally, you can schedule ClamAV definitions updates via cron.<br/> Select the desired frequency here.<br/><br/> - <input name='submit' type='submit' value='Update AV' /> + <input name='update_av' id='update_av' type='submit' value='Update AV' /> Click the button to update AV databases now.<br/> <strong>Note: This will take a while.</strong> Check /var/log/clamav/freshclam.log for progress information. ]]> @@ -195,53 +230,99 @@ </description> <type>input</type> <cols>60</cols> - <rows>5</rows> - </field> - <field> - <name>Advanced Options</name> - <type>listtopic</type> </field> <field> <fielddescr>squidclamav.conf</fielddescr> - <fieldname>squidclamav</fieldname> - <description>squidclamav.conf file. Leave empty to load sample file. Edit only if you know what are you doing.</description> + <fieldname>raw_squidclamav_conf</fieldname> + <description>squidclamav.conf file. Edit only if you know what are you doing.</description> <type>textarea</type> <encoding>base64</encoding> <cols>85</cols> <rows>15</rows> + <advancedfield/> </field> <field> <fielddescr>c-icap.conf</fielddescr> - <fieldname>c-icap_conf</fieldname> - <description>c-icap.conf file. Leave empty to load sample file. Edit only if you know what are you doing.</description> + <fieldname>raw_cicap_conf</fieldname> + <description>c-icap.conf file. Edit only if you know what are you doing.</description> <type>textarea</type> <encoding>base64</encoding> <cols>85</cols> <rows>15</rows> + <advancedfield/> </field> <field> <fielddescr>c-icap.magic</fielddescr> - <fieldname>c-icap_magic</fieldname> - <description>c-icap.conf file. Leave empty to load sample file. Edit only if you know what are you doing.</description> + <fieldname>raw_cicap_magic</fieldname> + <description>c-icap.conf file. Edit only if you know what are you doing.</description> <type>textarea</type> <encoding>base64</encoding> <cols>85</cols> <rows>15</rows> + <advancedfield/> </field> <field> <fielddescr>freshclam.conf</fielddescr> - <fieldname>freshclam_conf</fieldname> - <description>freshclam.conf file. Leave empty to load sample file. Edit only if you know what are you doing.</description> + <fieldname>raw_freshclam_conf</fieldname> + <description>freshclam.conf file. Edit only if you know what are you doing.</description> + <type>textarea</type> + <encoding>base64</encoding> + <cols>85</cols> + <rows>15</rows> + <advancedfield/> + </field> + <field> + <fielddescr>clamd.conf</fielddescr> + <fieldname>raw_clamd_conf</fieldname> + <description>clamd.conf file. Edit only if you know what are you doing.</description> <type>textarea</type> <encoding>base64</encoding> <cols>85</cols> <rows>15</rows> + <advancedfield/> </field> </fields> + <custom_php_after_head_command> + squid_print_antivirus_advanced_config(); + </custom_php_after_head_command> + <custom_php_before_form_command> + <![CDATA[ + squid_print_antivirus_advanced_config2(); + if ($_POST['enable_advanced'] == "enabled") { + $opts = array("clamav_url", "clamav_safebrowsing", "clamav_update", "clamav_dbregion", "clamav_dbservers"); + foreach ($opts as $opt) { + if (isset($_POST[$opt])) { + unset($_POST[$opt]); + } + } + } else { + $opts = array("raw_squidclamav_conf", "raw_cicap_conf", "raw_cicap_magic", "raw_freshclam_conf", "raw_clamd_conf"); + foreach ($opts as $opt) { + if (isset($_POST[$opt])) { + unset($_POST[$opt]); + } + } + } + ]]> + </custom_php_before_form_command> + <custom_php_after_form_command> + squid_print_antivirus_advanced_config2(); + </custom_php_after_form_command> <custom_php_validation_command> squid_validate_antivirus($_POST, $input_errors); </custom_php_validation_command> <custom_php_resync_config_command> + <![CDATA[ + if ($_POST['load_advanced'] == "Load Advanced" ) { + return; + } + if ($_POST['update_av'] == 'Update AV') { + return; + } + if ($_POST['enable_advanced'] == "enabled" ) { + squid_antivirus_put_raw_config($_POST); + } squid_resync(); + ]]> </custom_php_resync_config_command> </packagegui> diff --git a/config/squid3/34/squid_auth.xml b/config/squid3/34/squid_auth.xml index e2bae945..58a0bf12 100755 --- a/config/squid3/34/squid_auth.xml +++ b/config/squid3/34/squid_auth.xml @@ -127,7 +127,7 @@ ]]> </description> <type>input</type> - <size>60</size> + <size>5</size> </field> <field> <fielddescr>Authentication Prompt</fielddescr> @@ -135,6 +135,7 @@ <description>This string will be displayed at the top of the authentication request window.</description> <type>input</type> <default_value>Please enter your credentials to access the proxy</default_value> + <size>60</size> </field> <field> <fielddescr>Authentication Processes</fielddescr> diff --git a/config/squid3/34/squid_cache.xml b/config/squid3/34/squid_cache.xml index 2045005c..20f62376 100755 --- a/config/squid3/34/squid_cache.xml +++ b/config/squid3/34/squid_cache.xml @@ -168,7 +168,6 @@ ]]> </description> <type>checkbox</type> - <required/> </field> <field> <fielddescr>External Cache Managers</fielddescr> diff --git a/config/squid3/34/squid_js.inc b/config/squid3/34/squid_js.inc new file mode 100644 index 00000000..781b6710 --- /dev/null +++ b/config/squid3/34/squid_js.inc @@ -0,0 +1,273 @@ +<?php +/* + squid_js.inc + part of pfSense (https://www.pfSense.org/) + Copyright (C) 2015 ESF, LLC + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +/* + * Squid javascript helpers for GUI fields status manipulation + */ +require_once('globals.inc'); +require_once('config.inc'); + +/* + * Enable/disable and blank out various parts of the Authentication tab + * depending on selected 'Authentication Method' value + */ +function squid_print_javascript_auth() { + global $config; + if (is_array($config['installedpackages']['squid'])) { + $squidsettings = $config['installedpackages']['squid']['config'][0]; + } else { + $squidsettings = array(); + } + if (is_array($config['installedpackages']['squidauth']['config'])) { + $settingsauth = $config['installedpackages']['squidauth']['config'][0]; + } else { + $settingsauth = array(); + } + $transparent_proxy = ($squidsettings['transparent_proxy'] == 'on'); + $auth_method = $settingsauth['auth_method']; + + // No authentication for transparent proxy + if ($transparent_proxy and preg_match("/(local|ldap|radius|msnt|ntlm)/", $auth_method)) { + $javascript = <<< EOD +<script type="text/javascript"> +//<![CDATA[ +function on_auth_method_changed() { + document.iform.auth_method.disabled = 1; + document.iform.auth_server.disabled = 1; + document.iform.auth_ntdomain.disabled = 1; + document.iform.auth_server_port.disabled = 1; + document.iform.ldap_user.disabled = 1; + document.iform.ldap_version.disabled = 1; + document.iform.ldap_userattribute.disabled = 1; + document.iform.ldap_filter.disabled = 1; + document.iform.ldap_pass.disabled = 1; + document.iform.ldap_basedomain.disabled = 1; + document.iform.radius_secret.disabled = 1; + document.iform.msnt_secondary.disabled = 1; + document.iform.auth_prompt.disabled = 1; + document.iform.auth_processes.disabled = 1; + document.iform.auth_ttl.disabled = 1; + document.iform.unrestricted_auth.disabled = 1; + document.iform.no_auth_hosts.disabled = 1; +} +//]]> +</script> + +EOD; + + } else { + + $javascript = <<< EOD +<script type="text/javascript"> +//<![CDATA[ +function on_auth_method_changed() { + var field = document.iform.auth_method; + var auth_method = field.options[field.selectedIndex].value; + + if (auth_method == 'none') { + document.iform.auth_server.disabled = 1; + document.iform.auth_server_port.disabled = 1; + document.iform.auth_ntdomain.disabled = 1; + document.iform.ldap_user.disabled = 1; + document.iform.ldap_version.disabled = 1; + document.iform.ldap_userattribute.disabled = 1; + document.iform.ldap_filter.disabled = 1; + document.iform.ldap_pass.disabled = 1; + document.iform.ldap_basedomain.disabled = 1; + document.iform.radius_secret.disabled = 1; + document.iform.msnt_secondary.disabled = 1; + document.iform.auth_prompt.disabled = 1; + document.iform.auth_processes.disabled = 1; + document.iform.auth_ttl.disabled = 1; + document.iform.unrestricted_auth.disabled = 1; + document.iform.no_auth_hosts.disabled = 1; + } else { + document.iform.auth_prompt.disabled = 0; + document.iform.auth_processes.disabled = 0; + document.iform.auth_ttl.disabled = 0; + document.iform.unrestricted_auth.disabled = 0; + document.iform.no_auth_hosts.disabled = 0; + } + + switch (auth_method) { + case 'local': + document.iform.auth_server.disabled = 1; + document.iform.auth_server_port.disabled = 1; + document.iform.auth_ntdomain.disabled = 1; + document.iform.ldap_user.disabled = 1; + document.iform.ldap_pass.disabled = 1; + document.iform.ldap_version.disabled = 1; + document.iform.ldap_userattribute.disabled = 1; + document.iform.ldap_filter.disabled = 1; + document.iform.ldap_basedomain.disabled = 1; + document.iform.radius_secret.disabled = 1; + document.iform.msnt_secondary.disabled = 1; + break; + case 'ldap': + document.iform.auth_server.disabled = 0; + document.iform.auth_server_port.disabled = 0; + document.iform.ldap_user.disabled = 0; + document.iform.ldap_pass.disabled = 0; + document.iform.ldap_version.disabled = 0; + document.iform.ldap_userattribute.disabled = 0; + document.iform.ldap_filter.disabled = 0; + document.iform.ldap_basedomain.disabled = 0; + document.iform.radius_secret.disabled = 1; + document.iform.msnt_secondary.disabled = 1; + document.iform.auth_ntdomain.disabled = 1; + break; + case 'radius': + document.iform.auth_server.disabled = 0; + document.iform.auth_server_port.disabled = 0; + document.iform.ldap_user.disabled = 1; + document.iform.ldap_pass.disabled = 1; + document.iform.ldap_version.disabled = 1; + document.iform.ldap_userattribute.disabled = 1; + document.iform.ldap_filter.disabled = 1; + document.iform.ldap_basedomain.disabled = 1; + document.iform.radius_secret.disabled = 0; + document.iform.msnt_secondary.disabled = 1; + document.iform.auth_ntdomain.disabled = 1; + break; + case 'msnt': + document.iform.auth_server.disabled = 0; + document.iform.auth_server_port.disabled = 1; + document.iform.auth_ntdomain.disabled = 0; + document.iform.ldap_user.disabled = 1; + document.iform.ldap_pass.disabled = 1; + document.iform.ldap_version.disabled = 1; + document.iform.ldap_userattribute.disabled = 1; + document.iform.ldap_filter.disabled = 1; + document.iform.ldap_basedomain.disabled = 1; + document.iform.radius_secret.disabled = 1; + document.iform.msnt_secondary.disabled = 0; + break; + case 'cp': + document.iform.auth_server.disabled = 1; + document.iform.auth_server_port.disabled = 1; + document.iform.auth_ntdomain.disabled = 1; + document.iform.ldap_user.disabled = 1; + document.iform.ldap_version.disabled = 1; + document.iform.ldap_userattribute.disabled = 1; + document.iform.ldap_filter.disabled = 1; + document.iform.ldap_pass.disabled = 1; + document.iform.ldap_basedomain.disabled = 1; + document.iform.radius_secret.disabled = 1; + document.iform.msnt_secondary.disabled = 1; + document.iform.auth_prompt.disabled = 1; + document.iform.auth_processes.disabled = 0; + document.iform.auth_ttl.disabled = 0; + document.iform.unrestricted_auth.disabled = 1; + document.iform.no_auth_hosts.disabled = 1; + break; + } +} +//]]> +</script> + +EOD; + + } + print($javascript); +} + +/* onchange toggle helper for squid_print_javascript_auth() function */ +function squid_print_javascript_auth2() { + print("<script type=\"text/javascript\">on_auth_method_changed()</script>\n"); +} + +/* + * Enable/disable and blank out various parts of the Antivirus tab + * depending on selected 'Enable Manual Configuration' value + */ +function squid_print_antivirus_advanced_config() { + $javascript = <<< EOD +<script type="text/javascript"> +//<![CDATA[ +function on_antivirus_advanced_config_changed() { + var field = document.iform.enable_advanced; + var enable_advanced = field.options[field.selectedIndex].value; + + if (enable_advanced === 'disabled') { + document.iform['clamav_url'].disabled = 0; + document.iform['clamav_safebrowsing'].disabled = 0; + document.iform['clamav_update'].disabled = 0; + document.iform['clamav_dbregion'].disabled = 0; + document.iform['clamav_dbservers'].disabled = 0; + document.iform['clamav_dbservers'].disabled = 0; + document.iform['clamav_dbservers'].disabled = 0; + document.getElementById("load_advanced").disabled = 1; + document.iform['raw_squidclamav_conf'].disabled = 1; + document.iform['raw_squidclamav_conf'].value = ''; + document.iform['raw_cicap_conf'].disabled = 1; + document.iform['raw_cicap_conf'].value = ''; + document.iform['raw_cicap_magic'].disabled = 1; + document.iform['raw_cicap_magic'].value = ''; + document.iform['raw_freshclam_conf'].disabled = 1; + document.iform['raw_freshclam_conf'].value = ''; + document.iform['raw_clamd_conf'].disabled = 1; + document.iform['raw_clamd_conf'].value = ''; + } else { + document.iform['clamav_url'].disabled = 1; + document.iform['clamav_safebrowsing'].disabled = 1; + document.getElementById('clamav_safebrowsing').checked = 0; + document.iform['clamav_update'].disabled = 1; + document.getElementById("clamav_update").value = ''; + document.iform['clamav_dbregion'].disabled = 1; + document.getElementById("clamav_dbregion").value = ''; + document.iform['clamav_dbservers'].disabled = 1; + document.iform['clamav_dbservers'].value = ''; + document.getElementById("load_advanced").disabled = 0; + document.iform['raw_squidclamav_conf'].disabled = 0; + document.iform['raw_cicap_conf'].disabled = 0; + document.iform['raw_cicap_magic'].disabled = 0; + document.iform['raw_freshclam_conf'].disabled = 0; + document.iform['raw_clamd_conf'].disabled = 0; + + } + + if (document.getElementById("enable").checked == 0) { + document.getElementById("update_av").disabled = 1; + } else { + document.getElementById("update_av").disabled = 0; + } +} +//]]> +</script> + +EOD; + print($javascript); + +} + +/* onchange toggle helper for squid_print_antivirus_advanced_config() function */ +function squid_print_antivirus_advanced_config2() { + print("<script type=\"text/javascript\">on_antivirus_advanced_config_changed()</script>\n"); +} + +?> diff --git a/config/squid3/34/squid_reverse.inc b/config/squid3/34/squid_reverse.inc index 32c3fa65..d69d6a01 100755 --- a/config/squid3/34/squid_reverse.inc +++ b/config/squid3/34/squid_reverse.inc @@ -33,6 +33,7 @@ require_once('certs.inc'); /* This file is currently only being included in squid.inc and not used separately */ // require_once('squid.inc'); +/* Reverse Proxy Server configuration handler */ function squid_resync_reverse() { global $config; @@ -262,4 +263,74 @@ function squid_resync_reverse() { return $conf; } +/* Reverse Proxy Server input validation */ +function squid_validate_reverse($post, &$input_errors) { + global $config; + + if (!empty($post['reverse_ip'])) { + $reverse_ip = explode(";", ($post['reverse_ip'])); + foreach ($reverse_ip as $reip) { + if (!is_ipaddr(trim($reip))) { + $input_errors[] = "You must enter a valid IP address in the 'User-defined reverse-proxy IPs' field. '$reip' is invalid."; + } + } + } + + $fqdn = trim($post['reverse_external_fqdn']); + if (!empty($fqdn) && !is_domain($fqdn)) { + $input_errors[] = "'External FQDN' field must contain a valid domain name."; + } + + $port = trim($post['reverse_http_port']); + preg_match("/(\d+)/", shell_exec("/sbin/sysctl net.inet.ip.portrange.reservedhigh"), $portrange); + if (!empty($port) && !is_port($port)) { + $input_errors[] = "'Reverse HTTP port' must contain a valid port number."; + } + if (!empty($port) && is_port($port) && $port <= $portrange[1]) { + $input_errors[] = "'Reverse HTTP port' must contain a port number higher than net.inet.ip.portrange.reservedhigh sysctl value({$portrange[1]})."; + $input_errors[] = "To listen on low ports, change portrange.reservedhigh sysctl value to 0 in system tunable options and restart Squid daemon."; + } + $port = trim($post['reverse_https_port']); + if (!empty($port) && !is_port($port)) { + $input_errors[] = "'Reverse HTTPS port' must contain a valid port number."; + } + if (!empty($port) && is_port($port) && $port <= $portrange[1]) { + $input_errors[] = "'Reverse HTTPS port' must contain a port number higher than net.inet.ip.portrange.reservedhigh sysctl value({$portrange[1]})."; + $input_errors[] = "To listen on low ports, change portrange.reservedhigh sysctl value to 0 in system tunable options and restart Squid daemon."; + } + if ($post['reverse_ssl_cert'] == 'none') { + $input_errors[] = 'A valid certificate for the external interface must be selected'; + } + + if (($post['reverse_https'] != 'on') && ($post['reverse_owa'] == 'on')) { + $input_errors[] = "You have to enable reverse HTTPS before enabling OWA support."; + } + + if (!empty($post['reverse_owa_ip'])) { + $reverse_owa_ip = explode(";", ($post['reverse_owa_ip'])); + foreach ($reverse_owa_ip as $reowaip) { + if (!is_ipaddr(trim($reowaip))) { + $input_errors[] = "You must enter a valid IP address in the 'CAS-Array / OWA frontend IP address' field. '$reowaip' is invalid."; + } + } + } + + $contents = $post['reverse_cache_peer']; + if (!empty($contents)) { + $defs = explode("\r\n", ($contents)); + foreach ($defs as $def) { + $cfg = explode(";", ($def)); + if (!is_ipaddr($cfg[1])) { + $input_errors[] = "Please choose a valid IP in the cache peer configuration."; + } + if (!is_port($cfg[2])) { + $input_errors[] = "Please choose a valid port in the cache peer configuration."; + } + if (($cfg[3] != 'HTTPS') && ($cfg[3] != 'HTTP')) { + $input_errors[] = "Please choose HTTP or HTTPS in the cache peer configuration."; + } + } + } +} + ?> diff --git a/config/squid3/34/squid_reverse.xml b/config/squid3/34/squid_reverse.xml deleted file mode 100755 index 3617debc..00000000 --- a/config/squid3/34/squid_reverse.xml +++ /dev/null @@ -1,451 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> -<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> -<packagegui> - <copyright> -<![CDATA[ -/* $Id$ */ -/* ====================================================================================== */ -/* - squid_reverse.xml - part of pfSense (https://www.pfSense.org/) - Copyright (C) 2012-2014 Marcello Coutinho - Copyright (C) 2015 ESF, LLC - All rights reserved. -*/ -/* ====================================================================================== */ -/* - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ -/* ====================================================================================== */ - ]]> - </copyright> - <name>squidreverse</name> - <version>0.3.5</version> - <title>Proxy Server: Reverse Proxy</title> - <include_file>/usr/local/pkg/squid.inc</include_file> - <tabs> - <tab> - <text>General</text> - <url>/pkg_edit.php?xml=squid.xml&id=0</url> - </tab> - <tab> - <text>Upstream</text> - <url>/pkg_edit.php?xml=squid_upstream.xml&id=0</url> - </tab> - <tab> - <text>Cache</text> - <url>/pkg_edit.php?xml=squid_cache.xml&id=0</url> - </tab> - <tab> - <text>ACLs</text> - <url>/pkg_edit.php?xml=squid_nac.xml&id=0</url> - </tab> - <tab> - <text>Traffic Mgmt</text> - <url>/pkg_edit.php?xml=squid_traffic.xml&id=0</url> - </tab> - <tab> - <text>Reverse</text> - <url>/pkg_edit.php?xml=squid_reverse.xml&id=0</url> - <active/> - </tab> - <tab> - <text>Authentication</text> - <url>/pkg_edit.php?xml=squid_auth.xml&id=0</url> - </tab> - <tab> - <text>Users</text> - <url>/pkg.php?xml=squid_users.xml</url> - </tab> - <tab> - <text>Real Time</text> - <url>/squid_monitor.php</url> - </tab> - <tab> - <text>Sync</text> - <url>/pkg_edit.php?xml=squid_sync.xml</url> - </tab> - </tabs> - <fields> - <field> - <name>Squid Reverse Proxy General Settings</name> - <type>listtopic</type> - </field> - <field> - <fielddescr>Reverse Proxy Interface</fielddescr> - <fieldname>reverse_interface</fieldname> - <description> - <![CDATA[ - The interface(s) the reverse-proxy server will bind to.<br/> - Use CTRL + click to select multiple interfaces. - ]]> - </description> - <type>interfaces_selection</type> - <required/> - <default_value>wan</default_value> - <multiple/> - </field> - <field> - <fielddescr>User Defined Reverse Proxy IPs</fielddescr> - <fieldname>reverse_ip</fieldname> - <description> - <![CDATA[ - Squid will additionally bind to these user-defined IPs for reverse proxy operation. Useful for virtual IPs such as CARP.<br/> - <strong>Note: Separate entries by semi-colons (;)</strong> - ]]> - </description> - <type>input</type> - <size>70</size> - </field> - <field> - <fielddescr>External FQDN</fielddescr> - <fieldname>reverse_external_fqdn</fieldname> - <description>The external fully qualified domain name of the WAN IP address.</description> - <type>input</type> - <required/> - <size>70</size> - </field> - <field> - <fielddescr>Reset TCP Connections on Unauthorized Requests</fielddescr> - <fieldname>deny_info_tcp_reset</fieldname> - <description>If checked, the reverse proxy will reset the TCP connection if the request is unauthorized.</description> - <type>checkbox</type> - <default_value>on</default_value> - </field> - <field> - <name>Squid Reverse HTTP Settings</name> - <type>listtopic</type> - </field> - <field> - <fielddescr>Enable HTTP Reverse Mode</fielddescr> - <fieldname>reverse_http</fieldname> - <description> - <![CDATA[ - If checked, the proxy server will act in HTTP reverse mode.<br/> - <strong>Note: You must add a proper firewall rule with destination 'WAN Address'.</strong> - ]]> - </description> - <type>checkbox</type> - <enablefields>reverse_http_port,reverse_http_defsite</enablefields> - <required/> - <default_value>off</default_value> - </field> - <field> - <fielddescr>Reverse HTTP Port</fielddescr> - <fieldname>reverse_http_port</fieldname> - <description> - <![CDATA[ - This is the port the HTTP reverse proxy will listen on. Default value will be used if left empty.<br/> - Default: 80 - ]]> - </description> - <type>input</type> - <size>5</size> - <default_value>80</default_value> - </field> - <field> - <fielddescr>Reverse HTTP Default Site</fielddescr> - <fieldname>reverse_http_defsite</fieldname> - <description> - <![CDATA[ - This is the HTTP reverse proxy default site.<br/> - Note: Leave empty to use 'External FQDN' value specified above. - ]]> - </description> - <type>input</type> - <size>60</size> - </field> - <field> - <name>Squid Reverse HTTPS Settings</name> - <type>listtopic</type> - </field> - <field> - <fielddescr>Enable HTTPS Reverse Proxy</fielddescr> - <fieldname>reverse_https</fieldname> - <description> - <![CDATA[ - If checked, the proxy server will act in HTTPS reverse mode.<br/> - <strong>Note: You must add a proper firewall rule with destination 'WAN Address'.</strong> - ]]> - </description> - <type>checkbox</type> - <enablefields>reverse_https_port,reverse_https_defsite,reverse_ssl_cert,reverse_int_ca,reverse_ignore_ssl_valid,reverse_owa,reverse_owa_ip,reverse_owa_webservice,reverse_owa_activesync,reverse_owa_rpchttp,reverse_owa_mapihttp,reverse_owa_autodiscover,reverse_ssl_chain</enablefields> - <required/> - <default_value>off</default_value> - </field> - <field> - <fielddescr>Reverse HTTPS Port</fielddescr> - <fieldname>reverse_https_port</fieldname> - <description> - <![CDATA[ - This is the port the HTTPS reverse proxy will listen on. Default value will be used if left empty.<br/> - Default: 443 - ]]> - </description> - <type>input</type> - <size>5</size> - <default_value>443</default_value> - </field> - <field> - <fielddescr>Reverse HTTPS Default Site</fielddescr> - <fieldname>reverse_https_defsite</fieldname> - <description> - <![CDATA[ - This is the HTTPS reverse proxy default site.<br/> - Note: Leave empty to use 'External FQDN' value specified above. - ]]> - </description> - <type>input</type> - <size>60</size> - </field> - <field> - <fielddescr>Reverse SSL Certificate</fielddescr> - <fieldname>reverse_ssl_cert</fieldname> - <description>Choose the SSL Server Certificate here.</description> - <type>select_source</type> - <source>$config['cert']</source> - <source_name>descr</source_name> - <source_value>refid</source_value> - </field> - <field> - <fielddescr>Intermediate CA Certificate (If Needed)</fielddescr> - <fieldname>reverse_int_ca</fieldname> - <description> - <![CDATA[ - Paste a signed certificate in X.509 <strong>PEM format</strong> here. - ]]> - </description> - <type>textarea</type> - <cols>75</cols> - <rows>5</rows> - <encoding>base64</encoding> - </field> - <field> - <fielddescr>Ignore Internal Certificate Validation</fielddescr> - <fieldname>reverse_ignore_ssl_valid</fieldname> - <description>If checked, internal certificate validation will be ignored.</description> - <type>checkbox</type> - <default_value>on</default_value> - </field> - <field> - <name>OWA Reverse Proxy General Settings</name> - <type>listtopic</type> - </field> - <field> - <fielddescr>Enable OWA Reverse Proxy</fielddescr> - <fieldname>reverse_owa</fieldname> - <description>If checked, Squid will act as an accelerator/SSL offloader for Outlook Web App.</description> - <type>checkbox</type> - <enablefields>reverse_owa_ip,reverse_owa_activesync,reverse_owa_rpchttp,reverse_owa_mapihttp,reverse_owa_webservice,reverse_owa_autodiscover</enablefields> - </field> - <field> - <fielddescr>CAS-Array / OWA Frontend IP Address</fielddescr> - <fieldname>reverse_owa_ip</fieldname> - <description> - <![CDATA[ - These are the internal IPs of the CAS-Array (OWA frontend servers).<br/> - <strong>Note: Separate entries by semi-colons (;)</strong> - ]]> - </description> - <type>input</type> - <size>70</size> - </field> - <field> - <fielddescr>Enable ActiveSync</fielddescr> - <fieldname>reverse_owa_activesync</fieldname> - <description>If checked, ActiveSync will be enabled.</description> - <type>checkbox</type> - </field> - <field> - <fielddescr>Enable Outlook Anywhere</fielddescr> - <fieldname>reverse_owa_rpchttp</fieldname> - <description>If checked, RPC over HTTP will be enabled.</description> - <type>checkbox</type> - </field> - <field> - <fielddescr>Enable MAPI HTTP</fielddescr> - <fieldname>reverse_owa_mapihttp</fieldname> - <description> - <![CDATA[ - If checked, MAPI over HTTP will be enabled.<br/> - <strong>This feature is only available with at least Microsoft Exchange 2013 SP1</strong> - ]]> - </description> - <type>checkbox</type> - </field> - <field> - <fielddescr>Enable Exchange WebServices</fielddescr> - <fieldname>reverse_owa_webservice</fieldname> - <description> - <![CDATA[ - If checked, Exchange WebServices will be enabled.<br/> - <strong>There are potential DoS side effects to its use. Please avoid unless really required.</strong> - ]]> - </description> - <type>checkbox</type> - </field> - <field> - <fielddescr>Enable AutoDiscover</fielddescr> - <fieldname>reverse_owa_autodiscover</fieldname> - <description> - <![CDATA[ - If checked, AutoDiscover will be enabled.<br/> - <strong>You also should set up the autodiscover DNS record to point to you WAN IP.</strong> - ]]> - </description> - <type>checkbox</type> - </field> - <field> - <name>Squid Reverse Mappings</name> - <type>listtopic</type> - </field> - <field> - <fielddescr> - <![CDATA[ - Peer Definitions<br/> - Publishing Hosts - ]]> - </fielddescr> - <fieldname>reverse_cache_peer</fieldname> - <description> - <![CDATA[ - Enter each peer definition on a new line. Directives have to be separated by a semicolon(;).<br/><br/> - Syntax: [peer alias];[internal ip address];[port];[HTTP/HTTPS]<br/> - Example: HOST1;192.168.0.1;80;HTTP<br/> - <strong><span class="errmsg">WARNING:</span> Wrong syntax usage will result in Squid not starting!</strong> - ]]> - </description> - <type>textarea</type> - <cols>60</cols> - <rows>10</rows> - <encoding>base64</encoding> - </field> - <field> - <fielddescr> - <![CDATA[ - URI Definitions<br/> - Published URIs - ]]> - </fielddescr> - <fieldname>reverse_uri</fieldname> - <description> - <![CDATA[ - Enter each reverse ACL definition on a separate line. Directives have to be separated by a semicolon(;)<br/><br/> - Syntax: [group the uri belongs to];[URI to publish](;[vhost fqdn])<br/> - Example: URI1;public;server.example.com<br/><br/> - Notes:<br/> - - A group can contain multiple URIs<br/> - - If [vhost fqdn] is ommited, 'External FQDN' is used<br/> - - You also can specify http:// or https://<br/><br/> - <strong><span class="errmsg">WARNING:</span> Wrong syntax usage will result in Squid not starting!</strong> - ]]> - </description> - <type>textarea</type> - <cols>60</cols> - <rows>10</rows> - <encoding>base64</encoding> - </field> - <field> - <fielddescr> - <![CDATA[ - ACL Definitions<br/> - Published URIs - ]]> - </fielddescr> - <fieldname>reverse_acl</fieldname> - <description> - <![CDATA[ - Enter each reverse ACL definition on a new line. Directives have to be separated by a semicolon(;)<br/> - Syntax: [peer alias];[uri group alias]<br/> - Example: HOST1;URI1<br/> - <strong><span class="errmsg">WARNING:</span> Wrong syntax usage will result in Squid not starting!</strong> - ]]> - </description> - <type>textarea</type> - <cols>60</cols> - <rows>10</rows> - <encoding>base64</encoding> - </field> - <!-- - <field> - <fielddescr>Internal Hosts</fielddescr> - <type>rowhelper</type> - <rowhelper> - <rowhelperfield> - <fielddescr>IP Address</fielddescr> - <fieldname>reverse_cache_peer_ip</fieldname> - <type>input</type> - <size>15</size> - </rowhelperfield> - <rowhelperfield> - <fielddescr>Protocol</fielddescr> - <fieldname>reverse_cache_peer_proto</fieldname> - <type>select</type> - <options> - <option><name>HTTP</name><value>HTTP</value></option> - <option><name>HTTPS</name><value>HTTPS</value></option> - </options> - </rowhelperfield> - <rowhelperfield> - <fielddescr>Port</fielddescr> - <fieldname>reverse_cache_peer_port</fieldname> - <type>input</type> - <size>5</size> - </rowhelperfield> - <rowhelperfield> - <fielddescr>Peer Name</fielddescr> - <fieldname>reverse_cache_peer_name</fieldname> - <type>input</type> - <size>25</size> - </rowhelperfield> - </rowhelper> - </field> - <field> - <fielddescr>Published URI</fielddescr> - <type>rowhelper</type> - <rowhelper> - <rowhelperfield> - <fielddescr>URI</fielddescr> - <fieldname>reverse_cache_peer_uri</fieldname> - <type>input</type> - <size>50</size> - </rowhelperfield> - <rowhelperfield> - <fielddescr>Peer Name</fielddescr> - <fieldname>reverse_cache_peer</fieldname> - <type>input</type> - <size>25</size> - </rowhelperfield> - </rowhelper> - </field> - --> - </fields> - <custom_php_validation_command> - squid_validate_reverse($_POST, $input_errors); - </custom_php_validation_command> - <custom_php_resync_config_command> - squid_resync(); - </custom_php_resync_config_command> -</packagegui> diff --git a/config/squid3/34/squid_reverse_general.xml b/config/squid3/34/squid_reverse_general.xml index 19c504f1..90babcd0 100755 --- a/config/squid3/34/squid_reverse_general.xml +++ b/config/squid3/34/squid_reverse_general.xml @@ -42,7 +42,7 @@ ]]> </copyright> <name>squidreversegeneral</name> - <version>0.3.5</version> + <version>0.3.8</version> <title>Reverse Proxy Server: General</title> <include_file>/usr/local/pkg/squid.inc</include_file> <tabs> @@ -303,7 +303,12 @@ </field> </fields> <custom_php_validation_command> + <![CDATA[ + if (!empty($_POST) && !squid_enabled()) { + $input_errors[] = "Squid is disabled. You must enable Squid proxy under Services - Squid Proxy Server - General."; + } squid_validate_reverse($_POST, $input_errors); + ]]> </custom_php_validation_command> <custom_php_resync_config_command> squid_resync(); diff --git a/config/squid3/34/squid_traffic.xml b/config/squid3/34/squid_traffic.xml index ac86770f..bd01bbb7 100755 --- a/config/squid3/34/squid_traffic.xml +++ b/config/squid3/34/squid_traffic.xml @@ -217,6 +217,7 @@ <fieldname>quick_abort_max</fieldname> <description>If the transfer has more than x KB remaining, it will abort the retrieval.</description> <type>input</type> + <size>10</size> <default_value>0</default_value> </field> <field> diff --git a/config/squid3/34/squid_users.xml b/config/squid3/34/squid_users.xml index f67db48e..c47395b9 100755 --- a/config/squid3/34/squid_users.xml +++ b/config/squid3/34/squid_users.xml @@ -111,6 +111,7 @@ <description>Enter the username here.</description> <type>input</type> <required/> + <size>20</size> </field> <field> <fielddescr>Password</fielddescr> @@ -118,12 +119,14 @@ <description>Enter the password here.</description> <type>password</type> <required/> + <size>20</size> </field> <field> <fielddescr>Description</fielddescr> <fieldname>description</fieldname> <description>You may enter a description here for your reference (not parsed).</description> <type>input</type> + <size>60</size> </field> </fields> <custom_php_resync_config_command> diff --git a/pkg_config.10.xml b/pkg_config.10.xml index f84ff6b5..6c43bf58 100644 --- a/pkg_config.10.xml +++ b/pkg_config.10.xml @@ -395,7 +395,7 @@ </build_pbi> <build_options>barnyard2_UNSET_FORCE=ODBC PGSQL PRELUDE;barnyard2_SET_FORCE=GRE IPV6 MPLS MYSQL PORT_PCAP BRO;snort_SET_FORCE=BARNYARD PERFPROFILE SOURCEFIRE GRE IPV6 NORMALIZER APPID;snort_UNSET_FORCE=PULLEDPORK FILEINSPECT HA</build_options> <config_file>https://packages.pfsense.org/packages/config/snort/snort.xml</config_file> - <version>3.2.8.1</version> + <version>3.2.8.2</version> <required_version>2.2</required_version> <status>Stable</status> <configurationfile>/snort.xml</configurationfile> @@ -1052,7 +1052,7 @@ <pkginfolink>https://forum.pfsense.org/index.php/topic,48347.0.html</pkginfolink> <website>http://www.squid-cache.org/</website> <category>Network</category> - <version>0.3.7</version> + <version>0.3.9</version> <status>beta</status> <required_version>2.2</required_version> <maintainer>marcellocoutinho@gmail.com fernando@netfilter.com.br seth.mos@dds.nl mfuchs77@googlemail.com jimp@pfsense.org</maintainer> diff --git a/pkg_config.8.xml b/pkg_config.8.xml index 79860bb5..5abf5f5d 100644 --- a/pkg_config.8.xml +++ b/pkg_config.8.xml @@ -1110,7 +1110,7 @@ <descr>High performance web proxy cache.</descr> <website>http://www.squid-cache.org/</website> <category>Network</category> - <version>2.7.9 pkg v.4.3.10</version> + <version>2.7.9 pkg v.4.3.11</version> <status>Stable</status> <required_version>2</required_version> <maintainer>fernando@netfilter.com.br seth.mos@dds.nl mfuchs77@googlemail.com jimp@pfsense.org</maintainer> |