exim4 with ssmtp on Debian

Update: You need to be careful if you are updating to the latest Debian Exim (~4.67), since the Debian config file format has changed slightly. I'm pretty sure this whole thing could be easier, so I have filed #430057. Instructions below updated slightly.

Sending secure mail seems to have two possible implementations; firstly you can connect over an insecure channel and issue a command (STARTTLS) which tells the SMTP server to start a secure channel. The other option is where you use a secure channel to start with. Usually this happens with an SSL (TLS) connection on port 465 which you then probably have to authenticate over.

Exim doesn't support this second model, seemingly by design. Which is a little annoying if that's all your ISP offers! You may like this on your laptop, since by authenticating you should be able to send email from anywhere through the ISP mail server.

What you need is a wrapper that provides the SSL connection between your computer and the ISP. Then you have to fool exim into using it, and direct it to send passwords unencrypted (though the underlying channel is safely encrypted).

Firstly, install stunnel; I found stunnel4 didn't work that well. Then create a script to start it and make a tunnel to your ISP. Put the following a file /etc/init.d/ssmtp-tunnel (change to your ISP's secure email server) and then run update-rc.d ssmtp-tunnel defaults (and start it with /etc/init.d/ssmtp-tunnel start).

#! /bin/sh -e

case "$1" in
  start)
    echo -n "Starting ssmtp tunnel "
    start-stop-daemon --start --quiet --exec /usr/sbin/stunnel -- -c -d ssmtp -r securemail.internode.on.net:ssmtp
    echo "stunnel."
    ;;
  stop)
    echo -n "Stopping ssmtp tunnel "
    start-stop-daemon --stop --quiet --oknodo --retry 2 --exec /usr/sbin/stunnel
    echo "stunnel."
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  *)
    echo "Usage: /etc/init.d/ssmtp-tunnel {start|stop|restart|reload|force-reload}"
    exit 1
esac

exit 0

If you telnet localhost 465 and see a normal SMTP connection, which is running over SSL, you have things working correctly.

Now you need to configure exim to use this to firstly authenticate, then send the email onto the smarthost.

Make sure you're using the big config file option with dpkg-reconfigure exim4-config. When it asks you what the smarthost should be, tell it localhost.

  • Firstly create the file /etc/exim4/exim4.conf.localmacros (if it doesn't already exist) and add a line AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS = true. This forces using authentication even though it looks like an unencrypted channel.

  • Then in /etc/exim4/exim4.conf.template, under the smarthost router (i.e. the line that starts smarthost:) add self = send. This allows what exim thinks is a router to an external MTA to actually go back to the localhost.

  • In the same file change the remote_smtp_smarthost (i.e the line that starts remote_smtp_smarthost:) transport to have:

    • hosts_avoid_tls = localhost
    • hosts_require_auth = localhost
    • port = 465

    (all on separate lines).

  • Add a line to /etc/exim4/passwd.client for localhost with your ISP username/password (or just use * if this is the only entry).

Finally, update the config file with update-exim4.conf and restart exim /etc/init.d/exim4 restart. All going well, Exim will now get the mail out wherever you are!

Dig Jazz Applet

I really enjoy DIG Jazz from the ABC. The digital radio channel via the TV set-top box is great to have on in the background when working from home, or you can use the streaming versions when work pays for the bandwidth :)

One slightly annoying thing is you hear something good and have to go to the website to figure out what was just played. I de-compiled the flash application to see where it gets its information, and it turns out it is just a fairly boring XML file. Since I've been meaning to get to know PyGtk a bit better, I knocked up a simple applet that, when clicked on, shows you the current song playing.

Dig Jazz Applet

Source code available here or I also made a Debian package.

Iceweasel to Firefox User-Agent

If you use Iceweasel and a website is complaining you don't have Firefox® (such as the Google toolbar installation page), download the user-agent switcher plugin and use it to import this specification. You can then "fake" being a plain-old Firefox® running on on Linux; the Iceweasel site provides one that fakes Firefox® on Windows XP should you need that.

Stopping at program at exit

Today I wanted a way to run a program to completion but stop it just before it is destroyed, therefore allowing me to inspect some /proc variables I was interested in.

As it happens the ptrace option PTRACE_O_TRACEEXIT is designed for just that. To use it, you first either attach to the process, or if forking a new process call PTRACE_TRACEME and exec as usual.

