--- spamd.bak 2004-04-09 08:21:39.275541000 -0400 +++ spamd 2004-04-09 16:29:00.537194000 -0400 @@ -128,6 +128,7 @@ 'setuid-with-ldap' => \$opt{'setuid-with-ldap'}, 'Q' => \$opt{'setuid-with-sql'}, 'virtual-config-dir=s' => \$opt{'virtual-config-dir'}, + 'virtual-config-account=s' => \$opt{'virtual-config-account'}, 'pidfile|r=s' => \$opt{'pidfile'}, 'syslog|s=s' => \$opt{'syslog'}, 'syslog-socket=s' => \$opt{'syslog-socket'}, @@ -1189,32 +1190,55 @@ { my ($username) = @_; - my $dir=$opt{'virtual-config-dir'}; + my $vdir=$opt{'virtual-config-dir'}; my $userdir; my $prefsfile; - if (defined $dir) { + my ($name,$pwd,$uid,$gid,$quota,$comment,$gcos,$dir,$etc) = getpwnam($username); + + # If this is a real user, handle as if not virtual + if ((defined $dir) && ($opt{'virtual-config-account'})) { + $setuid_to_user = 1; + my $retcd = handle_user ($username); + return $retcd; + } + + if (defined $vdir) { my $safename = $username; $safename =~ s/[^-A-Za-z0-9\+_\.\,\@\=]/_/gs; my $localpart = ''; my $domain = ''; if ($safename =~ /^(.*)\@(.*)$/) { $localpart = $1; $domain = $2; } - $dir =~ s/\%u/${safename}/g; - $dir =~ s/\%l/${localpart}/g; - $dir =~ s/\%d/${domain}/g; - $dir =~ s/\%\%/\%/g; - - $userdir = $dir; - $prefsfile = $dir.'/user_prefs'; - # Log that the default configuration is being used for a user. - logmsg("Using default config for $username: $prefsfile"); + $vdir =~ s/\%u/${safename}/g; + $vdir =~ s/\%l/${localpart}/g; + $vdir =~ s/\%d/${domain}/g; + $vdir =~ s/\%\%/\%/g; + + $userdir = $vdir; + $prefsfile = $vdir.'/user_prefs'; +# # Log that the default configuration is being used for a user. +# logmsg("Using default config for $username: $prefsfile"); + } + + my $msg = "checking for " . $prefsfile; + if ($opt{'virtual-config-account'}) { + handle_setuid_change ($opt{'virtual-config-account'}, + $msg, $userdir); } if (-f $prefsfile) { # Found a config, load it. $spamtest->read_scoreonly_config($prefsfile); - } + } elsif ($opt{'create-prefs'}) { + if ((! -d $userdir) && (! mkdir $userdir, 0700)) { + logmsg "info: failed to create $userdir for $username."; + } else { + create_default_cf_if_needed ($prefsfile, + $opt{'virtual-config-account'}, $userdir); + $spamtest->read_scoreonly_config($prefsfile); + } + } # assume that $userdir will be a writable directory we can # use for AWL, Bayes dbs etc. @@ -1561,6 +1585,46 @@ # note: do not do 'return if linux'; for some reason, it doesn't work } +sub handle_setuid_change { + my $username = shift; + my $msg = shift; + my $newdir = shift; + my ($name,$pwd,$uid,$gid,$quota,$comment,$gcos,$dir,$etc) = getpwnam($username); + + if (defined($newdir)) { $dir = $newdir;} + + if ( !$spamtest->{'paranoid'} && !defined($uid) ) { + #if we are given a username, but can't look it up, + #Maybe NIS is down? lets break out here to allow + #them to get 'defaults' when we are not running paranoid. + logmsg "handle_user() -> unable to find user [$username]!\n"; + return 0; + } + + $uid =~ /^(\d+)$/ and $uid = $1; # de-taint + $gid =~ /^(\d+)$/ and $gid = $1; # de-taint + + $) = "$gid $gid"; # change eGID + $> = $uid; # change eUID + if ( !defined($uid) || ($> != $uid and $> != ($uid-2**32))) { + logmsg "fatal: setuid to $username failed"; + die; # make it fatal to avoid security breaches + } + else { + if (defined($newdir)) { + $spamtest->signal_user_changed ({ username => $username, + user_dir => $newdir }); + } else { + $spamtest->signal_user_changed ({ username => $username}); + } + if (defined($msg)) { + logmsg "info: setuid to $username succeeded, ". $msg; + } else { + logmsg "info: setuid to $username succeeded."; + } + } +} + __DATA__ =head1 NAME @@ -1740,6 +1804,16 @@ The pattern B expand to an absolute directory when spamd is running daemonized (B<-d>). +=item B<--virtual-config-account>=I +When this option is used in conjunction with then B<--virtual-config-dir> +and spamc sends a virtual username (i.e. jm@example.com), spamd will change +to this account id to access/create the user preferences directory. + +If a username is passed to spamd that is in the /etc/passwd file, then +spamd processes that user as if B<--virtual-config-dir> had not been +specified. This is useful when some accounts are real and some are +virtual. + =item B<-r> I, B<--pidfile>=I Write the process ID of the spamd parent to the file specified by I.