13 June 2012

OpenEMM with SELinux

We have OpenEMM installed on a CentOS 6 VM.

Emails could be sent fine, but bounce management wasn't working, and worse, it was breaking sendmail as no local mails were getting through. ie root@localhost would not be delivered.

Looking in /var/log/maillog I got this error:


Jun 13 12:00:41 news sendmail[7711]: q5DB0fF9007711: Milter (bav): error connecting to filter: Permission denied
Jun 13 12:00:41 news sendmail[7711]: q5DB0fF9007711: Milter (bav): to error state
Jun 13 12:00:41 news sendmail[7711]: q5DB0fF9007711: Milter: initialization failed, temp failing commands

I guessed that the problem was the connection to the bav filter.  In the sendmail.mc the input mail filter lines points to the bav.sock file:


INPUT_MAIL_FILTER(`bav', `S=unix:/home/openemm/var/run/bav.sock, F=T')dnl

The permissions on the bav.sock file were 0775, so at first I tried changing this to 777, but that had no effect at all.  Then I hit upon the problem.

THE PROBLEM:  SE Linux was enabled, and prevented sendmail talking to the bav filter.

This can be seen in the /var/log/audit/audit.log:


type=AVC msg=audit(1339590098.672:140014): avc:  denied  { connectto } for  pid=8178 comm="sendmail" path="/home/openemm/var/run/bav.sock" scontext=unconfined_u:system_r:sendmail_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket
type=SYSCALL msg=audit(1339590098.672:140014): arch=c000003e syscall=42 success=no exit=-13 a0=5 a1=7fff2fdcd6d0 a2=6e a3=7fff2fdcd3e0 items=0 ppid=7697 pid=8178 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=51 sgid=51 fsgid=51 tty=(none) ses=10525 comm="sendmail" exe="/usr/sbin/sendmail.sendmail" subj=unconfined_u:system_r:sendmail_t:s0 key=(null)


Sendmail was making a request to the bav.sock unix socket, which was being blocked by SELinux, with the result that all incoming emails were being qeueued up, and never being processed.  I proved this by disabling the bav filter in selinux.mc, and I got a flood of incoming mail....

One suggestion I came across was to disable SELinux, which lets face it, really isn't a solution.

THE SOLUTION: I had to create and install an SELinux module to enable this connection.

First I had to install the policycoreutils, this includes the all important audit2allow utility.

yum install policycoreutils-python

Then run the command:

grep sendmail_t /var/log/audit/audit.log | audit2allow -M openemm

This creates 2 files openemm.pp, and openemm.te.

The contents of openemm.te are


module openemm 1.0;

require {
        type sendmail_t;
        type unconfined_t;
        type initrc_t;
        class unix_stream_socket connectto;
}

#============= sendmail_t ==============
allow sendmail_t initrc_t:unix_stream_socket connectto;
allow sendmail_t unconfined_t:unix_stream_socket connectto;


This I guess allows sendmail to connect to a unix socket.

Then I ran the following command to install the module. (make sure you add the .pp extension)

semodule -i openemm.pp

After this everything started working as expected


Update Sept 2012:

Everything still doesn't work as expected, such is life.  Bounce management requires procmail working, and procmail was having issues running the bav process.  I was getting the following error in sendmail:


/home/openemm/bin/scripts/scan_and_unsubscribe: cannot execute binary file


However running the audit2allow again specifying procmail_t, and make sure the output file is procmail2 as procmail already exists as a module.

Useful article on selinux configuration:  http://omotech.com/blog/?p=196


Update April 2014:

After another CentOS update SELinux decided to block access to the sendmail folders in the openemm home directory.   So we had to jump through the audit hoops to get it working again.  This time I combined my previous policy attempts for sendmail/openemm into a single file, compiled the pp file, and upgraded the existing policy.

Here is my latest policy file:

module openemm 4;

require {
type unconfined_t;
type initrc_t;
type sendmail_t;
type setfiles_t;
type ptmx_t;
type home_root_t;
type user_tmp_t;
type user_home_t;
type user_home_dir_t;
class sock_file { getattr read write };
class dir { read write getattr remove_name add_name };
class file { rename open create read write getattr lock unlink };
class lnk_file { read write getattr };
class chr_file { read write getattr };
class unix_stream_socket connectto;
}

#============ setfiles_t ==============
allow setfiles_t ptmx_t:chr_file { read write getattr };

#============= sendmail_t ==============
allow sendmail_t initrc_t:unix_stream_socket connectto;
allow sendmail_t unconfined_t:unix_stream_socket connectto;
allow sendmail_t ptmx_t:chr_file { read write getattr };

allow sendmail_t user_home_dir_t:dir { read write getattr remove_name add_name };
allow sendmail_t user_home_dir_t:file { write getattr read lock unlink open rename create };
allow sendmail_t user_home_dir_t:sock_file { read write getattr };
allow sendmail_t user_home_dir_t:lnk_file { read write getattr };

allow sendmail_t user_home_t:dir { read write getattr remove_name add_name };
allow sendmail_t user_home_t:file { write getattr read lock unlink open rename create };
allow sendmail_t user_home_t:sock_file { read write getattr };
allow sendmail_t user_home_t:lnk_file { read write getattr };

allow sendmail_t user_tmp_t:dir { read write getattr remove_name add_name };
allow sendmail_t user_tmp_t:file { write getattr read lock unlink open rename create };
allow sendmail_t user_tmp_t:sock_file { read write getattr };

I have also created a script file to compile the policy file:


#!/bin/bash
rm openemm.mod
rm openemm.pp
checkmodule -M -m -o openemm.mod openemm.te
semodule_package -m openemm.mod -o openemm.pp


Running the script file creates the openemm.pp file from the openemm.te file.  Provided you change the version number at the top of the policy file (the line saying: module openemm 2.1;) rather than installing another policy it is possible to upgrade the existing policy, with the command:

semodule -u openemm.pp

Useful article on compling polices: melikedev.com
semodule command on Fedora: semodule

Update April 2018:

This has now been updated for OpenEMM 2015 R3,

It has also been added to github

Also its worth noting that sometimes the SELinux context of the files can get all messed up, and the module above doesn't work.  When I upgraded, I first extracted the files to the /tmp folder, which then gave all the files an SE context of usr_tmp_t:

To show all the file security contexts do:

# ls -Z

If you go to /home, and issue the command:

#restorecon openemm

This will reset the security context of the openemm files, back to what they ought to be, i.e. user_home_t and life will be sweeter again.