Then you use the ptrace call PTRACE_SETOPTIONS with the PTRACE_O_TRACEEXIT option in the data pointer, and wait for the traced process as usual (unfortunately due to a bug you will have to clag the #defines from the kernel header for now). There are now two conditions to handle:

  1. The child received a SIGTRAP with the PTRACE_EVENT_EXIT status set, signalling to us that it has exited. This is a terminal state; you can inspect the registers, etc, but the process can not come back to life now. This status is "overloaded" in the status returned by wait, e.g.

    /* wait for signal from child */
    waitpid(pid, &status, 0);
    
    /* any signal stops the child, so check that the incoming signal is a
    SIGTRAP and the event_exit flag is set */
    
    if ((WSTOPSIG(status) == SIGTRAP) &&
        (status & (PTRACE_EVENT_EXIT << 8)))
         ...
    
  2. Any other signal will have also caused the tracing parent to be woken, so we need to pass that signal through to the child process with a PTRACE_CONT call specifing the signal in the data pointer; e.g.

    /* if not, pass the original signal onto the child */
    if (ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status))) {
           perror("stopper: ptrace(PTRACE_CONT, ...)");
               exit(1);
    }
    

A straight forward example is stopper.c. The program allows you to run a program (or attach to a running program) and effecitvley pause it just before it exits, allowing you to inspect it and then manually dispose of it once you have the data you need.

Big Bands are Back!

8pm Monday nights sees the return of the Rhino Factory to the Zodiac Hotel, 244 Pitt Street. Plenty of couches, dance floor and of course Sydney's craziest 18 piece big band. It's only 10 metres from Town Hall station, so come and support live jazz, and of course have a few beers. Check out the myspace site for more music and photos.

CDBS + Autotools + Python

There is a bit of an art to getting CDBS to build packages with Python extensions made with autotools, so hopefully this will help someone. This might be appropriate where you have a library which ships with some Python modules you wish to package.

The basic idea is to re-build separate trees for the various Python versions you wish to support, and then install these separate builds to the same place before creating the final package.

  1. Firstly, add an XS line to the top of your control file with the Python versions to support, such as XS-Python-Version: >=2.3. Then get this into a variable in your rules file with pyversions

    PY_VERSIONS = $(shell pyversions --requested debian/control)
    

    You'll also want build dependencies on python-all-dev, python-central (>= 0.5).

  2. Your Python package also needs to be setup with the correct variables so it has the right dependencies, etc, something like

    Package: python-package
    Architecture: any
    Section: python
    Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}
    Provides: ${python:Provides}
    XB-Python-Version: ${python:Versions}
    Description: Python bindings for blah
     Description here
    
  3. Now the magic is to get multiple builds for each version of Python requested. The first thing to do is add a configure/python-packagename target which will get called early in the package creation phase. In standard make we can make this target depend on "stamp" files for each version of python we need to support. For example

    configure/python-packagename:: $(addprefix configure-stamp-, $(PY_VERSIONS))
    

    which expands to something like

    configure/python-packagename:: configure-stamp-2.3 configure-stamp-2.4 configure-stamp-2.5
    
  4. Now we make a implicit rule for anything called configure-stamp-% which will setup separate build directories for the different Python versions.

    configure-stamp-%:
            mkdir build-$*
            cd build-$* && PYTHON=`which $*` $(DEB_CONFIGURE_SCRIPT_ENV) \
                $(DEB_CONFIGURE_SCRIPT) \
                    $(DEB_CONFIGURE_NORMAL_ARGS) \
                    --disable-maintainer-mode \
                    $(cdbs_configure_flags) \
                    $(DEB_CONFIGURE_EXTRA_FLAGS) \
                    $(DEB_CONFIGURE_USER_FLAGS)
            touch $@
    

    You may want to tweak this, and it may be a bit fragile if CDBS decides to change the names of things.

  5. Now we have our extra versions configured, we have to organise actually building them. Do the same thing to create some build stamps, and in the implicit build-stamp rule change to the appropriate build directory.

    build-stamp-%:
            make -C build-$*
            touch $@
    
    build/python-package:: $(addprefix build-stamp-, $(PY_VERSIONS))
    
  6. Do the same thing for the install step -- hopefully what happens in this stage is that each build will put its shared libraries in /usr/lib/python2.*/site-packages/. Then it is a matter of putting them in python-package.install to be copied.

    install-stamp-%:
            make -C build-$* install DESTDIR=$(CURDIR)/debian/tmp
            touch $@
    
    install/python-package:: $(addprefix install-stamp-, $(PY_VERSIONS))
    
  7. To setup the right variables, etc, you need to call dh_pycentral for your package on binary-install. See the Python Policy for details on what this will do, especially if you are shipping Python files which need to be pre-compiled.

    binary-install/python-package::
        dh_pycentral
    
  8. Finally, clean up by extending the clean rule.

    clean::
            -rm -rf $(addprefix build-, $(PY_VERSIONS))
            -rm -rf $(addprefix configure-stamp-, $(PY_VERSIONS))
            -rm -rf $(addprefix build-stamp-, $(PY_VERSIONS))
            -rm -rf $(addprefix install-stamp-, $(PY_VERSIONS))
    

