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.

30 April 2012

MYSQL update and select at the same time (almost)

How

You have to update to a variable then select the value of the variable.

update `datatable` set `rate` := @a := (`rate` + 2);

select @a as `index`;

(Note you have to use the funky := operator, which means this is really definitely an assignment operation)

But why do it like this?

This allows you an atomic operation, updating a column, and returning the value at the same time, without using table locking. Apparently the update operation is atomic, so provided the database connection is not shared @a will not be overwritten.

13 March 2012

Apache "AllowOverride None" confusion

Background

We had a situation where, there was a Apache Server with virtual hosts configured, one of the virtual hosts  was located at

eg. /var/www/mysite

Under there was another media folder called media.

/var/www/mysite/media

I wanted to serve the media as a separate virtual host.  The basic configuration was easy enough, just create a separate symlinked virtual host configuration file in /etc/apache2/sites-enabled for the new media site.

What went wrong

Everything seemed to work fine if the files (jpgs) were found in the media folder they were returned to the client as expected, however if a file was missing the server was generating server redirection errors, instead of 404s.

This was causing me to tear my hair out.  Why redirection errors?  There was no .htaccess file in the media folder, and in the directory section in the virtual host configuration "AllowOverride None" was set.  So I was reasonably expecting that no .htaccess file would be processed for this virtual host, and as there wasn't one in the media folder anyway, I couldn't understand which rules was it processing to end up with redirection errors.

What was really happening

AllowOverride None meant that no .htacces directives in the media folder were being applied, but because there was an .htaccess in the parent folder for the site virtual host, those rules were being applied instead, which is where the redirect rules were located causing the redirect fail.

How to fix

Adding another directory section to the virtual host config did the trick, this prevented the parent .htaccess file from being processed.

[Directory /]
   AllowOverride None 
   Options None
[/Directory]

*angle brackets changed because of blogger

(If you want to be really restrictive you should add "Deny from all" in there too, just make sure you add "Allow from all" in your home directory section )

Why the fix works

.htaccess files are processed from the current folder to the parent folder and all the way up to the root folder (of the disk!). Setting "AllowOverride None" on /var/www/mysite/media meant that in the media folder and down, no .htacces files are processed, but they still inherit from the parent folders.

Setting the AllowOverride None on the root folder meant that no .htaccess files are processed except those in the folders that I explicitly allow.