Download | Plain Text | Line Numbers
--- spamd/spamd.raw.orig 2009-12-15 22:09:03.000000000 +0100
+++ spamd/spamd.raw 2009-12-15 22:15:34.000000000 +0100
@@ -88,6 +88,7 @@
use Mail::SpamAssassin::SubProcBackChannel;
use Mail::SpamAssassin::SpamdForkScaling qw(:pfstates);
use Mail::SpamAssassin::Logger qw(:DEFAULT log_message);
+use Mail::SpamAssassin::Util qw(untaint_var);
use Mail::SpamAssassin::Timeout;
use Getopt::Long;
@@ -2076,7 +2076,21 @@
my $prefsfrom = $username; # the one passed, NOT $opt{username}
- if ($prefsfrom eq $suidto || $opt{'vpopmail'}) {
- $userdir = $suiddir; # reuse the already-looked-up info
+ if ($prefsfrom eq $suidto) {
+ $userdir = $suiddir; # reuse the already-looked-up info, tainted
+ } elsif ( $opt{'vpopmail'} ) {
+ #
+ # If vpopmail config enabled then set $userdir to virtual homedir
+ #
+ my $username_untainted;
+ $username_untainted =
+ untaint_var($username) if $username =~ /^[-:,.=+A-Za-z0-9_\@~]+\z/;
+ my $vpopdir = $suiddir; # This should work with common vpopmail setups
+ $userdir = `$vpopdir/bin/vuserinfo -d \Q$username_untainted\E`;
+ if ($? == 0) {
+ chomp($userdir);
+ } else {
+ $userdir = handle_user_vpopmail($username_untainted,$vpopdir);
+ }
} else {
$userdir = (getpwnam($prefsfrom))[7];
}
@@ -2095,30 +2108,47 @@
# call this anyway, regardless of --user-config, so that
# signal_user_changed() is called
- handle_user_set_user_prefs($userdir, $username);
+ handle_user_set_user_prefs(untaint_var($userdir), $username);
}
-sub handle_user_set_user_prefs {
- my ($dir, $username) = @_;
-
- # If vpopmail config enabled then set $dir to virtual homedir
+sub handle_user_vpopmail {
#
- if ( $opt{'vpopmail'} ) {
- my $vpopdir = $dir;
- $dir = `$vpopdir/bin/vuserinfo -d \Q$username\E`;
- if ($? != 0) {
- #
- # If vuserinfo failed $username could be an alias
- #
- $dir = `$vpopdir/bin/valias \Q$username\E`;
- if ($? == 0 && $dir !~ /.+ -> &/) {
- $dir =~ s,.+ -> (/.+)/Maildir/,$1,;
+ # If vuserinfo failed $username could be an alias
+ # As the alias could be an alias itself we'll try to resolve it recursively
+ # Because we're mistrusting vpopmail we'll set off an alarm
+ #
+ my $username = shift;
+ my $vpopdir = shift;
+ my $userdir;
+ my $vpoptimeout = 5;
+ my $vptimer = Mail::SpamAssassin::Timeout->new({ secs => $vpoptimeout });
+
+ $vptimer->run(sub {
+ my $vpopusername = $username;
+ local $1;
+ do {
+ my $vpopusername_tainted = `$vpopdir/bin/valias \Q$vpopusername\E`;
+ no re 'taint';
+ if ($vpopusername_tainted =~ /.+ -> &?(.+)/) {
+ $vpopusername = untaint_var($1);
} else {
- undef($dir);
+ die "failed to resolve vpopmail user/alias '$username' using vuserinfo/valias";
}
- }
- chomp($dir);
+ } until (($userdir = `$vpopdir/bin/vuserinfo -d \Q$vpopusername\E`) && $? == 0);
+ $userdir =~ s{.+ -> (/.+)/Maildir/}{$1};
+ });
+
+ if ($vptimer->timed_out()) {
+ undef $userdir;
+ die "failed to resolve vpopmail user/alias '$username' in time ($vpoptimeout seconds)";
+ } else {
+ chomp($userdir);
}
+ return $userdir;
+}
+
+sub handle_user_set_user_prefs {
+ my ($dir, $username) = @_;
# don't do this if we weren't passed a directory
if ($dir) {
--- lib/Mail/SpamAssassin/Util.pm.orig 2008-06-10 11:20:22.000000000 +0200
+++ lib/Mail/SpamAssassin/Util.pm 2009-12-15 22:17:41.000000000 +0100
@@ -50,7 +50,7 @@
require Exporter;
@ISA = qw(Exporter);
-@EXPORT = qw(local_tz base64_decode);
+@EXPORT = qw(local_tz base64_decode untaint_var);
use Mail::SpamAssassin;
use Mail::SpamAssassin::Util::RegistrarBoundaries;