Thanks to Sebastien Bacher, who I think came up with this scheme originally for gnome-menus.

Offline status: online

I defy anyone to tell me what an offline status of online actually means. Or what an offline status of offline means. Would this mean that if I'm online my current online status is offline, or are both my online and offline status online?

offline status: online

2007 Honda Civic Hybrid Review

We recently picked up our new Honda Civic Hybrid, to replace our out-of-lease Audi A3. The short answer is, it seems to be a great car.

When you first get in it feels quite spacious, although the front dash is kind of large and imposing. At first I thought this was to accommodate batteries, but they are actually behind the rear seat (meaning in the hybrid you can not lay the seats down). It has plenty of hidey-holes to store stuff, most of which have a pull-over cover.

The drivers position is quite fine, although visibility probably isn't as good as in the older Audi. The steering wheel seems a little small, but the built-in controls are good. One thing I miss from the Audi is a space on the right of the accelerator to rest your foot, which is especially good for long periods on cruise control. The digital speedo is above the other controls and quite large, and is very visible to all your passengers (maybe this is an added safety feature!).

There is annoyingly little actual information about the "Integrated Motor Assist" system, other than it assists the motor and charges when you brake. There is a little indicator that tells you how much assistance it is giving, and conversely how much it is charing when you coast or brake. When you brake to a halt it goes into "auto stop" mode, where everything is off. The electric motor seems to take you from standing for about 2 seconds, presumably whilst the petrol engine starts up. It is quite smart about keeping the engine ticking on hills, but it does roll backwards just slightly.

When coasting, it seems that the engine goes idle, or at least the current fuel consumption gauge goes to zero. When the engine flicks back to charge mode there is a little whirring noise from somewhere under the dash, and when starting on electric the car does have a sort of subtle shudder; other than you wouldn't really notice.

The CV transmission is fantastic, and makes for a very smooth ride, especially on cruise control which doesn't have to hunt for gears. It is quite strange putting your foot down and just having the car accelerate with no noticeable gear changes. It has plenty of power for getting around town, and goes OK in the above 100km/h range. Even carrying 5 people it didn't seem to struggle. It gets around car parks just fine, and the steering is very, very smooth (new tyres probably help, however).

For some reason you can't shut of the two innermost air-conditioning vents, but otherwise the climate control works great. At least in Australia the interior has a touch of the Henry Ford about it: you can have it in any colour as long at is it beige. The rims are standard too, but look quite nice and modern.

Minor annoyances are lack of a switch-blade style key (they take up less pocket room) and, more annoyingly, lack of a remote boot unlock feature. This is something that comes in very handy when you have hands full of shopping, or a trombone and related paraphernalia. I also like the Audi hydraulic arm that kept the bonnet open, not that I plan to be under there much. Not that you'd want to touch anything, the two large red cables from the 158V batteries look like they could pack quite a punch.

It has a few less flashy features than the Prius, but it by no means feels like like a cheaper car. And the satisfaction you get from sitting in traffic (a fact of life in Sydney) using zero petrol is pretty good!

Update : We've just returned from a road trip from Sydney to Melbourne and back, covering 2170km. This was essentially all highway driving on cruise control at around 100-110km/h, with full boot of luggage. The trip computer tells us we averaged 5.8L/100km, which is a fair way off the 4.6L/100km claimed in the Green Vehicle Guide. A new 1.4L petrol Fiat Punto travelling with us on the way down also was running at under 6L/100km. In normal inner-Sydney driving we average 6.8L/100km, and the lowest we have achieved is 5.4L/100km whilst driving around the M2-M7-M5 loop when the new Lane Cove tunnel opened, which was often at lower speeds (80-90km/h) than open highway driving.