SELinux is that “thing” that breaks functionalities and makes sysadmins think there is some magical force preventing whatever process to write on a 777 permission file or connecting to a socket. Usually learning how to configure SELinux and disable particular restrictions is the best way to go, but when deploying multiple nodes for dev testing or qa behind a firewall or in a private network (virtual cloud) the fast solution is preferred.
Some typical “access denied” issues caused by SELinux are:
-
Configuring the database engine to access files on a different mount point (e.g. some storage freshly allocated in AWS). The database works flawlessly with data files on a certain path but after mounting the storage and putting the same file on the same path, the startup fails.
-
Postfix cannot deliver local mails through the LMTP socket (e.g. used by Cyrus Imap or Dovecot).
-
Errors with accessing paths in PHP scripts (well, not always a bad thing, this one).
Taking down SELinux is easy. The config file is /etc/selinux/config and the typical content is:
# This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - SELinux is fully disabled. SELINUX=enforcing # SELINUXTYPE= type of policy in use. Possible values are: # targeted - Only targeted network daemons are protected. # strict - Full SELinux protection. SELINUXTYPE=targeted # SETLOCALDEFS= Check local definition changes SETLOCALDEFS=0
The obvious “fix” is to replace enforcing with any of the other 2 options. The “permissive” one will fill up a log with various warnings and would-be restrictions that can help do some proper configuration. But the real solution is to just put “disabled” in there and forget about it. *
Oh, and the node must be restarted:
$ sudo telinit 6
That’s it, have fun!
* No, this is not the real solution on a security-aware environment. Learning SELinux is the actual way to go for the long term (while I agree to you that the syntax is messy and the controls are way too fine grained, which is a good and a bad thing at the same time). More reading on this topic:
Everybody’s favorite way of sending spam: the mail() function in PHP. But what about the bounced e-mails?
Yeah, about them. Where do they get sent back? Well, not so fast. Not always to the “From” address of the original e-mail, that’s for sure. The e-mail servers return e-mails to the “envelope sender” which may or may not be the same as “From”. There used to be a special header, “Errors-To”, but it got deprecated and nowadays may simply be ignored.
Anyway, let’s go back to the “envelope sender”; this is set by the smtp client when connecting to the server and one would expect that the mail() from PHP be smart enough to deal with it. Let’s see how this function really works. First, let’s take a look in php.ini:
[mail function] ; For Win32 only. SMTP = localhost smtp_port = 25 ; For Win32 only. sendmail_from = me@example.com ; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). sendmail_path = /usr/sbin/sendmail -t -i
On Windows it looks like mail() really handles everything by itself. On Linux it looks like the work is delegated to an external component – sendmail. Let’s take a look in the sendmail man page (well, actually the one from Postfix):
-i When reading a message from standard input, don´t treat a line with only a . character as the end of input.
-t Extract recipients from message headers. These are added to any recipients specified on the command line.
It looks like mail() fixes up the e-mail contents and then pipes it to sendmail; but what about the “envelope sender”? The sendmail man page is even more revealing:
-f sender Set the envelope sender address. This is the address where delivery problems are sent to. With Postfix versions before 2.1, the Errors-To: message header overrides the error return address.
No -f parameter is provided in this case; this means that bounces get sent to one of the following:
- for older e-mail systems, to the Errors-To: header e-mail address (if any provided in the 4th parameter of the mail() function);
- to the Return-Path: header e-mail address (if any provided in the 4th parameter of the mail() function);
- to the e-mail address that was automatically determined for the local user that executed the sendmail command (e.g. apache, nobody). Postfix stores it in the X-Postfix-Sender: header (added automatically).
If we want to avoid the 3rd scenario we must do some programming work. First, let’s notice that in php.ini one could change the e-mail sending program with a script of our own that can do some magic and then call sendmail:
sendmail_path = /usr/local/sbin/sendmail_wrapper
The script should obviously have the right permissions:
rwxr-xr-x 1 root root 814 Oct 4 15:45 sendmail_wrapper
One may write such script in Python or Ruby; PHP works wonderfully, though, as long as you do not call mail() in the script:
#!/usr/bin/php -q <?php set_time_limit(0); $mtext = ""; $from = ""; $has_return_path = false; // Feel free to replace regex with a better e-mail match $regex="/[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\.-][a-z0-9]+)*)+\\.[a-z]{2,}/i"; $stdin = fopen('php://stdin', 'r'); while(!feof($stdin)) { $cline=fgets($stdin); if (!((strpos($cline, "Return-Path:")===false))) if (preg_match_all($regex, $cline, $matches, PREG_PATTERN_ORDER)) $has_return_path = true; if (!((strpos($cline, "From:")===false))) if (preg_match_all($regex, $cline, $matches, PREG_PATTERN_ORDER)) $from = $matches[0][0]; $mtext.=$cline; } fclose($stdin); if (!empty($from) && !$has_return_path) $from_opt = ' -f'.$from; $fd=popen('/usr/sbin/sendmail -t -i'.$from_opt, 'w'); fwrite($fd, $mtext); pclose($fd); ?>
Well, that’s about it. I hope you enjoyed it.