Download | Plain Text | No Line Numbers


  1. --- spamd/spamd.raw.orig 2009-12-15 22:09:03.000000000 +0100
  2. +++ spamd/spamd.raw 2009-12-15 22:15:34.000000000 +0100
  3. @@ -88,6 +88,7 @@
  4. use Mail::SpamAssassin::SubProcBackChannel;
  5. use Mail::SpamAssassin::SpamdForkScaling qw(:pfstates);
  6. use Mail::SpamAssassin::Logger qw(:DEFAULT log_message);
  7. +use Mail::SpamAssassin::Util qw(untaint_var);
  8. use Mail::SpamAssassin::Timeout;
  9.  
  10. use Getopt::Long;
  11. @@ -2076,7 +2076,21 @@
  12. my $prefsfrom = $username; # the one passed, NOT $opt{username}
  13.  
  14. - if ($prefsfrom eq $suidto || $opt{'vpopmail'}) {
  15. - $userdir = $suiddir; # reuse the already-looked-up info
  16. + if ($prefsfrom eq $suidto) {
  17. + $userdir = $suiddir; # reuse the already-looked-up info, tainted
  18. + } elsif ( $opt{'vpopmail'} ) {
  19. + #
  20. + # If vpopmail config enabled then set $userdir to virtual homedir
  21. + #
  22. + my $username_untainted;
  23. + $username_untainted =
  24. + untaint_var($username) if $username =~ /^[-:,.=+A-Za-z0-9_\@~]+\z/;
  25. + my $vpopdir = $suiddir; # This should work with common vpopmail setups
  26. + $userdir = `$vpopdir/bin/vuserinfo -d \Q$username_untainted\E`;
  27. + if ($? == 0) {
  28. + chomp($userdir);
  29. + } else {
  30. + $userdir = handle_user_vpopmail($username_untainted,$vpopdir);
  31. + }
  32. } else {
  33. $userdir = (getpwnam($prefsfrom))[7];
  34. }
  35. @@ -2095,30 +2108,47 @@
  36.  
  37. # call this anyway, regardless of --user-config, so that
  38. # signal_user_changed() is called
  39. - handle_user_set_user_prefs($userdir, $username);
  40. + handle_user_set_user_prefs(untaint_var($userdir), $username);
  41. }
  42.  
  43. -sub handle_user_set_user_prefs {
  44. - my ($dir, $username) = @_;
  45. -
  46. - # If vpopmail config enabled then set $dir to virtual homedir
  47. +sub handle_user_vpopmail {
  48. #
  49. - if ( $opt{'vpopmail'} ) {
  50. - my $vpopdir = $dir;
  51. - $dir = `$vpopdir/bin/vuserinfo -d \Q$username\E`;
  52. - if ($? != 0) {
  53. - #
  54. - # If vuserinfo failed $username could be an alias
  55. - #
  56. - $dir = `$vpopdir/bin/valias \Q$username\E`;
  57. - if ($? == 0 && $dir !~ /.+ -> &/) {
  58. - $dir =~ s,.+ -> (/.+)/Maildir/,$1,;
  59. + # If vuserinfo failed $username could be an alias
  60. + # As the alias could be an alias itself we'll try to resolve it recursively
  61. + # Because we're mistrusting vpopmail we'll set off an alarm
  62. + #
  63. + my $username = shift;
  64. + my $vpopdir = shift;
  65. + my $userdir;
  66. + my $vpoptimeout = 5;
  67. + my $vptimer = Mail::SpamAssassin::Timeout->new({ secs => $vpoptimeout });
  68. +
  69. + $vptimer->run(sub {
  70. + my $vpopusername = $username;
  71. + local $1;
  72. + do {
  73. + my $vpopusername_tainted = `$vpopdir/bin/valias \Q$vpopusername\E`;
  74. + no re 'taint';
  75. + if ($vpopusername_tainted =~ /.+ -> &?(.+)/) {
  76. + $vpopusername = untaint_var($1);
  77. } else {
  78. - undef($dir);
  79. + die "failed to resolve vpopmail user/alias '$username' using vuserinfo/valias";
  80. }
  81. - }
  82. - chomp($dir);
  83. + } until (($userdir = `$vpopdir/bin/vuserinfo -d \Q$vpopusername\E`) && $? == 0);
  84. + $userdir =~ s{.+ -> (/.+)/Maildir/}{$1};
  85. + });
  86. +
  87. + if ($vptimer->timed_out()) {
  88. + undef $userdir;
  89. + die "failed to resolve vpopmail user/alias '$username' in time ($vpoptimeout seconds)";
  90. + } else {
  91. + chomp($userdir);
  92. }
  93. + return $userdir;
  94. +}
  95. +
  96. +sub handle_user_set_user_prefs {
  97. + my ($dir, $username) = @_;
  98.  
  99. # don't do this if we weren't passed a directory
  100. if ($dir) {
  101. --- lib/Mail/SpamAssassin/Util.pm.orig 2008-06-10 11:20:22.000000000 +0200
  102. +++ lib/Mail/SpamAssassin/Util.pm 2009-12-15 22:17:41.000000000 +0100
  103. @@ -50,7 +50,7 @@
  104. require Exporter;
  105.  
  106. @ISA = qw(Exporter);
  107. -@EXPORT = qw(local_tz base64_decode);
  108. +@EXPORT = qw(local_tz base64_decode untaint_var);
  109.  
  110. use Mail::SpamAssassin;
  111. use Mail::SpamAssassin::Util::RegistrarBoundaries;
  112.