Mail-SpamAssassin
view release on metacpan or search on metacpan
sa-update.raw view on Meta::CPAN
if ( defined $opt{'help'} ) {
print_usage_and_exit("For more information read the sa-update man page.\n", 0);
}
if ( defined $opt{'version'} ) {
print_version();
exit(0);
}
if ( $opt{'allowplugins'} && !$opt{'reallyallowplugins'} ) {
warn "Security warning: dangerous option --allowplugins used:\n".
"- there should never be need to use this option, see man sa-update(1)\n".
"- specify --reallyallowplugins to allow activating plugins\n";
exit 2;
}
$use_inet4 = $have_inet4 && ( !$opt{'force_pf'} || $opt{'force_pf'} eq 'inet' );
$use_inet6 = $have_inet6 && ( !$opt{'force_pf'} || $opt{'force_pf'} eq 'inet6' );
if ( $opt{'force_pf'} && $opt{'force_pf'} eq 'inet' && !$have_inet4 ) {
warn "Option -4 specified but support for the ".
"INET protocol family is not available.\n";
}
if ( $opt{'force_pf'} && $opt{'force_pf'} eq 'inet6' && !$have_inet6 ) {
warn "Option -6 specified but support for the ".
"INET6 protocol family is not available.\n";
}
if ( defined $opt{'httputil'} && $opt{'httputil'} !~ /^(curl|wget|fetch|lwp)$/ ) {
warn "Invalid parameter for --httputil, curl|wget|fetch|lwp wanted\n";
}
if ( defined $opt{'score-multiplier'} && $opt{'score-multiplier'} !~ /^\d+(?:\.\d+)?$/ ) {
die "Invalid parameter for --score-multiplier, integer or float expected.\n";
}
if ( defined $opt{'score-limit'} && $opt{'score-limit'} !~ /^\d+(?:\.\d+)?$/ ) {
die "Invalid parameter for --score-limit, integer or float expected.\n";
}
# Figure out what version of SpamAssassin we're using, and also figure out the
# reverse of it for the DNS query. Handle x.yyyzzz as well as x.yz.
my $SAVersion = $Mail::SpamAssassin::VERSION;
if ($SAVersion =~ /^(\d+)\.(\d{3})(\d{3})$/) {
$SAVersion = join(".", $1+0, $2+0, $3+0);
}
elsif ($SAVersion =~ /^(\d)\.(\d)(\d)$/) {
$SAVersion = "$1.$2.$3";
}
else {
die "fatal: SpamAssassin version number '$SAVersion' is in an unknown format!\n";
}
my $RevSAVersion = join(".", reverse split(/\./, $SAVersion));
# set debug areas, if any specified (only useful for command-line tools)
$opt{'debug'} ||= 'all' if (defined $opt{'debug'});
# Find the default site rule directory, also setup debugging and other M::SA bits
my $SA = Mail::SpamAssassin->new({
debug => $opt{'debug'},
local_tests_only => 1,
dont_copy_prefs => 1,
PREFIX => $PREFIX,
DEF_RULES_DIR => $DEF_RULES_DIR,
LOCAL_RULES_DIR => $LOCAL_RULES_DIR,
LOCAL_STATE_DIR => $LOCAL_STATE_DIR,
});
if (defined $opt{'updatedir'}) {
$opt{'updatedir'} = untaint_file_path($opt{'updatedir'});
}
else {
$opt{'updatedir'} = $SA->sed_path('__local_state_dir__/__version__');
}
# check only disabled gpg
# https://bz.apache.org/SpamAssassin/show_bug.cgi?id=5854
if ( defined $opt{'checkonly'}) {
$GPG_ENABLED=0;
dbg("gpg: Disabling gpg requirement due to checkonly flag.");
}
dbg("generic: sa-update version $VERSION");
dbg("generic: using update directory: $opt{'updatedir'}");
# doesn't really display useful things for this script, but we do want
# a module/version listing, etc. sa-update may be used for older versions
# of SA that don't include this function, so eval around it.
eval { $SA->debug_diagnostics(); 1; };
$SA->finish();
# untaint the command-line args; since the root user supplied these, and
# we're not a setuid script, we trust them
foreach my $optkey (keys %opt) {
next if ref $opt{$optkey};
untaint_var(\$opt{$optkey});
}
##############################################################################
# Deal with gpg-related options
if (@{$opt{'gpgkey'}}) {
$GPG_ENABLED = 1;
foreach my $key (@{$opt{'gpgkey'}}) {
unless (is_valid_gpg_key_id($key)) {
dbg("gpg: invalid gpgkey parameter $key");
next;
}
$key = uc $key;
dbg("gpg: adding key id $key");
$valid_GPG{$key} = 1;
}
}
if (defined $opt{'gpgkeyfile'}) {
$GPG_ENABLED = 1;
open(GPG, $opt{'gpgkeyfile'})
sa-update.raw view on Meta::CPAN
sub is_valid_gpg_key_id {
# either a keyid (8 bytes) or a fingerprint (40 bytes)
return ($_[0] =~ /^[a-fA-F0-9]+$/ && (length $_[0] == 8 || length $_[0] == 40));
}
##############################################################################
sub clean_update_dir {
my($dir, $preserve_files_ref) = @_;
dbg("generic: cleaning directory %s", $dir);
unless (opendir(DIR, $dir)) {
warn "error: cannot opendir $dir: $!\n";
dbg("generic: attempt to opendir ($dir) failed");
return;
}
while(my $file = readdir(DIR)) {
next if $file eq '.' || $file eq '..';
my $path = File::Spec->catfile($dir, $file);
if ($preserve_files_ref && $preserve_files_ref->{$path}) {
dbg("generic: preserving $file");
next;
}
untaint_var(\$path);
next unless -f $path;
dbg("generic: unlinking $file");
if (!unlink $path) {
warn "error: cannot remove file $path: $!\n";
closedir(DIR) or die "cannot close directory $dir: $!";
return;
}
}
closedir(DIR) or die "cannot close directory $dir: $!";
return 1;
}
sub delete_files {
my(@filenames) = @_;
foreach my $path (@filenames) {
dbg("generic: unlinking $path");
unlink $path or warn "error: cannot unlink file $path: $!\n";
}
return 1;
}
##############################################################################
sub lint_check_dir {
my $dir = shift;
# due to the Logger module's globalness (all M::SA objects share the same
# Logger setup), we can't change the debug level here to only include
# "config" or otherwise be more terse. :(
my $spamtest = Mail::SpamAssassin->new( {
rules_filename => $dir,
site_rules_filename => $LOCAL_RULES_DIR,
ignore_site_cf_files => 1,
userprefs_filename => File::Spec->catfile($dir, "doesnotexist"),
local_tests_only => 1,
dont_copy_prefs => 1,
PREFIX => $PREFIX,
DEF_RULES_DIR => $DEF_RULES_DIR,
LOCAL_RULES_DIR => $LOCAL_RULES_DIR,
LOCAL_STATE_DIR => $LOCAL_STATE_DIR,
});
# need to kluge disabling bayes since it may try to expire the DB, and
# without the proper config it's not going to be good.
$spamtest->{conf}->{use_bayes} = 0;
my $res = $spamtest->lint_rules();
$spamtest->finish();
return $res == 0;
}
##############################################################################
=head1 NAME
sa-update - automate SpamAssassin rule updates
=head1 SYNOPSIS
B<sa-update> [options]
Options:
--channel channel Retrieve updates from this channel
Use multiple times for multiple channels
--channelfile file Retrieve updates from the channels in the file
--checkonly Check for update availability, do not install
--install file Install updates directly from this file. Signature
verification will use "file.asc", or "file.sha512"
or "file.sha256".
--allowplugins Allow updates to load plugin code (DANGEROUS)
--gpgkey key Trust the key id to sign releases
Use multiple times for multiple keys
--gpgkeyfile file Trust the key ids in the file to sign releases
--gpghomedir path Store the GPG keyring in this directory
--gpg and --nogpg Use (or do not use) GPG to verify updates
(--gpg is assumed by use of the above
--gpgkey and --gpgkeyfile options)
--import file Import GPG key(s) from file into sa-update's
keyring. Use multiple times for multiple files
--updatedir path Directory to place updates, defaults to the
SpamAssassin site rules directory
(default: @@LOCAL_STATE_DIR@@/@@VERSION@@)
--refreshmirrors Force the MIRRORED.BY file to be updated
--forcemirror url Use a specific mirror instead of downloading from
official mirrors
--httputil util Force used download tool. By default first found
from these is used: curl, wget, fetch, lwp
--score-multiplier x.x Adjust all scores from update channel, multiply
with given value (integer or float).
--score-limit x.x Adjust all scores from update channel, limit
to given value (integer or float). Limiting
is done after possible multiply operation.
-D, --debug [area=n,...] Print debugging messages
( run in 1.221 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )