php IHDR w Q )Ba pHYs sRGB gAMA a IDATxMk\U s&uo,mD )Xw+e?tw.oWp;QHZnw`gaiJ9̟灙a=nl[ ʨ G;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ y H@E7j 1j+OFRg}ܫ;@Ea~ j`u'o> j- $_q?qS XzG'ay
files >> /usr/libexec/webmin/virtual-server/ |
files >> //usr/libexec/webmin/virtual-server/feature-virus.pl |
# Functions for turning Virus filtering on or off on a per-domain basis sub check_depends_virus { return !$_[0]->{'spam'} ? $text{'setup_edepvirus'} : undef; } sub init_virus { $clam_wrapper_cmd = "$module_config_directory/clam-wrapper.pl"; } # setup_virus(&domain) # Adds an entry to the procmail file for this domain to call clamscan too sub setup_virus { &$first_print($text{'setup_virus'}); &obtain_lock_virus($_[0]); &require_spam(); local $spamrc = "$procmail_spam_dir/$_[0]->{'id'}"; # Find the clamscan recipe local @recipes = &procmail::parse_procmail_file($spamrc); local @clamrec = &find_clam_recipe(\@recipes); if (@clamrec) { # Already there? &$second_print($text{'setup_virusalready'}); } else { # Copy the wrapper program ©_clam_wrapper(); # Add the recipe local $recipe0 = { 'flags' => [ 'c', 'w' ], 'type' => '|', 'action' => $clam_wrapper_cmd." ". &full_clamscan_path() }; local $varon = { 'name' => 'VIRUSMODE', 'value' => 1 }; local $recipe1 = { 'flags' => [ 'e' ], 'action' => $config{'clam_delivery'} }; local $varoff = { 'name' => 'VIRUSMODE', 'value' => 0 }; if (@recipes > 1) { &procmail::create_recipe_before($recipe0, $recipes[1], $spamrc); &procmail::create_recipe_before($varon, $recipes[1], $spamrc); &procmail::create_recipe_before($recipe1, $recipes[1], $spamrc); &procmail::create_recipe_before($varoff, $recipes[1], $spamrc); } else { &procmail::create_recipe($recipe0, $spamrc); &procmail::create_recipe($varon, $spamrc); &procmail::create_recipe($recipe1, $spamrc); &procmail::create_recipe($varoff, $spamrc); } &$second_print($text{'setup_done'}); } &release_lock_virus($_[0]); } # modify_virus(&domain, &olddomain) # Doesn't have to do anything sub modify_virus { } # delete_virus(&domain) # Just remove the procmail entry that calls clamscan sub delete_virus { local $spamrc = "$procmail_spam_dir/$_[0]->{'id'}"; if (!-r $spamrc && !$_[0]->{'spam'}) { # Spam already deleted, so the whole procmail file will have been # already removed. So do nothing! return 1; } &$first_print($text{'delete_virus'}); &obtain_lock_virus($_[0]); &require_spam(); local @recipes = &procmail::parse_procmail_file($spamrc); local @clamrec = &find_clam_recipe(\@recipes); if (@clamrec) { &procmail::delete_recipe($clamrec[1]); &procmail::delete_recipe($clamrec[0]); # Also take out VIRUSMODE variables @recipes = &procmail::parse_procmail_file($spamrc); foreach my $r (reverse(@recipes)) { if ($r->{'name'} eq 'VIRUSMODE') { &procmail::delete_recipe($r); } } &$second_print($text{'setup_done'}); } else { &$second_print($text{'delete_virusnone'}); } &release_lock_virus($_[0]); } # clone_virus(&domain, &old-domain) # Does nothing, as cloning the spamassassin config clones virus settings too sub clone_virus { return 1; } # copy_clam_wrapper() # Copies the clamav wrapper script into place sub copy_clam_wrapper { ©_source_dest("$module_root_directory/clam-wrapper.pl", $clam_wrapper_cmd); &set_ownership_permissions(undef, undef, 0755, $clam_wrapper_cmd); } # validate_virus(&domain) # Make sure the domain's procmail config file calls ClamAV sub validate_virus { local ($d) = @_; &require_spam(); local $spamrc = "$procmail_spam_dir/$d->{'id'}"; return &text('validate_espamprocmail', "<tt>$spamrc</tt>") if (!-r $spamrc); local @recipes = &procmail::parse_procmail_file($spamrc); local @clamrec = &find_clam_recipe(\@recipes); return &text('validate_evirus', "<tt>$spamrc</tt>") if (!@clamrec); return undef; } # check_virus_clash() # No need to check for clashes .. sub check_virus_clash { return 0; } # find_clam_recipe(&recipes) # Returns the two recipes used for virus filtering sub find_clam_recipe { local $i; for($i=0; $i<@{$_[0]}; $i++) { if ($_[0]->[$i]->{'action'} =~ /clam(d?)scan/ || $_[0]->[$i]->{'action'} =~ /\Q$clam_wrapper_cmd\E/) { # Found clamscan .. but is the next one OK? if ($_[0]->[$i+1]->{'flags'}->[0] eq 'e') { return ( $_[0]->[$i], $_[0]->[$i+1] ); } elsif ($_[0]->[$i+2]->{'flags'}->[0] eq 'e') { return ( $_[0]->[$i], $_[0]->[$i+2] ); } } } return ( ); } # sysinfo_virus() # Returns the ClamAV version sub sysinfo_virus { local $out = &backquote_command("$config{'clamscan_cmd'} -V 2>/dev/null", 1); local $vers = $out =~ /ClamAV\s+([0-9\.]+)/i ? $1 : "Unknown"; return ( [ $text{'sysinfo_virus'}, $vers ] ); } # Update the procmail scripts for all domains that call clamscan so that they # call the wrapper instead sub fix_clam_wrapper { &require_spam(); foreach my $d (grep { $_->{'virus'} } &list_domains()) { local $spamrc = "$procmail_spam_dir/$d->{'id'}"; local @recipes = &procmail::parse_procmail_file($spamrc); local @clamrec = &find_clam_recipe(\@recipes); if ($clamrec[0]->{'action'} !~ /\Q$clam_wrapper_cmd\E/ && $clamrec[0]->{'action'} =~ /^(\S*clam(d?)scan)\s+\-$/) { $clamrec[0]->{'action'} = "$clam_wrapper_cmd $1"; &procmail::modify_recipe($clamrec[0]); } } } # get_domain_virus_delivery(&domain) # Returns the delivery mode and dest for some domain. The modes can be : # 0 - Throw away , 1 - File under home , 2 - Forward to email , 3 - Other file, # 4 - Normal ~/mail/virus file, 5 - Deliver normally , 6 - ~/Maildir/.virus/ , # -1 - Broken! sub get_domain_virus_delivery { local ($d) = @_; &require_spam(); local $spamrc = "$procmail_spam_dir/$d->{'id'}"; local @recipes = &procmail::parse_procmail_file($spamrc); local @clamrec = &find_clam_recipe(\@recipes); if (!@clamrec) { return (-1); } elsif (!$clamrec[1]) { return (5); } elsif ($clamrec[1]->{'action'} eq '/dev/null') { return (0); } elsif ($clamrec[1]->{'action'} =~ /^\$HOME\/mail\/(virus|Virus)$/) { return (4, $1); } elsif ($clamrec[1]->{'action'} =~ /^\$HOME\/Maildir\/.(virus|Virus)\/$/) { return (6, $1); } elsif ($clamrec[1]->{'action'} =~ /^\$HOME\/(.*)$/) { return (1, $1); } elsif ($clamrec[1]->{'action'} =~ /\@/) { return (2, $clamrec[1]->{'action'}); } else { return (3, $clamrec[1]->{'action'}); } } # save_domain_virus_delivery(&domain, mode, dest) # Updates the delivery method for viruses for some domain sub save_domain_virus_delivery { local ($d, $mode, $dest) = @_; &require_spam(); local $spamrc = "$procmail_spam_dir/$d->{'id'}"; local @recipes = &procmail::parse_procmail_file($spamrc); local @clamrec = &find_clam_recipe(\@recipes); return 0 if (!@clamrec); local $r = $clamrec[1]; # Preserve existing settings if not set local ($oldmode, $olddest) = &get_domain_virus_delivery($d); if (!defined($mode)) { ($mode, $dest) = ($oldmode, $olddest); } elsif (!defined($dest)) { $dest = $olddest; } # Work out folder name, defaulting to upper case local $folder; if ($mode == 4 || $mode == 6) { if ($dest =~ /^[a-z0-9\.\_\-]+$/i) { $folder = $dest; } else { $folder = "Virus"; } } $r->{'action'} = $mode == 0 ? "/dev/null" : $mode == 4 ? "\$HOME/mail/$folder" : $mode == 6 ? "\$HOME/Maildir/.$folder/" : $mode == 1 ? "\$HOME/$dest" : $dest; $r->{'type'} = $mode == 2 ? "!" : ""; &procmail::modify_recipe($r); return 1; } # full_clamscan_path() # Returns the clamav scan command, using the full path plus any args sub full_clamscan_path { local $prog = $config{'clamscan_cmd'}; if ($prog eq "clamd-stream-client") { $prog .= &make_stream_client_args($config{'clamscan_host'}); } elsif ($prog eq "clamdscan") { $prog .= &get_clamdscan_args(); } local ($cmd, @args) = &split_quoted_string($prog); local $fullcmd = &has_command($cmd); return undef if (!$fullcmd); local @rv = ( $fullcmd, @args ); return join(" ", map { /\s/ ? "\"$_\"" : $_ } @rv); } # make_stream_client_args([host[:port]]) # Convert a hostname with possible port into an arg string sub make_stream_client_args { my ($hostport) = @_; my ($host, $port) = split(/:/, $hostport); my $rv; if ($host) { $rv .= " -d ".$host; if ($port) { $rv .= " -p ".$port; } } return $rv; } # get_clamdscan_args() # Returns any extra args needed for clamdscan, like for the config file sub get_clamdscan_args { local $scanfile = "/etc/clamd.d/scan.conf"; &foreign_require("init"); if (-r $scanfile && &init::action_status("clamd\@scan")) { return " --config-file ".$scanfile; } return undef; } # get_domain_virus_scanner(&domain) # Returns the virus scanning command use for some domain. This can be clamscan, # clamdscan or some other path. sub get_domain_virus_scanner { local ($d) = @_; &require_spam(); local $spamrc = "$procmail_spam_dir/$d->{'id'}"; local @recipes = &procmail::parse_procmail_file($spamrc); local @clamrec = &find_clam_recipe(\@recipes); if (@clamrec) { local $rv = $clamrec[0]->{'action'}; $rv =~ s/^\Q$clam_wrapper_cmd\E\s+//; local @rvs = &split_quoted_string($rv); if ($rvs[0] eq &has_command("clamscan")) { $rv = "clamscan"; } elsif ($rvs[0] eq &has_command("clamdscan")) { $rv = "clamdscan"; } elsif ($rvs[0] eq &has_command("clamd-stream-client")) { $rv = "clamd-stream-client"; } return $rv; } else { return undef; } } # save_domain_virus_scanner(&domain, program) # Updates the virus scanning program in the procmail config sub save_domain_virus_scanner { local ($d, $prog) = @_; &require_spam(); local $spamrc = "$procmail_spam_dir/$d->{'id'}"; local @recipes = &procmail::parse_procmail_file($spamrc); local @clamrec = &find_clam_recipe(\@recipes); if (@clamrec) { if ($prog eq "clamscan") { $prog = &has_command("clamscan"); } elsif ($prog eq "clamdscan") { $prog = &has_command("clamdscan"); $prog .= &get_clamdscan_args(); } elsif ($prog eq "clamd-stream-client") { $prog = &has_command("clamd-stream-client"); $prog .= &make_stream_client_args($config{'clamscan_host'}); } $clamrec[0]->{'action'} = "$clam_wrapper_cmd $prog"; &procmail::modify_recipe($clamrec[0]); } } # get_global_virus_scanner() # Returns the virus scanning program used by all domains, and possibly also # the clamd hostname sub get_global_virus_scanner { if ($config{'clamscan_cmd_global'}) { # We know it from the module config return ($config{'clamscan_cmd'}, $config{'clamscan_host'}); } else { # Find the most used one for all domains local (%cmdcount, $maxcmd); foreach my $d (grep { $_->{'virus'} } &list_domains()) { local $cmd = &get_domain_virus_scanner($d); if ($cmd) { $cmdcount{$cmd}++; if (!$maxcmd || $cmdcount{$cmd} > $cmdcount{$maxcmd}) { $maxcmd = $cmd; } } } return ($maxcmd || $config{'clamscan_cmd'}, undef); } } # save_global_virus_scanner(command, scanner-host) # Update all domains to use a new scanning command sub save_global_virus_scanner { local ($cmd, $host) = @_; $config{'clamscan_cmd'} = $cmd; $config{'clamscan_cmd_global'} = 1; $config{'clamscan_host'} = $host; $config{'last_check'} = time()+1; &save_module_config(); foreach my $d (grep { $_->{'virus'} } &list_domains()) { &save_domain_virus_scanner($d, $cmd); } } # test_virus_scanner(command, [host]) # Tests some virus scanning command. Returns an error message on failure, undef # on success. If clamscan takes more than 10 seconds, this typically assumes # that it is working but slow. sub test_virus_scanner { local ($cmd, $host) = @_; local $fullcmd = $cmd; if ($cmd eq "clamd-stream-client") { # Set remote host $fullcmd .= &make_stream_client_args($host); } else { # Tell command to use stdin if ($cmd eq "clamdscan") { $fullcmd .= &get_clamdscan_args(); } $fullcmd .= " -"; } local ($out, $timed_out) = &backquote_with_timeout("$fullcmd </dev/null 2>&1", 10, 1); if ($timed_out) { return undef; } elsif ($?) { return "<pre>".&html_escape($out)."</pre>"; } elsif ($cmd ne "clamd-stream-client" && $out !~ /OK/) { return $text{'sv_etestok'}; } else { return undef; } } # check_clamd_status() # Checks if clamd is configured and running on this system. Returns 0 if not, # 1 if yes, or -1 if we can't tell (due to a non-supported OS). sub check_clamd_status { local %avahi_pids = map { $_, 1 } grep { $_ != $$ } &find_byname("avahi-daemon"); local @pids = grep { $_ != $$ && !$avahi_pids{$_} } &find_byname("clamd"); if (@pids) { # Running already, so we assume everything is cool return 1; } local $clamd = &has_command("clamd") || &has_command("/opt/csw/sbin/clamd"); if (!$clamd) { # No installed return -1; } &foreign_require("init", "init-lib.pl"); if (&init::action_status("clamdscan-clamd")) { return 0; # Joe's init script for redhat } elsif (&init::action_status("clamd\@scan")) { return 0; # EPEL 7/Fedora 20 clamav-scanner package } elsif (&init::action_status("clamav-daemon")) { return 0; # Ubuntu } elsif (&init::action_status("clamd-wrapper") || &init::action_status("clamd-virtualmin")) { return 0; # Redhat, not setup yet } elsif (&init::action_status("clamd")) { return 0; # RHEL 6+, not setup yet } elsif (&init::action_status("clamav-clamd")) { return 0; # FreeBSD } elsif (-r "/opt/csw/etc/clamd.conf.CSW") { return 0; # Solaris CSW package } return -1; } # enable_clamd() # Do everything needed to configure and start clamd. May print stuff with the # standard functions. sub enable_clamd { local $st = &check_clamd_status(); return 1 if ($st == 1 || $st == -1); # Check for simple init scripts local $init; &foreign_require("init", "init-lib.pl"); foreach my $i ("clamav-daemon", "clamdscan-clamd", "clamav-clamd", "clamd", "clamd\@scan") { if (&init::action_status($i)) { $init = $i; last; } } # Make sure socket file is valid in config foreach my $c ("/etc/clamd.conf", "/etc/clamd.d/scan.conf", "/etc/clamd.d/virtualmin.conf") { next if (!-r $c); local $lref = &read_file_lines($c); local $sfile; local $clamuser; foreach my $l (@$lref) { if ($l =~ /^\s*LocalSocket\s+(\S+)/) { $sfile = $1; } elsif ($l =~ /^\s*LocalSocketMode\s+/) { $l = "LocalSocketMode 666"; } elsif ($l =~ /^\s*User\s+(\S+)/) { $clamuser = $1; } } &flush_file_lines($c); if ($sfile =~ /^(\S+)\/([^\/]+)$/) { local $sdir = $1; if (!-d $sdir) { if ($clamuser) { &make_dir($sdir, 0755); &set_ownership_permissions($clamuser, undef, 0755, $sdir); } else { &make_dir($sdir, 0777); } } else { &set_ownership_permissions(undef, undef, 0755, $sdir); } } &set_ownership_permissions(undef, undef, 0666, $sfile); } if ($init) { # Ubuntu, Joe's or FreeBSD .. all we have to do is enable and # start the daemon! &$first_print(&text('clamd_start')); &init::enable_at_boot($init); local ($ok, $out) = &init::start_action($init); if (!$ok || $out =~ /failed|error/i) { &$second_print(&text('clamd_estart', "<tt>".&html_escape($out)."</tt>")); } else { &$second_print($text{'setup_done'}); } } elsif (&init::action_status("clamd-wrapper")) { # Looks like a Redhat system .. start by creating the .conf file local $service = "virtualmin"; local $cfile = "/etc/clamd.d/$service.conf"; local $srcpat = "/usr/share/doc/clamav-server-*/clamd.conf"; local ($srcfile) = glob($srcpat); &$first_print(&text('clamd_copyconf', "<tt>$cfile</tt>")); if (!$srcfile && !-r $cfile) { &$second_print(&text('clamd_esrcfile', "<tt>$srcpat</tt>")); return 0; } local $user = "nobody"; local @uinfo = getgrnam($user); local $group = getgrgid($uinfo[3]); &lock_file($cfile); if (!-r $cfile) { ©_source_dest($srcfile, $cfile); } local $lref = &read_file_lines($cfile); local ($logfile, $socketfile); foreach my $l (@$lref) { if ($l =~ /^\s*Example/) { $l = "# Example"; } $l =~ s/<SERVICE>/$service/g; $l =~ s/<USER>/$user/g; $l =~ s/<GROUP>/$group/g; if ($l =~ /^#+\s*LogFile\s+(\/\S+)/) { $l = "LogFile $1"; $logfile = $1; } if ($l =~ /^#+\s*LocalSocket\s+(\S+)/) { $l = "LocalSocket $1"; } if ($l =~ /^LocalSocket\s+(\S+)/) { $socketfile = $1; } } &flush_file_lines($cfile); &unlock_file($cfile); local $othercfile = "/etc/clamd.conf"; if (!-r $othercfile) { &symlink_logged($cfile, $othercfile); } &$second_print($text{'setup_done'}); # Create empty log if ($logfile && !-r $logfile) { &open_tempfile(LOG, ">$logfile", 0, 1); &close_tempfile(LOG); &set_ownership_permissions($user, $group, 0755, $logfile); } # Create directory for socket file if ($socketfile) { local $socketdir = $socketfile; $socketdir =~ s/\/[^\/]+$//; if (!-d $socketdir) { &make_dir($socketdir, 0755); &set_ownership_permissions($user, $group, 0755, $socketdir); } } # Copy and fix the init wrapper script local $srcifile = &init::action_filename("clamd-wrapper"); local $ifile = &init::action_filename("clamd-virtualmin"); &$first_print(&text('clamd_initscript', "<tt>$ifile</tt>")); if (-r $srcifile && !-r $ifile) { ©_source_dest($srcifile, $ifile); } local $lref = &read_file_lines($ifile); local ($already) = grep { /^CLAMD_SERVICE=/ } @$lref; if ($already) { &$second_print($text{'clamd_initalready'}); } else { &lock_file($ifile); for(my $i=0; $i<@$lref; $i++) { if ($lref->[$i] =~ /^\#\s*Xchkconfig:\s+\-\s+(\d+)\s+(\d+)/) { # Fix chkconfig line $lref->[$i] = "# chkconfig: 2345 $1 $2"; } elsif ($lref->[$i] =~ /^\#\s*Xdescription:(.*)/) { # Fix description line $lref->[$i] = "# description:$1"; } elsif ($lref->[$i] !~ /^#/) { # Specify service name at top of file splice(@$lref, $i, 0, "CLAMD_SERVICE=$service"); last; } } &flush_file_lines($ifile); &set_ownership_permissions(undef, undef, 0755, $ifile); &unlock_file($ifile); &$second_print($text{'setup_done'}); } # Link the clamd program local $clamd = &has_command("clamd"); local $clamdcopy = $clamd.".".$service; &$first_print(&text('clamd_linkbin', "<tt>$clamdcopy</tt>")); &unlink_file($clamdcopy); &symlink_logged($clamd, $clamdcopy); &$second_print($text{'setup_done'}); # Create the socket directory if (-d "/var/run/clamd.$service") { &make_dir("/var/run/clamd.$service", 0777); } # Start the daemon, and enable at boot &$first_print(&text('clamd_start')); &init::enable_at_boot("clamd-virtualmin"); &init::disable_at_boot("clamd-wrapper"); local ($ok, $out); if (defined(&init::start_action)) { ($ok, $out) = &init::start_action($init); } else { $out = &backquote_logged("$ifile start 2>&1"); $ok = !$?; } if (!$ok || $out =~ /failed|error/i) { &$second_print(&text('clamd_estart', "<tt>".&html_escape($out)."</tt>")); } else { &$second_print($text{'setup_done'}); } } elsif (-r "/opt/csw/etc/clamd.conf.CSW") { # Solaris CSW package .. copy config file local $cfile = "/opt/csw/etc/clamd.conf"; local $srcfile = "/opt/csw/etc/clamd.conf.CSW"; &$first_print(&text('clamd_copyconf', "<tt>$cfile</tt>")); if (-r $cfile) { &$second_print($text{'clamd_esrcalready'}); } else { ©_source_dest($srcfile, $cfile); &$second_print($text{'setup_done'}); } # Create the log directory &$first_print($text{'clamd_logdir'}); local $lref = &read_file_lines($cfile); local ($logfile, $user); foreach my $l (@$lref) { if ($l =~ /^\s*LogFile\s+(\S+)/i) { $logfile = $1; } elsif ($l =~ /^\s*User\s+(\S+)/i) { $user = $1; } } if (-r $logfile) { &$second_print($text{'clamd_logalready'}); } elsif ($logfile) { local $logdir = $logfile; $logdir =~ s/\/[^\/]+$//; &make_dir($logdir, 0700); if ($user) { &set_ownership_permissions($user, undef, undef,$logdir); } else { &set_ownership_permissions(undef, undef, 0777, $logdir); } &$second_print(&text('clamd_logdone', "<tt>$logdir</tt>")); } else { &$second_print($text{'clamd_lognone'}); } # Create or enable bootup action &$first_print(&text('clamd_start')); local $init = "clamd-csw"; local $clamd = &has_command("clamd") || &has_command("/opt/csw/sbin/clamd"); &init::enable_at_boot($init, "Start ClamAV server", $clamd, "ps -ef | grep clamd | grep -v grep | grep -v \$\$ | awk '{ print \$2 }' | xargs kill"); local $ifile = &init::action_filename($init); local $out = &backquote_logged("$ifile start 2>&1"); if ($? || $out =~ /failed|error/i) { &$second_print(&text('clamd_estart', "<tt>".&html_escape($out)."</tt>")); } else { &$second_print($text{'setup_done'}); } } return 1; } # disable_clamd() # Shut down the clamd process and disable at boot. May also print stuff. sub disable_clamd { &foreign_require("init", "init-lib.pl"); foreach my $init ("clamdscan-clamd", "clamav-daemon", "clamd-virtualmin", "clamd-wrapper", "clamd-csw", "clamav-clamd", "clamd", "clamd\@scan") { if (&init::action_status($init)) { &$first_print(&text('clamd_stop')); &init::disable_at_boot($init); local ($ok, $out) = &init::stop_action($init); if (!$ok || $out =~ /failed|error/i) { &$second_print(&text('clamd_estop', "<tt>".&html_escape($out)."</tt>")); return 0; } &$second_print($text{'setup_done'}); return 1; } } return 0; } # startstop_virus([&typestatus]) # Returns a hash containing the current status of the clamd server and short # and long descriptions for the action to switch statuses sub startstop_virus { local ($scanner, $host) = &get_global_virus_scanner(); if (!($scanner eq 'clamdscan' || $scanner eq 'clamd-stream-client' && !$host)) { # Clamd isn't being used return ( ); } local @pids = grep { $_ != $$ } &find_byname("clamd"); if (@pids) { return ( { 'status' => 1, 'name' => $text{'index_clamname'}, 'desc' => $text{'index_clamstop'}, 'restartdesc' => $text{'index_clamrestart'}, 'longdesc' => $text{'index_clamstopdesc'} } ); } else { return ( { 'status' => 0, 'name' => $text{'index_clamname'}, 'desc' => $text{'index_clamstart'}, 'longdesc' => $text{'index_clamstartdesc'} } ); } } # start_service_virus() # Attempts to start the clamd server, returning undef on success or any error # message on failure. sub start_service_virus { &push_all_print(); &set_all_null_print(); local $rv = &enable_clamd(); &pop_all_print(); return $rv ? undef : $text{'clamd_estartmsg'}; } # stop_service_virus() # Attempts to stop the clamd server, returning undef on success or any error # message on failure. sub stop_service_virus { &foreign_require("init", "init-lib.pl"); foreach my $init ("clamdscan-clamd", "clamav-daemon", "clamd-virtualmin", "clamd-wrapper", "clamd-csw", "clamav-clamd", "clamd", "clamd\@scan") { if (&init::action_status($init)) { local ($ok, $out) = &init::stop_action($init); return $ok ? undef : "<tt>".&html_escape($out)."</tt>"; } } local @pids = grep { $_ != $$ } &find_byname("clamd"); if (@pids) { if (&kill_logged('TERM', @pids)) { return undef; } return &text('clamd_ekillmsg', $!); } else { return $text{'clamd_estopmsg'}; } } # Virus config files are the same as spam sub obtain_lock_virus { &obtain_lock_spam(@_); } # Virus config files are the same as spam sub release_lock_virus { &release_lock_spam(@_); } $done_feature_script{'virus'} = 1; 1;y~or5J={Eeu磝Qk ᯘG{?+]ן?wM3X^歌>{7پK>on\jy Rg/=fOroNVv~Y+ NGuÝHWyw[eQʨSb> >}Gmx[o[<{Ϯ_qFvM IENDB`