SELinux interfering with Postfix

Posted on . Updated on .

This is the last post I’ll write about migrating to Fedora and I’ll cover the problem that made me waste more time. I hadn’t run a system with SELinux before and I had trouble finding the source of the problem. Only after searching and reading a lot of web pages, forums and wikis I found a reference to SELinux that clicked in my mind. I’ll bear SELinux in mind for future similar problems.

Long story short, I monitor my hard drives with “smartd” and have it configured to send an email to my user account in case of trouble. I soon realized local mail wasn’t working because Fedora’s minimal installation doesn’t include an MTA by default. From the possible choices in Fedora, I went with Postfix. It’s modern and simple to configure for local mail delivery only. In fact, Fedora’s default configuration file comes prepared exactly for that purpose, with very sane defaults. A quick test confirmed local mail was working, and I forwarded root’s mail to my user account too.

Stage two of the plan involved setting up a $HOME/.forward file for my user that delivered mail to both the local mailbox and an external mail address at my domain. I already had a script prepared for that using some common tools for this situation: “msmtp” to deliver mail to the external address, “formail” (from the procmail package) to slightly modify it before sending it, and “getmail_mbox” (from the getmail package) to deliver it locally unmodified. I’m posting the script below in case you find it useful.

#!/bin/sh
FROM_ADDRESS=foo@example.com
TO_ADDRESS=bar@example.com
MAILBOX=/var/spool/mail/user
TEMPORARY_FILE="$( mktemp /tmp/mailforward.XXXXXX )"
cat >"$TEMPORARY_FILE"
SUBJECT="$( formail -x Subject -c <"$TEMPORARY_FILE" )"
<"$TEMPORARY_FILE" formail \
        -i "From: $FROM_ADDRESS" \
        -i "To: $TO_ADDRESS" \
        -i "Subject: [localhost]$SUBJECT" \
        | msmtp -f "$FROM_ADDRESS" "$TO_ADDRESS"
getmail_mbox "$MAILBOX" <"$TEMPORARY_FILE"
rm "$TEMPORARY_FILE"

That script usually sits as a link named $HOME/bin/mailforward pointing to the real location of the file somewhere else in my home directory (where I keep it under version control), and my .forward file pipes all incoming local mail to it.

"|/home/user/bin/mailforward"

I enabled that but surprisingly I noticed I was receiving my local mail only at the local mailbox. SELinux just wasn’t in my mind, but it was preventing the local mail process in Postfix from executing the script, which resided in my $HOME/bin directory as mentioned before. I thought it was a problem with Postfix and wasted more than one hour trying to find out what could be wrong.

There are several possible solutions to the real problem. One is simply disabling SELinux. You can do that by editing /etc/selinux/config and changing SELINUX to the value “disabled”. A reboot is needed, as far as I know, and I don’t remember if running dracut to regenerate the initial RAM disk is needed too.

A second solution is to disable SELinux only for that Postfix process. I read you can do that but I didn’t investigate how to do it.

The third and more elegant solution is simply allowing that specific action that’s currently being denied. I know nothing about SELinux but it’s surprisingly easy to do and well documented. It turns out when SELinux denies permission to do something, it writes a line in /var/log/audit/audit.log describing that event in detail, and that log line is enough for a tool called “audit2allow” to generate a SELinux policy file that can be added to the system allowing the operation, hence the tool name.

Suppose you extract the specific log lines to a file named denied.log and you set on the name “postfixlocal” for the set of rules you want to create. You’d simply run the following.

audit2allow -m postfixlocal <denied.log >postfixlocal.te
semodule -i postfixlocal.pp

The first command creates the SELinux policy, in two forms. A textual form in postfixlocal.te and a “compiled” form in postfixlocal.pp. The second line copies postfixlocal.pp to a special directory and adds the rules in it to the current set of SELinux policies, making it a permanent change.

In my case, the contents of postfixlocal.te were something like this:

module postfixlocal 1.0;

require {
        type user_home_t;
        type home_bin_t;
        type postfix_local_t;
        class lnk_file read;
        class file { execute execute_no_trans };
}

#============= postfix_local_t ==============
allow postfix_local_t home_bin_t:lnk_file read;
allow postfix_local_t user_home_t:file { execute execute_no_trans };

After that, mail forwarding was working. If SELinux gives me more headaches, I’ll consider disabling it. I don’t think it’s really important for a workstation. But so far that’s the only problem I had with it, and it’s nice to have that extra protection for free. You can simply forget about it. For future weird problems, I’ll remember to check /var/log/audit/audit.log just in case.

comments powered by Disqus