# Copyright (C) 2008-2014 Zentyal S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use strict; use warnings; package EBox::Squid; use base qw( EBox::FirewallObserver EBox::LogObserver EBox::NetworkObserver ); use EBox::Global; if (EBox::Global->modExists('samba')) { require EBox::Module::Kerberos; push (@EBox::Squid::ISA, 'EBox::Module::Kerberos'); } else { require EBox::Module::Service; push (@EBox::Squid::ISA, 'EBox::Module::Service'); } use EBox::Service; use EBox::Config; use EBox::Firewall; use EBox::Validate qw( :all ); use EBox::Exceptions::InvalidData; use EBox::Exceptions::Internal; use EBox::Exceptions::External; use EBox::Exceptions::DataNotFound; use EBox::Exceptions::MissingArgument; use EBox::Exceptions::Sudo::Command; use EBox::Squid::Firewall; use EBox::Squid::LogHelper; use EBox::Squid::LdapUserImplementation; use EBox::Squid::Types::ListArchive; use EBox::DBEngineFactory; use EBox::Dashboard::Value; use EBox::Dashboard::Section; use EBox::Menu::Item; use EBox::Menu::Folder; use EBox::Sudo; use EBox::Gettext; use EBox::Util::Version; use EBox; use TryCatch; use HTML::Mason; use File::Basename; use EBox::NetWrappers qw(to_network_with_mask); # Module local conf stuff use constant SQUID_CONF_FILE => '/etc/squid/squid.conf'; use constant E2GDIR => '/etc/e2guardian'; use constant DEFAULT_PORT => '3128'; use constant PROXYPORT_FILTER => '3129'; use constant CHMOD_DIRMODE => '750'; use constant CHMOD_FILEMODE => '640'; use constant SQUIDCSSFILE => '/etc/squid/errorpage.css'; use constant MAXDOMAINSIZ => 255; use constant E2GLISTSDIR => E2GDIR . '/lists'; use constant E2G_LOGROTATE_CONF => '/etc/logrotate.d/e2guardian'; use constant CLAMD_SCANNER_CONF_FILE => E2GDIR . '/contentscanners/clamdscan.conf'; use constant KEYTAB_FILE => '/etc/squid/HTTP.keytab'; use constant SQUID_DEFAULT_FILE => '/etc/default/squid'; use constant CRONFILE => '/etc/cron.d/zentyal-squid'; use constant SQUID_ZCONF_FILE => '/etc/zentyal/squid.conf'; sub _create { my $class = shift; my $self = $class->SUPER::_create(name => 'squid', printableName => __('HTTP Proxy'), @_); $self->{logger} = EBox::logger(); bless ($self, $class); return $self; } sub _kerberosServicePrincipals { return [ 'HTTP' ]; } sub _kerberosKeytab { return { path => KEYTAB_FILE, user => 'root', group => 'proxy', mode => '440', }; } # Method: initialSetup # # Overrides: # EBox::Module::Base::initialSetup # sub initialSetup { my ($self, $version) = @_; $self->SUPER::initialSetup($version); unless ($version) { # Create default rules only if installing the first time # Allow clients to browse Internet by default $self->model('AccessRules')->add(source => { any => undef }, policy => { allow => undef }); } # Setting the right permissions for e2guardian my @cmds; push (@cmds, 'chown -R e2guardian:e2guardian '. E2GDIR); push (@cmds, 'find '. E2GDIR .' -type d -exec chmod '. CHMOD_DIRMODE .' {} +'); push (@cmds, 'find '. E2GDIR .' -type f -exec chmod '. CHMOD_FILEMODE .' {} +'); EBox::info('changing permissions'); EBox::Sudo::root(@cmds); foreach my $name ('squid', 'logs') { my $mod = $self->global()->modInstance($name); if ($mod and $mod->changed()) { $mod->saveConfigRecursive(); } } } sub setupLDAP { my ($self) = @_; my $netbiosName = $self->global()->modInstance('samba')->model('DomainSettings')->value('netbiosName'); EBox::Sudo::root("samba-tool group addmembers 'Domain Admins' zentyal-squid-$netbiosName"); } # Method: usedFiles # # Override EBox::Module::Service::usedFiles # sub usedFiles { return [ { 'file' => SQUID_CONF_FILE, 'module' => 'squid', 'reason' => __('Front HTTP Proxy configuration file') }, { 'file' => E2GDIR . '/e2guardian.conf', 'module' => 'squid', 'reason' => __('Content filter configuration file') }, { 'file' => E2GDIR . '/e2guardianf1.conf', 'module' => 'squid', 'reason' => __('Default filter group configuration') }, { 'file' => E2GDIR . '/common.story', 'module' => 'squid', 'reason' => __('Default filter group configuration') }, { 'file' => E2GLISTSDIR . '/filtergroupslist', 'module' => 'squid', 'reason' => __('Filter groups membership') }, { 'file' => E2GLISTSDIR . '/bannedextensionlist', 'module' => 'squid', 'reason' => __('Content filter banned extension list') }, { 'file' => E2GLISTSDIR . '/bannedmimetypelist', 'module' => 'squid', 'reason' => __('Content filter banned mime type list') }, { 'file' => E2GLISTSDIR . '/exceptionsitelist', 'module' => 'squid', 'reason' => __('Content filter exception site list') }, { 'file' => E2GLISTSDIR . '/greysitelist', 'module' => 'squid', 'reason' => __('Content filter grey site list') }, { 'file' => E2GLISTSDIR . '/bannedsitelist', 'module' => 'squid', 'reason' => __('Content filter banned site list') }, { 'file' => E2GLISTSDIR . '/exceptionurllist', 'module' => 'squid', 'reason' => __('Content filter exception URL list') }, { 'file' => E2GLISTSDIR . '/greyurllist', 'module' => 'squid', 'reason' => __('Content filter grey URL list') }, { 'file' => E2GLISTSDIR . '/bannedurllist', 'module' => 'squid', 'reason' => __('Content filter banned URL list') }, { 'file' => E2GLISTSDIR . '/bannedphraselist', 'module' => 'squid', 'reason' => __('Forbidden phrases list'), }, { 'file' => E2GLISTSDIR . '/exceptionphraselist', 'module' => 'squid', 'reason' => __('Exception phrases list'), }, # # obsolete https://github.com/e2guardian/e2guardian/issues/125 # { # 'file' => E2GLISTSDIR . '/pics', # 'module' => 'squid', # 'reason' => __('PICS ratings configuration'), # }, { 'file' => E2G_LOGROTATE_CONF, 'module' => 'squid', 'reason' => __(q{E2guardian's log rotation configuration}), }, { 'file' => CLAMD_SCANNER_CONF_FILE, 'module' => 'squid', 'reason' => __(q{E"guardian's antivirus scanner configuration}), }, { 'file' => E2GLISTSDIR . '/authplugins/ipgroups', 'module' => 'squid', 'reason' => __('Filter groups per IP'), }, { 'file' => SQUID_DEFAULT_FILE, 'module' => 'squid', 'reason' => __('Set the kerberos keytab path'), }, { 'file' => KEYTAB_FILE, 'module' => 'squid', 'reason' => __('Extract the service principal key'), } ]; } # Method: actions # # Override EBox::Module::Service::actions # sub actions { return [ { 'action' => __('Overwrite blocked page templates'), 'reason' => __('E2guardian blocked page templates will be overwritten with Zentyal' . ' customized templates.'), 'module' => 'squid' }, { 'action' => __('Override squid upstart job'), 'reason' => __('Zentyal will take care of starting and stopping ' . 'the services.'), 'module' => 'squid' }, { 'action' => __('Remove e2guardian init script link'), 'reason' => __('Zentyal will take care of starting and stopping ' . 'the services.'), 'module' => 'squid' } ]; } sub enableService { my ($self, $status) = @_; if ($status) { my @ifaces = @{ $self->global()->modInstance('network')->ExternalIfaces() }; if (not @ifaces) { throw EBox::Exceptions::External( __('To enable the HTTP proxy module, you need to have a least one external network interface') ); } } $self->SUPER::enableService($status); } sub _cache_mem { my $cache_mem = EBox::Config::configkey('cache_mem'); ($cache_mem) or throw EBox::Exceptions::External(__('You must set the '. 'cache_mem variable in the Zentyal configuration file')); return $cache_mem; } sub _max_object_size { my $max_object_size = EBox::Config::configkey('maximum_object_size'); ($max_object_size) or throw EBox::Exceptions::External(__('You must set the '. 'max_object_size variable in the Zentyal configuration file')); return $max_object_size; } # Method: transproxy # # Returns if the transparent proxy mode is enabled # # Returns: # # boolean - true if enabled, otherwise undef # sub transproxy { my ($self) = @_; return $self->model('GeneralSettings')->value('transparentProxy'); } # Method: setPort # # Sets the listening port for the proxy # # Parameters: # # port - string: port number # sub setPort { my ($self, $port) = @_; $self->model('GeneralSettings')->setValue('port', $port); } # Method: port # # Returns the listening port for the proxy # # Returns: # # string - port number # sub port { my ($self) = @_; my $port = $self->model('GeneralSettings')->value('port'); unless (defined($port) and ($port =~ /^\d+$/)) { return DEFAULT_PORT; } return $port; } # Function: banThreshold # # Gets the weighted phrase value that will cause a page to be banned. # # Returns: # # A positive integer with the current ban threshold. # sub banThreshold { my ($self) = @_; my $model = $self->model('ContentFilterThreshold'); return $model->contentFilterThresholdValue(); } sub filterNeeded { my ($self) = @_; unless ($self->isEnabled()) { return 0; } my $rules = $self->model('AccessRules'); if ($rules->rulesUseFilter()) { return 1; } return 0; } sub authNeeded { my ($self) = @_; unless ($self->isEnabled()) { return 0; } my $rules = $self->model('AccessRules'); return $rules->rulesUseAuth(); } sub kerberosNeeded { my ($self) = @_; unless ($self->isEnabled()) { return 0; } my $global = $self->global(); if ($global->communityEdition()) { return 0; } my $samba = $global->modInstance('samba'); unless ($samba and $samba->isEnabled()) { return 0; } my $settings = $self->model('GeneralSettings'); if ($settings->kerberosValue()) { return 1; } } sub httpsBlockNeeded { my ($self) = @_; unless ($self->isEnabled()) { return 0; } if ($self->global()->communityEdition()) { return 0; } my $rules = $self->model('AccessRules'); if ($rules->rulesUseHTTPS()) { return 1; } } # Function: usesPort # # Implements EBox::FirewallObserver interface # sub usesPort { my ($self, $protocol, $port, $iface) = @_; ($protocol eq 'tcp') or return undef; # PROXYPORT_FILTER is hard-coded, they are reported as used even # if the services are disabled. ($port eq PROXYPORT_FILTER) and return 1; # the port selected by the user (by default DEFAULT_PORT) is only reported # if the service is enabled ($self->isEnabled()) or return undef; ($port eq $self->port()) and return 1; return undef; } sub _enforceServiceState { my ($self, @params) = @_; # We stop override this to stop first due to the listen port changes $self->_stopService(@params); if($self->isEnabled()) { $self->_startService(@params); } } sub _setConf { my ($self) = @_; my $filter = $self->filterNeeded(); $self->_writeDefaultConf(); $self->_writeSquidConf($filter); $self->writeConfFile(SQUIDCSSFILE, 'squid/errorpage.css', []); if ($filter) { $self->_writeE2gConf(); } EBox::Squid::Types::ListArchive->commitAllPendingRemovals(); } sub revokeConfig { my ($self) = @_; $self->SUPER::revokeConfig(); EBox::Squid::Types::ListArchive->revokeAllPendingRemovals(); } sub _antivirusNeeded { my ($self, $profiles_r) = @_; my $global = $self->global(); return 0 unless $global->modExists('antivirus'); return 0 unless $global->modInstance('antivirus')->isEnabled(); if (not $profiles_r) { my $profiles = $self->model('FilterProfiles'); return $profiles->antivirusNeeded(); } foreach my $profile (@{ $profiles_r }) { if ($profile->{antivirus}) { return 1; } } return 0; } sub notifyAntivirusEnabled { my ($self, $enabled) = @_; $self->filterNeeded() or return; $self->setAsChanged(); } sub _writeDefaultConf { my ($self) = @_; my $vars = []; push (@{$vars}, 'keytab' => KEYTAB_FILE); $self->writeConfFile(SQUID_DEFAULT_FILE, 'squid/squid.default.mas', $vars, { mode => '0644'}); } sub _writeSquidConf { my ($self, $filter) = @_; my $accesRulesModel = $self->model('AccessRules'); my $rules = $accesRulesModel->rules(); my $squidFilterProfiles = $accesRulesModel->squidFilterProfiles(); my $generalSettings = $self->model('GeneralSettings'); my $global = $self->global(); my $sysinfo = $global->modInstance('sysinfo'); my $network = $global->modInstance('network'); my $users = $global->modInstance('samba'); my $kerberos = $self->kerberosNeeded(); my $krbRealm = ($users and $kerberos) ? $users->kerberosRealm() : ''; my $krbPrincipal = 'HTTP/' . $sysinfo->hostName() . '.' . $sysinfo->hostDomain(); my @writeParam = (); push @writeParam, ('port' => $filter ? PROXYPORT_FILTER : $self->port()); if ($self->transproxy() and not $filter) { push @writeParam, ('mode' => 'intercept'); } push @writeParam, ('rules' => $rules); push @writeParam, ('filterProfiles' => $squidFilterProfiles); push @writeParam, ('hostfqdn' => $sysinfo->fqdn()); push @writeParam, ('auth' => $self->authNeeded()); push @writeParam, ('principal' => $krbPrincipal); push @writeParam, ('realm' => $krbRealm); if ($users and $users->isEnabled() and $users->isProvisioned()) { push @writeParam, ('dn' => $users->ldap()->dn()); push @writeParam, ('roDn' => $self->_kerberosServiceAccountDN()); push @writeParam, ('roPasswd' => $self->_kerberosServiceAccountPassword()); } my $append_domain = $network->model('SearchDomain')->domainValue(); push (@writeParam, append_domain => $append_domain); push (@writeParam, memory => $self->_cache_mem()); push (@writeParam, max_object_size => $self->_max_object_size()); my $cacheDirSize = $generalSettings->cacheDirSizeValue(); push (@writeParam, cacheDirSize => $cacheDirSize); push (@writeParam, nameservers => $network->nameservers()); my $cache_host = $network->model('Proxy')->serverValue(); my $cache_port = $network->model('Proxy')->portValue(); my $cache_user = $network->model('Proxy')->usernameValue(); my $cache_passwd = $network->model('Proxy')->passwordValue(); push (@writeParam, cache_host => $cache_host); push (@writeParam, cache_port => $cache_port); push (@writeParam, cache_user => $cache_user); push (@writeParam, cache_passwd => $cache_passwd); push (@writeParam, notCachedDomains => $self->_notCachedDomains()); push (@writeParam, objectsDelayPools => $self->_objectsDelayPools()); $self->writeConfFile(SQUID_CONF_FILE, 'squid/squid.conf.mas', \@writeParam, { mode => '0640'}); if (EBox::Config::boolean('debug')) { $self->_checkSquidFile(SQUID_CONF_FILE); } } sub _checkSquidFile { my ($self, $confFile) = @_; try { EBox::Sudo::root("squid -k parse $confFile"); } catch (EBox::Exceptions::Command $e) { my $error = join ' ', @{ $e->error() }; throw EBox::Exceptions::Internal("Error in squid configuration file $confFile: $error"); } } sub _objectsDelayPools { my ($self) = @_; my @delayPools = @{$self->model('DelayPools')->delayPools()}; return \@delayPools; } sub _writeE2gConf { my ($self) = @_; # FIXME - get a proper lang name for the current locale my $lang = $self->_E2GLang(); my @e2gProfiles = @{ $self->_e2gProfiles }; my @writeParam = (); push(@writeParam, 'port' => $self->port()); push(@writeParam, 'lang' => $lang); push(@writeParam, 'squidport' => PROXYPORT_FILTER); push(@writeParam, 'weightedPhraseThreshold' => $self->_banThresholdActive); push(@writeParam, 'nGroups' => scalar @e2gProfiles); push(@writeParam, 'auth' => $self->authNeeded()); my $antivirus = $self->_antivirusNeeded(\@e2gProfiles); push(@writeParam, 'antivirus' => $antivirus); my $maxchildren = EBox::Config::configkey('maxchildren'); push(@writeParam, 'maxchildren' => $maxchildren); my $minchildren = EBox::Config::configkey('minchildren'); push(@writeParam, 'minchildren' => $minchildren); my $minsparechildren = EBox::Config::configkey('minsparechildren'); push(@writeParam, 'minsparechildren' => $minsparechildren); my $preforkchildren = EBox::Config::configkey('preforkchildren'); push(@writeParam, 'preforkchildren' => $preforkchildren); my $maxsparechildren = EBox::Config::configkey('maxsparechildren'); push(@writeParam, 'maxsparechildren' => $maxsparechildren); my $maxagechildren = EBox::Config::configkey('maxagechildren'); push(@writeParam, 'maxagechildren' => $maxagechildren); $self->writeConfFile(E2GDIR . '/e2guardian.conf', 'squid/e2guardian.conf.mas', \@writeParam, { mode => '0644'}); # disable banned, exception phrases lists, regex URLs and PICS ratings $self->writeConfFile(E2GLISTSDIR . '/bannedphraselist', 'squid/bannedphraselist.mas', [], { mode => '0644'}); $self->writeConfFile(E2GLISTSDIR . '/exceptionphraselist', 'squid/exceptionphraselist.mas', [], { mode => '0644'}); $self->writeConfFile(E2GLISTSDIR . '/pics', 'squid/pics.mas', [], { mode => '0644'}); $self->writeConfFile(E2GLISTSDIR . '/bannedregexpurllist', 'squid/bannedregexpurllist.mas', [], { mode => '0644'}); $self->writeE2gGroups(); if ($antivirus) { my $avMod = $self->global()->modInstance('antivirus'); $self->writeConfFile(CLAMD_SCANNER_CONF_FILE, 'squid/clamdscan.conf.mas', [ clamdSocket => $avMod->localSocket() ]); } foreach my $group (@e2gProfiles) { my $number = $group->{number}; my $policy = $group->{policy}; @writeParam = (); push(@writeParam, 'group' => $number); push(@writeParam, 'policy' => $policy); push(@writeParam, 'antivirus' => $group->{antivirus}); push(@writeParam, 'threshold' => $group->{threshold}); push(@writeParam, 'groupName' => $group->{groupName}); push(@writeParam, 'defaults' => $group->{defaults}); EBox::Module::Base::writeConfFileNoCheck(E2GDIR . "/e2guardianf$number.conf", 'squid/e2guardianfN.conf.mas', \@writeParam, { mode => '0644'}); if ($policy eq 'filter') { $self->_writeE2gDomainsConf($group); } if (not exists $group->{defaults}->{bannedextensionlist}) { @writeParam = (); push(@writeParam, 'extensions' => $group->{bannedExtensions}); EBox::Module::Base::writeConfFileNoCheck(E2GLISTSDIR . "/bannedextensionlist", 'squid/bannedextensionlist.mas', \@writeParam); } if (not exists $group->{defaults}->{bannedmimetypelist}) { @writeParam = (); push(@writeParam, 'mimeTypes' => $group->{bannedMIMETypes}); EBox::Module::Base::writeConfFileNoCheck(E2GLISTSDIR . "/bannedmimetypelist", 'squid/bannedmimetypelist.mas', \@writeParam); } } $self->_writeCronFile(); $self->_writeE2gTemplates(); $self->writeConfFile(E2G_LOGROTATE_CONF, 'squid/e2guardian.logrotate', []); } sub _writeCronFile { my ($self) = @_; my $times; my @cronTimes; my $rules = $self->model('AccessRules'); foreach my $profile (@{$rules->filterProfiles()}) { next unless $profile->{usesFilter} and $profile->{timePeriod}; if ($profile->{policy} eq 'deny') { # this is managed in squid, we don't need to rewrite E2G files for it next; } foreach my $day (keys %{$profile->{days}}) { my @times; # if the profile only has days, we change it at new day (00:00) push @times, $profile->{begin} ? $profile->{begin} : '00:00'; if ($profile->{end}) { push @times, $profile->{end}; } foreach my $time (@times) { unless (exists $times->{$time}) { $times->{$time} = {}; } $times->{$time}->{$day} = 1; } } } foreach my $time (keys %{$times}) { my ($hour, $min) = split (':', $time); my $days = join (',', sort (keys %{$times->{$time}})); push (@cronTimes, { days => $days, hour => $hour, min => $min }); } $self->writeConfFile(CRONFILE, 'squid/zentyal-squid.cron.mas', [ times => \@cronTimes ]); } sub writeE2gGroups { my ($self) = @_; my $rules = $self->model('AccessRules'); my @profiles = @{$rules->filterProfiles()}; my @groups; my @objects; my $anyAddressProfileSeen; my (undef, $min, $hour, undef, undef, undef, $day) = localtime(); foreach my $profile (@profiles) { if ($profile->{policy} eq 'deny') { # this is stopped in squid, nothing to do next; } if ($profile->{timePeriod}) { unless ($profile->{days}->{$day}) { next; } if ($profile->{begin}) { my ($beginHour, $beginMin) = split (':', $profile->{begin}); if ($hour < $beginHour) { next; } elsif (($hour == $beginHour) and ($min < $beginMin)) { next; } } if ($profile->{end}) { my ($endHour, $endMin) = split (':', $profile->{end}); if ($hour > $endHour) { next; } elsif (($hour == $endHour) and ($min >= $endMin)) { next; } } } if ($profile->{anyAddress}) { if ($anyAddressProfileSeen) { next; } $anyAddressProfileSeen = 1; push @objects, $profile; } elsif ($profile->{group}) { push (@groups, $profile); } else { push (@objects, $profile); } } my $realm = ''; if ($self->kerberosNeeded()) { my $samba = $self->global()->modInstance('samba'); $realm = '@' . $samba->kerberosRealm(); } my @writeParams = (); push (@writeParams, groups => \@groups); push (@writeParams, realm => $realm); $self->writeConfFile(E2GLISTSDIR . '/filtergroupslist', 'squid/filtergroupslist.mas', \@writeParams, { mode => '0644'}); $self->writeConfFile(E2GLISTSDIR . '/authplugins/ipgroups', 'squid/ipgroups.mas', [ objects => \@objects ], { mode => '0644'}); } sub _writeE2gTemplates { my ($self) = @_; my $lang = $self->_E2GLang(); my $file = E2GDIR . '/languages/' . $lang . '/template.html'; my $extra_messages = ''; my $edition = $self->global()->edition(); if (($edition eq 'community') or ($edition eq 'basic')) { $extra_messages = __sx('This is a Community Edition. Get one of the fully supported {oh}Commercial Editions{ch} for automatic security updates.', oh => '', ch => ''); } EBox::Module::Base::writeConfFileNoCheck($file, 'squid/template.html.mas', [ extra_messages => $extra_messages, image_name => "zentyal-$edition.png", ]); } sub _banThresholdActive { my ($self) = @_; my @e2gProfiles = @{ $self->_e2gProfiles }; foreach my $group (@e2gProfiles) { if ($group->{threshold} > 0) { return 1; } } return 0; } sub _notCachedDomains { my ($self) = @_; my $model = $self->model('NoCacheDomains'); return $model->notCachedDomains(); } sub _e2gProfiles { my ($self) = @_; my $profileModel = $self->model('FilterProfiles'); return $profileModel->e2gProfiles(); } sub _writeE2gDomainsConf { my ($self, $group) = @_; my $number = $group->{number}; my @domainsFiles = ('bannedsitelist', 'exceptionsitelist', 'exceptionurllist'); foreach my $file (@domainsFiles) { next if (exists $group->{defaults}->{$file}); my $path = E2GLISTSDIR . '/' . $file . $number; my $template = "squid/$file.mas"; EBox::Module::Base::writeConfFileNoCheck($path, $template, $group->{$file}); } } sub firewallHelper { my ($self) = @_; my $ro = $self->isReadOnly(); if ($self->isEnabled()) { return new EBox::Squid::Firewall(ro => $ro); } return undef; } # Method: menu # # Overrides EBox::Module method. # # sub menu { my ($self, $root) = @_; my $folder = new EBox::Menu::Folder('name' => 'Squid', 'icon' => 'squid', 'text' => $self->printableName(), 'order' => 500); $folder->add(new EBox::Menu::Item('url' => 'Squid/Composite/General', 'text' => __('General Settings'))); $folder->add(new EBox::Menu::Item('url' => 'Squid/View/AccessRules', 'text' => __(q{Access Rules}))); $folder->add(new EBox::Menu::Item('url' => 'Squid/View/FilterProfiles', 'text' => __(q{Filter Profiles}))); $folder->add(new EBox::Menu::Item('url' => 'Squid/View/CategorizedLists', 'text' => __(q{Categorized Lists}))); $folder->add(new EBox::Menu::Item('url' => 'Squid/View/DelayPools', 'text' => __(q{Bandwidth Throttling}))); $root->add($folder); } # Method: _daemons # # Overrides # sub _daemons { return [ { name => 'squid' }, { name => 'e2guardian', precondition => \&filterNeeded }, ]; } # Impelment LogHelper interface sub tableInfo { my ($self) = @_; my $titles = { 'timestamp' => __('Date'), 'remotehost' => __('Host'), 'rfc931' => __('User'), 'url' => __('URL'), 'domain' => __('Domain'), 'bytes' => __('Bytes'), 'mimetype' => __('Mime/type'), 'event' => __('Event') }; my @order = ( 'timestamp', 'remotehost', 'rfc931', 'url', 'domain', 'bytes', 'mimetype', 'event'); my $events = { 'accepted' => __('Accepted'), 'denied' => __('Denied'), 'filtered' => __('Filtered') }; return [{ 'name' => __('HTTP Proxy'), 'tablename' => 'squid_access', 'titles' => $titles, 'order' => \@order, 'filter' => ['url', 'domain', 'remotehost', 'rfc931'], 'events' => $events, 'eventcol' => 'event', }]; } sub logHelper { my ($self) = @_; return (new EBox::Squid::LogHelper); } # Method to return the language to use with E2G depending on the locale # given by EBox sub _E2GLang { my $locale = EBox::locale(); my $lang = 'ukenglish'; # TODO: Make sure this list is not obsolete my %langs = ( 'da' => 'danish', 'de' => 'german', 'es' => 'arspanish', 'fr' => 'french', 'it' => 'italian', 'nl' => 'dutch', 'pl' => 'polish', 'pt' => 'portuguese', 'sv' => 'swedish', 'tr' => 'turkish', ); $locale = substr($locale,0,2); if ( exists $langs{$locale} ) { $lang = $langs{$locale}; } return $lang; } sub addPathsToRemove { my ($self, $when, @files) = @_; my $key = 'paths_to_remove_on_' . $when; my $state = $self->get_state(); my $toRemove = $state->{$when}; $toRemove or $toRemove = []; push @{$toRemove }, @files; $state->{$key} = $toRemove; $self->set_state($state); } sub clearPathsToRemove { my ($self, $when) = @_; my $key = 'paths_to_remove_on_' . $when; my $state = $self->get_state(); delete $state->{$key}; $self->set_state($state); } sub pathsToRemove { my ($self, $when) = @_; my $key = 'paths_to_remove_on_' . $when; my $state = $self->get_state(); my $toRemove = $state->{$key}; $toRemove or $toRemove = []; return $toRemove; } sub aroundRestoreConfig { my ($self, $dir, %options) = @_; my $categorizedLists = $self->model('CategorizedLists'); $categorizedLists->beforeRestoreConfig(); $self->SUPER::aroundRestoreConfig($dir, %options); $categorizedLists->afterRestoreConfig(); } # LdapModule implementation sub _ldapModImplementation { return new EBox::Squid::LdapUserImplementation(); } # Method: regenGatewaysFailover # # Overrides: # # # sub regenGatewaysFailover { my ($self) = @_; $self->restartService(); } # Security Updates Add-On message sub _commercialMsg { return __sx('Want to avoid threats such as malware, phishing and bots? Get one of the {oh}Commercial Editions{ch} that will keep your Content Filtering rules always up-to-date.', oh => '', ch => ''); } sub ifaceExternalChanged { my ($self, $iface, $toExternal) = @_; if (not $self->_externalIfacesAfterChange($toExternal)) { return 1; } return 0; } sub ifaceMethodChanged { my ($self, $iface, $old, $new) = @_; my $network = $self->global()->modInstance('network'); if (not $network->ifaceIsExternal($iface)) { return 0; } my $noExternalMethod = 0; my @noExternalMethods = qw(notset trunk); foreach my $method (@noExternalMethods) { if ($method eq $old) { return 0; } if ($method eq $new) { $noExternalMethod = 1; } } if (not $noExternalMethod) { return 0; } if (not $self->_externalIfacesAfterChange(0)) { return 1; } return 0; } sub changeIfaceExternalProperty { my ($self, $iface, $toExternal) = @_; $self->_ifaceChangeDone($iface, $toExternal); } sub freeIface { my ($self, $iface, $toExternal) = @_; my $ifaceExternal = $self->global()->modInstance('network')->ifaceIsExternal($iface); if ($ifaceExternal) { $self->_ifaceChangeDone($iface, 0); } } sub _externalIfacesAfterChange { my ($self, $toExternal) = @_; if (not $self->isEnabled()) { # we do not care, external interfaces are check when enabling the module return 1; } if ($toExternal) { return 1; } my $network = $self->global()->modInstance('network'); my $nExternal = @{ $network->ExternalIfaces() }; # simulate changed $nExternal -= 1 ; return ($nExternal > 0) } sub _ifaceChangeDone { my ($self, $iface, $toExternal) = @_; if (not $self->_externalIfacesAfterChange($toExternal)) { EBox::warn("Disabling HTTP proxy because $iface is not longer external and there are not interfaces left"); $self->enableService(0); } } 1;