Author: vetinari
Date: Wed May 14 12:09:02 2008
New Revision: 905

Modified:
   trunk/qpsmtpd-prefork

Log:
prefork: - add --detach option to daemonize like forkserver
         - use user/group switching from forkserver to support secondary
           groups (needed with plugins/queue/postfix-queue)


Modified: trunk/qpsmtpd-prefork
==============================================================================
--- trunk/qpsmtpd-prefork       (original)
+++ trunk/qpsmtpd-prefork       Wed May 14 12:09:02 2008
@@ -73,6 +73,7 @@
 my $status          = 0;
 my $signal          = '';
 my $pretty          = 0;
+my $detach          = 0;
 my $user;
 
 # help text
@@ -91,6 +92,7 @@
 --user username     : User the daemon should run as
 --pid-file path            : Path to pid file
 --renice-parent int : Subtract value from parent process nice level (default: 
$re_nice)
+--detach            : detach from controlling terminal (daemonize)
 --help              : This message
 EOT
     exit 0;
@@ -109,10 +111,11 @@
     'pretty-child'    => \$pretty,
     'user=s'          => \$user,
     'renice-parent=i' => \$re_nice,
+    'detach'          => \$detach,
     'help'            => \&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
 $maxconnip = $max_children if ($maxconnip == 0);
@@ -125,26 +128,32 @@
   if (!$idle_children || $idle_children > $max_children || $idle_children < 
-1);
 $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();
 
 #start daemon
 sub run {
     # get UUID/GUID
-    my ($uuid, $ugid, $group);
+    my ($quid, $qgid, $groups);
     if ($user) {
-        my $T_uuid  = `id -u $user`;
-        my $T_ugid  = `id -g $user`;
-        my $T_group = `id -n -g $user`;
-        chomp($T_uuid);
-        chomp($T_ugid);
-        chomp($T_group);
-
-        # make the following vars taint happy
-        $uuid  = $1 if ($T_uuid  =~ /(\d+)/);
-        $ugid  = $1 if ($T_ugid  =~ /(\d+)/);
-        $group = $1 if ($T_group =~ /(\w+)/);
-        die("FATAL: unknown user <$user> or missing group information")
-          if (!$uuid || !$ugid);
+        (undef, undef, $quid, $qgid) = getpwnam $user
+          or die "unable to determine uid/gid for $user\n";
+        $groups = "$qgid $qgid";
+        while (my ($name,$passwd,$gid,$members) = getgrent()) {
+            my @m = split(/ /, $members);
+            if (grep {$_ eq $user} @m) {
+                $groups .= " $gid";
+            }
+        }
+        endgrent;
     }
 
     my @Socket_opts = (
@@ -182,12 +191,12 @@
 
     if ($user) {
         # change UUID/UGID
-        $) = "$ugid $ugid";    # effective gid
-        $( = $ugid;            # real gid
-        $> = $uuid;            # effective uid
-        $< = $uuid;            # real uid. we now cannot setuid anymore
-        die "FATAL: failed to setuid to user: $user, uid: $uuid\n"
-          if ($> != $uuid and $> != ($uuid - 2**32));
+        $) = $groups;
+        POSIX::setgid($qgid) or die "unable to change gid: $!\n";
+        POSIX::setuid($quid) or die "unable to change uid: $!\n";
+        $> = $quid;
+        die "FATAL: failed to setuid to user: $user, uid: $quid\n"
+          if ($> != $quid and $> != ($quid - 2**32));
     }
 
     # setup shared memory

Reply via email to