Recently I decided to do some restructuring of a Postfix/Amavis/ClamAV 
installation and ran into a puzzling situation. After some head-scratching, I 
came up with a solution and thought I'd share it, in case it should be helpful 
to others (that's also why I'm posting here, rather than to the developers 
list).

FWIW, the setup is Amavis 2.12.1 on Linux with Perl 5.30, and ClamAV 0.103.2. 
The packages are loosely based on Fedora but locally-built.

Now, as for the setup: 

* There are two user accounts, "amavis" and "clamscan". 
* Both are members of "clamgroup". 
* The ClamAV socket is owned by user "clamscan", 
* and "clamgroup" has r+w permission on it. 

Unfortunately, that won't fly, at least not with $daemon_group = "amavis" in 
amavisd.conf. That brings the infamous "Permission denied" on the socket.

However, with $daemon_group = "clamgroup", all is well, and the amavisd
daemon can talk to clamd, as expected. Incidentally, that means that
things on disk are OK.

But I didn't like that "solution", so I wondered why amavisd seems to ignore 
the supplementary groups.

In the end, inserting a call to initgroups() into the drop_priv() function took 
care of that.

The patch that I am applying to my local build is given below. In
case it gets garbled, the really relevant line in full is:

   Unix::Groups::FFI::initgroups($desired_user);

This is inserted in front of the setgid/setuid calls (at line 18889 or
so). 

I have also sprinkled some logging statements in between. They are helpful to 
see the difference between
running it with and without the initgroups() call being made.

The possible downside is that this call introduces a dependency on 
perl-Unix-Groups-FFI, even in situations where no privilege drop is 
desired/required.

For me, that is no problem. If it is, it might be possible to add a Y/N config 
variable like $daemon_extra_groups, and pull in initgroups() only if this is 
set to true. But that would be confusing. I think that the user/group concept 
should be honored out of the box. Other than the extra dependency, I don't see 
any reason why not.

Compare to ClamAV, where they used to have an "AllowSupplementaryGroups" 
setting. This is now obsolete and it always "allows supplementary groups".

Comments welcome, if any.

Best,

Luc Pardon


--- a/amavisd.orig      2021-05-15 11:19:01.419229284 +0200
+++ b/amavisd   2021-05-15 11:20:15.608210946 +0200
@@ -239,6 +239,7 @@
     MIME::Decoder::Base64 MIME::Decoder::Binary MIME::Decoder::QuotedPrint
     MIME::Decoder::NBit MIME::Decoder::UU MIME::Decoder::Gzip64
     Net::LibIDN Net::Server Net::Server::PreFork
+    Unix::Groups::FFI
   ));
   # with earlier versions of Perl one may need to add additional modules
   # to the list, such as: auto::POSIX::setgid auto::POSIX::setuid ...
@@ -18886,8 +18887,22 @@
   }
   defined $gid or die "drop_priv: No such group: $desired_group\n";
   $( = $gid;  $) = "$gid $gid";   # real and effective GID
+
+  my @groups = Unix::Groups::FFI::getgrouplist($desired_user) 
+                 or print "drop_priv: Can't getgrouplist for $desired_user: 
$!";
+  do_log(5, "Grouplist for $desired_user: " . join(', ',@groups) );
+
+  my $rc = Unix::Groups::FFI::initgroups($desired_user);
+  do_log(5, "initgroups($desired_user) returns $rc");
+
   POSIX::setgid($gid) or die "drop_priv: Can't setgid to $gid: $!";
+  @groups = Unix::Groups::FFI::getgroups() or print "drop_priv: Can't 
getgroups: $!";
+  do_log(5, "getgroups() after setgid() : " . join(', ',@groups) );
+
   POSIX::setuid($uid) or die "drop_priv: Can't setuid to $uid: $!";
+  @groups = Unix::Groups::FFI::getgroups() or print "drop_priv: Can't 
getgroups: $!";
+  do_log(5, "getgroups() after setuid() : " . join(', ',@groups) );
+
   $> = $uid; $< = $uid;  # just in case
 # print STDERR "desired user=$desired_user ($uid), current: EUID: $> ($<)\n";
 # print STDERR "desired group=$desired_group ($gid), current: EGID: $) ($()\n";



Reply via email to