Thursday, 19 September 2013

Configuring postfix under OS X (10.8) with stunnel to Virgin Media SMTP

I am using the system-default version of postfix, but with SASL authentication provided by dovecot (as configured in this post).  One additional complexity of my configuration is that I need to have my ISP (Virgin Media) handle outgoing mail for me, as if I don't then mail is often bounced by the destination server as I am part of a blacklisted subnet.  This is further complicated in that Virgin Media run their SMTP server on a non-standard port and postfix doesn't support encrypted delivery on non-standard ports (see this message on the VM forums for some clarification).

I'm not going to cover standard postfix configuration, as there are better sites than this to do that, but I want to cover the use of dovecot to provide SASL authentication to my SMTP clients (i.e. me using my MacBook or Phone to send e-mail) and the tunnelling of outgoing SMTP through to Virgin Media.

Postfix


These are the additions/changes I made to /etc/postfix/main.cf:

relayhost = [127.0.0.1]:8465

mydomain_fallback = localhost

smtpd_use_tls = yes
smtpd_tls_security_level = encrypt
smtpd_tls_auth_only = yes
smtpd_tls_key_file = /private/etc/ssl/private/mydomain_com.key
smtpd_tls_cert_file = /private/etc/ssl/mydomain_com.crt
smtpd_tls_CAfile = /private/etc/ssl/private/PositiveSSLCA2.crt
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = /opt/local/var/run/dovecot/auth-client
smtpd_sasl_security_options = noanonymous
smtpd_pw_server_security_options = gssapi,login,plain
smtp_use_tls = yes
smtp_sasl_auth_enable = yes
smtp_sasl_security_options =
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd

Note that the smtp_sasl_password_maps file looks like this:

$ ls -l /etc/postfix/sasl_passwd
-rw-------  1 root  wheel  114 Sep 18 10:57 sasl_passwd
$ sudo cat /etc/postfix/sasl_passwd
[127.0.0.1]:8465        username@virginmedia.com:password

Whenever you make a change to this file you need to run postmap on the file in order to recreate the hash file:

$ sudo postmap /etc/postfix/sasl_passwd

postfix launchd configuration


There is, of course, a default launchd configuration file for postfix, however I think I removed the Disabled key, in order to avoid having to use the -w flag with launchctl.  This is the whole file:

$ cat /System/Library/LaunchDaemons/org.postfix.master.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>KeepAlive</key>
        <true/>
        <key>Label</key>
        <string>org.postfix.master</string>
        <key>Program</key>
        <string>/usr/libexec/postfix/master</string>
        <key>ProgramArguments</key>
        <array>
                <string>master</string>
        </array>
        <key>QueueDirectories</key>
        <array>
                <string>/var/spool/postfix/maildrop</string>
        </array>
        <key>AbandonProcessGroup</key>
        <true/>
</dict>
</plist>


stunnel


In order to install stunnel, I used macports:

$ sudo port install stunnel

The stunnel configuration file is quite simple:

$ cat /opt/local/etc/stunnel/smtp_virginmedia.conf
client = yes
connect = smtp.virginmedia.com:465

This is simple as I want to run stunnel in "inetd" mode, which means that the system will listen on the local port used to tunnel the connection (port 8465) and invoke stunnel when a connection is accepted.  The alternative approach is to run stunnel in "daemon" mode where it runs all the time listening on whatever ports it is configured to tunnel.  I chose "inetd" mode as I thought it might be more efficient and I also wanted to play about with launchd configuration files.

OS X doesn't have a traditional inetd and instead uses launchd. Configuring that took a fair amount of time.  The macport stunnel port doesn't provide a launchd configuration file, however given stunnel came from macports I followed their convention of locating the .plist file in /opt/local/etc/LaunchDaemons and creating a symbolic link to /Library/LaunchDaemons:

$ sudo bash
# cd /opt/local/etc/LaunchDaemons
# mkdir org.macports.stunnel
# vi org.macports.stunnel/org.macports.stunnel.plist

Here are the contents:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd" >
<plist version='1.0'>
<dict>
    <key>Label</key>
    <string>org.macports.stunnel</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/local/bin/stunnel</string>
<string>/opt/local/etc/stunnel/smtp_virginmedia.conf</string>
    </array>
    <key>inetdCompatibility</key>
    <dict>
        <key>Wait</key>
        <false/>
    </dict>
    <key>Debug</key>
    <false/>
    <key>Disabled</key>
    <false/>
    <key>KeepAlive</key>
    <false/>
    <key>Sockets</key>
    <dict>
        <key>Listeners</key>
        <dict>
            <key>SockServiceName</key>
            <string>8465</string>
            <key>SockType</key>
            <string>stream</string>
            <key>SockFamily</key>
            <string>IPv4</string>
        </dict>
    </dict>
</dict>
</plist>

# cd /Library/LaunchDaemons
# ln -s /opt/local/etc/LaunchDaemons/org.macports.stunnel/org.macports.stunnel.plist .
# launchctl load /Library/LaunchDaemons/org.macports.stunnel.plist

Testing


It took me a while to get the configuration working (mostly because of broken postfix configuration, but also because I was using the wrong username), however the following method is the best I found to test both the stunnel configuration and the authentication against the Virgin Media SMTP server:

Create the Base64 encoding of the username/password you put into /etc/postfix/sasl_passwd

$ perl -MMIME::Base64 -e 'print encode_base64("username");'
dXNlcm5hbWU=
$ perl -MMIME::Base64 -e 'print encode_base64("password");'
cGFzc3dvcmQ=

and invoke the smtp tunnel:

 $ telnet localhost 8465
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 know-smtprelay-3-imp bizsmtp ESMTP server ready
EHLO trojanfoe.com
250-know-smtprelay-3-imp hello [82.31.123.207], pleased to meet you
250-HELP
250-AUTH LOGIN PLAIN
250-SIZE 36700160
250-8BITMIME
250 OK
AUTH LOGIN
334 VXNlcm5hbWU6
dXNlcm5hbWU=
334 UGFzc3dvcmQ6
cGFzc3dvcmQ=
535 Authentication Credentials Invalid (VM300)
Connection closed by foreign host.

The reason the authentication failed was because I literally pasted the Base64 of "username" and "password", however once you get the username/password right you will be able to see this succeeding).

That's pretty much it; you'll need to unload postfix (if it's currently loaded) from launchd and reload it, using the normal:

$ sudo launchctl load /System/Library/LaunchDaemons/org.postfix.master.plist

No comments:

Post a Comment