prefork: - add --detach option to daemonize like forkserver

- use user/group switching from forkserver to support secondary
	   groups (needed with plugins/queue/postfix-queue)


git-svn-id: https://svn.perl.org/qpsmtpd/trunk@905 958fd67b-6ff1-0310-b445-bb7760255be9
This commit is contained in:
Hanno Hecker 2008-05-14 19:09:02 +00:00
parent 96d3f6d40a
commit 502e1d286e

View File

@ -73,6 +73,7 @@ my $quiet = 0;
my $status = 0; my $status = 0;
my $signal = ''; my $signal = '';
my $pretty = 0; my $pretty = 0;
my $detach = 0;
my $user; my $user;
# help text # help text
@ -91,6 +92,7 @@ Usage: qpsmtpd-prefork [ options ]
--user username : User the daemon should run as --user username : User the daemon should run as
--pid-file path : Path to pid file --pid-file path : Path to pid file
--renice-parent int : Subtract value from parent process nice level (default: $re_nice) --renice-parent int : Subtract value from parent process nice level (default: $re_nice)
--detach : detach from controlling terminal (daemonize)
--help : This message --help : This message
EOT EOT
exit 0; exit 0;
@ -109,10 +111,11 @@ GetOptions(
'pretty-child' => \$pretty, 'pretty-child' => \$pretty,
'user=s' => \$user, 'user=s' => \$user,
'renice-parent=i' => \$re_nice, 'renice-parent=i' => \$re_nice,
'detach' => \$detach,
'help' => \&usage, 'help' => \&usage,
) || &usage; ) || &usage;
$user = $1 if ($user =~ /(\w+)/); if ($user =~ /^([\w\-]+)$/) { $user = $1 } else { &usage }
# set max from ip to max number of children if option is set to disabled # set max from ip to max number of children if option is set to disabled
$maxconnip = $max_children if ($maxconnip == 0); $maxconnip = $max_children if ($maxconnip == 0);
@ -125,26 +128,32 @@ $idle_children = $max_children
if (!$idle_children || $idle_children > $max_children || $idle_children < -1); if (!$idle_children || $idle_children > $max_children || $idle_children < -1);
$chld_pool = $idle_children; $chld_pool = $idle_children;
if ($detach) {
open STDIN, '/dev/null' or die "/dev/null: $!";
open STDOUT, '>/dev/null' or die "/dev/null: $!";
open STDERR, '>&STDOUT' or die "open(stderr): $!";
defined (my $pid = fork) or die "fork: $!";
exit 0 if $pid;
POSIX::setsid or die "setsid: $!";
}
run(); run();
#start daemon #start daemon
sub run { sub run {
# get UUID/GUID # get UUID/GUID
my ($uuid, $ugid, $group); my ($quid, $qgid, $groups);
if ($user) { if ($user) {
my $T_uuid = `id -u $user`; (undef, undef, $quid, $qgid) = getpwnam $user
my $T_ugid = `id -g $user`; or die "unable to determine uid/gid for $user\n";
my $T_group = `id -n -g $user`; $groups = "$qgid $qgid";
chomp($T_uuid); while (my ($name,$passwd,$gid,$members) = getgrent()) {
chomp($T_ugid); my @m = split(/ /, $members);
chomp($T_group); if (grep {$_ eq $user} @m) {
$groups .= " $gid";
# make the following vars taint happy }
$uuid = $1 if ($T_uuid =~ /(\d+)/); }
$ugid = $1 if ($T_ugid =~ /(\d+)/); endgrent;
$group = $1 if ($T_group =~ /(\w+)/);
die("FATAL: unknown user <$user> or missing group information")
if (!$uuid || !$ugid);
} }
my @Socket_opts = ( my @Socket_opts = (
@ -182,12 +191,12 @@ sub run {
if ($user) { if ($user) {
# change UUID/UGID # change UUID/UGID
$) = "$ugid $ugid"; # effective gid $) = $groups;
$( = $ugid; # real gid POSIX::setgid($qgid) or die "unable to change gid: $!\n";
$> = $uuid; # effective uid POSIX::setuid($quid) or die "unable to change uid: $!\n";
$< = $uuid; # real uid. we now cannot setuid anymore $> = $quid;
die "FATAL: failed to setuid to user: $user, uid: $uuid\n" die "FATAL: failed to setuid to user: $user, uid: $quid\n"
if ($> != $uuid and $> != ($uuid - 2**32)); if ($> != $quid and $> != ($quid - 2**32));
} }
# setup shared memory # setup shared memory