Usable security: the sudo security model

Edit: here’s the talk I was watching while writing this post, for context.

I’m starting writing this while I’m at Enigma 2016 listening to the usable security track. I think it’s a perfectly good time to start talk publicly about my experience trying to bring security to a Unix-based company I worked for before.

This is not a story of large company, the company I worked for was fairly small, with five people working in it at the time I was there. I’ll use “we” but I will point out that I’m no longer at that company and this is all in the past. I hope and expect the company to have improved their practices. When I joined the company, it was working on a new product, which meant we had a number of test servers running within the office and only one real “production” server for this running in a datacenter. In addition to the new product, a number of servers for a previous product were in production, and a couple of local testing servers for these.

While there was no gaping security hole for the company (otherwise I wouldn’t even be talking about it!) the security hygiene in the company was abysmal. We had an effective sysadmin at the office for the production server, and an external consultant to manage the network, but the root password (yes singular) of all devices was also known to the owner of the company, who also complained when I told them I wouldn’t share my password.

One of the few things that I wanted to set up there was a stronger authentication and stopping people from accessing everything with root privileges. For that stepping stone I ended up using, at least for the test servers (I never managed to put this into proper production), sudo.

We have all laughed at sudo make me a sandwich but the truth is that it’s still a better security mode than running as root, if used correctly. In particular, I did ask the boss what they wanted to run as root, and after getting rid of the need for root for a few actions that could be done unprivileged, I set up a whitelist of commands that their user could run without password. They were mostly happy not to have to login as root, but it was still not enough for me.

My follow-up ties to the start of this article, in particular the fact I started writing this while listening to Jon Oberheide. What I wanted to achieve was having an effective request for privilege escalation to root — that is, if someone were to actually find the post-it with the owner’s password they wouldn’t get access to root on any production system, even though they may be able to execute some (safe) routine tasks. At the time, my plan involved using Duo Security and a customized duo_unix so that a sudo request for any non-whitelisted command (including sudo -i) would require confirmation to the owner’s phone. Unfortunately at the time this hit two obstacles: the pull request with the code to handle PAM authentication for sudo was originally rejected (I’m not sure what the current state of that is, maybe it can be salvaged if it’s still not supported) and the owners didn’t want to pay for the Duo license – even just for the five of us, let alone providing it as a service to customers – even though my demo did have them quite happy about the idea of only ever needing their own password (or ssh key, but let’s not go there for now.)

This is just one of many things that were wrong in that company of course, but I think it shows a little bit that even in the system administration work, sometimes security and usability do go hand in hand, and a usable solution can make even a small company more secure.

And for those wondering, no I’m in no way affiliate with Duo, I just find it a good technology and I’m glad Dug pointed me at it a while back.

Securing logins, Duo Security experience

In January, I’ve ranted about not being able to get a Yubikey so that I could test some kind of OTP token for logging in to the FTP of one of my servers, so that my friend who is maintaining the WordPress install could work even from his office (where SSH does not work).

In the comments of that post Dug Song pointed me to his company, Duo Security which actually seemed like a good idea for what I had in mind. It provides support for both software and hardware token generators, has a clear API, and has a few integrations already available. Unfortunately now we’re in April, and you’ve seen nothing from me discussing it before. Why?

Well, mostly it feels like there’s a problem with timing. When I ranted about Yubikey, it was the week before leaving for FOSDEM, so I was finishing up job stuff and I couldn’t look at it until I came back from my combined trip (after FOSDEM I came here to Los Angeles). So when I started looking into it, I was at first only able to provide them with some build system changes.

When I then decided to spend some more time on it since the need to set up FTP increased, I started fighting with vsftpd to get it to accept using their PAM integration to use log in. The end result has been … a lot of time spent. Unfortunately the original design of their PAM implementation only works with a normal challenge-response authentication method (so it wouldn’t work with “safe” sshd PAM configurations), and more to the point, it would require asking two passwords, which an FTP client can’t.

While I first hacked it around, I was able to implement while here in LA last month a more complete patchset that implements a proper way to use it as a “single factor” authentication, or as a secondary push authentication. Unfortunately, I haven’t yet received a response about this patchset, which is why you won’t find duo_unix in Gentoo as it is.

The situation is getting more complex now: from one side I’m going to cut down most of my contract work in Italy as that’s not making me any money (seriously I think that even with all my ranting Flattr and Google AdSense are making me more money than website hosting), so I don’t foresee the need to provide users with some kind of strong authentication on the long term. From the other, while the firmware I’m working on doesn’t really care about this kind of strong authentication, the organization for which I’m working could use something like this. Of course, if the upstream for the package is not responding, that’s bad enough not to consider this.

I’m honestly not sure what to say since Dug and Jon seemed like friendly and helpful guys, maybe they are just too swamped with other requests and they can’t process mine as well, but whatever the reason, the issue I’m afraid is going to be a lapsed sale for them. Guys if you’re reading this, please let me know something, okay?

PAM, glibc 2.14, and NIS

After my list of issues related to glibc-2.14, the situation is somewhat more manageable: Mike fixed his own mistakes in the build of libtirpc, which now builds a working library, but on the other hand resolved to use a dirty hack to install the old NIS/YP header files, which are need by both libtirpc and other packages. Dirty or not, this at least produces some reasonable expectations of a working starting point.

I won’t even quote Mike’s suggestion for how to add support for libtirpc since that’s going to cause huge trouble with non-Linux platforms, given that for instances FreeBSD has a working RPC implementation (which, as far as I can tell, supports iPv6) in its C library itself. This means that what you should have in the ebuild, is probably something along these lines:

IUSE="elibc_glibc"

RDEPEND="elibc_glibc? ( || ( net-libs/libtirpc 

The option of creating a virtual package for this is sweet, but unfortunately, supporting libtirpc requires the buildsystem to identify it properly. it takes a bit of work on making it possible to build against that implementation in most cases, so simply adding the virtual is unlikely to be of help.

With enough support to actually fix the packages, tonight I looked into PAM, which I knew would become troublesome, since I already tried removing NIS support from it a few years ago; at the time I was unable to follow through with upstream because it was still the time I was getting in and out of hospitals.

At the time I had a patch that allowed building if NIS was unavailable, but it didn’t make it possible to disable NIS when available; this is instead implemented now in version 1.1.3-r1, with the nis USE flag, which I suggest to keep disabled (it is disabled by default). When actually enabling it, it’ll require either libtirpc (preferred) or an old glibc version.

Since NIS/YP is a virtually dead technology, it shouldn’t surprise that the default is now to keep it disabled, it’s not just a matter of requiring an extra dependency; I doubt anybody is using that stuff on any modern system; definitely not on users’ desktops or servers, which would be probably happy to drop a bunch of code that was left unused.

For those who wonder how much code are we talking about, comparing the before and after of the pam_unix module, which is the main consumer of the NIS/YP interfaces, it shows the total size decreasing of about 3KiB, one of which is purely part of the executable code, while the rest is distributed across data and rodata sections (which seem to mostly relate to string literals), and the overhead (imported symbol and string tables). Might not sound like a lot, especially on a module with about 50KiB of copy-on-write bss section, but it’s still something you gain by simply removing unused code, without even the need to optimize anything.

The extraordinary world of libtool

A little sidenote first; since I’ve had more system freezes with Yamato, I’m currently using the Dell laptop as my main box; I’m considering creating a proper frontend for Yamato, and leave that one headless, but that’s longer term, for now I’ll be fine this way. Huge thanks to Jürgen and Cyprien for making these stressful days much more bearable.

In my current line of work, I’ve hit the worst roadblock with, well, PAM. Not on the interface level this time but rather on the build system level. The problem? Building a copy of Linux-PAM 1.1.3 (sys-libs/pam in Gentoo) for a different ROOT will fail, if in that ROOT is installed an older copy of Linux-PAM, and LDFLAGS contains the directive -L${ROOT}/lib (let’s assume 32-bit userland, never 64-bit).

Let’s analyse the current series of problems then: why would you have to mangle LDFLAGS at all? Well, it mostly relates to finding the correct library when linking up. When building within a ROOT directory for the same architecture, most libraries are linked at from the base system, this is why emerge will always install the packages for / as well as for the designated root. When cross-building, the libraries will be searched for in the SYSROOT directory (which usually is /usr/$CHOST), but emerge is not currently smart enough to deal with that case, and thus the packages will not be merged there before merging the one for ROOT. For a previous customer of mine I simply had my wrapper scripts build everything twice, once in SYSROOT and one in the actual filesystem tree.

To avoid the double/triple build of the same package, the common method is to add to the include and library search paths the paths within ROOT that should be searched. This works most of the time, but there are situations where it simply doesn’t work as intended. For instance, doing so with iproute2 will cause -L$ROOT/lib to take precedence over the -L../lib that is used by the build system to link to their internal “libutil” — in turn this will cause the linker to prefer resolving -lutil to the system copy of libutil (provided by glibc) rather than the internal convenience static library. Another good reason to avoid too-common names for convenience libraries. Fixing that was trivial (even though I don’t see it merged yet).

On the other hand, if you were to drop all the mangling of LDFLAGS, you’d be hitting issues with the .la files as libtool will then translate name references into full-paths, referencing / directly, and failing when cross-compiling arm-on-x86. Which is yet another reason why, well, we should be killing those stupid files.

But how does all this relate to Linux-PAM? Well, first of all, just like iproute2 above, the build system for Linux-PAM 1.1.3 uses the combination of library search path and name reference to link to the just-built libpam and libpam_misc, and once again this is trivial to fix (even though it requires a 30KB patch, and breaks my clean record it’s mostly an automated process; I didn’t want to use sed in the ebuild though because I would risk to keep it on new versions where hopefully it won’t be needed). Unfortunately this only fixes half the problem: Linux-PAM builds fine, but it then refuses to install.

The problem here is a pretty common one, which I have already experienced when working on xine and relates to the relinking feature; you probably have seen libtool doing relink during the install phase of a package, often taking quite a lot of time, for instance that’s the case for evolution. The reason why libtool proceeds to take care of this is that you’re building libraries (or in this case, modules/plugins/how-you-want-to-call-them) that link against a just-built library; since libtool can use rpath to make it easier to debug executables from the build directory, it has to make sure that the installed copy is not using broken paths.

I’m not sure if this is a bug or a feature, though, and libtool forces relinking even when the package does not use rpath, or when they are not used at all during build debug (because fast-install is enabled). Also, for just about the same problem with paths, libtool does not use path-based linking during the relink, but rather it uses name references, that are susceptible to the LDFLAGS mangling stated above.

For now, the solution I found is a hack: I simply vouch to libtool that I don’t want it to re-link all the PAM modules during install, which both solves the build problem and should reduce the time needed for Linux-PAM to build. Unfortunately this does not solve it for all the other packages out there with the same problem. I guess it’s time to look for a solution libtool side.

What’s the plan with PAM?

Okay after quite a few days working on pambase, and a few discussions, I think I have a decent plan going forward to implement the new pambase. You can find the current status of the code in the repository but of course it is not really enough to get to test it; I’m still undecided whether I should add an overlay to the same repository, or get a PAM-only overlay where I can dump all the ebuilds for review.

So here is the rundown. First of all, as I said many times by now, I’ve replaced the C preprocessor with the M4 tool instead; this provides me a much more complete macro language, which means I can easily add further support, and mess around to disable/enable options as needed. Thanks to this, we now have a number of other authentication schemes, such as LDAP, PKCS#11 (via pam_pkcs11, I’m also going to add pam_p11 which is definitely simpler to set up even though it has less features).

But the main difference is in the services that it provides out of the box; there are now a number of new service files that will be used directly or indirectly by all the packages using PAM in the tree; while I didn’t like increasing the number of service files, there are slight differences in the behaviour of each that makes it necessary to split them around. For instance a remote login by default will not force root to login on a secure tty (although you might want to do that!), and as I said before you cannot easily use the same auth chain for both a login and a password-changer.

Another issue that I’m having trouble wrapping my head around is that you really cannot use the same authentication schemes for both interactive and automatic services; so for instance if you’re logging into a remote mail server you cannot provide an access token to do the login (since it requires it to be connected locally on the server). From one side, the same goes for ssh actually… I guess the only reason why I don’t feel as compelled to tackle it there is that I don’t use PAM for authenticating on SSH and neither should you in most cases.

What is now available in the repository is mostly working fine; although it remains a problem of interfacing it properly: I’m still unsure of the way the various modules stack up. For what it’s worth, one of the most obnoxious things I can think of is properly supporting pam_loginuid: it should be used by services both interactive and non-interactive to properly set auditing to log the user who’s acting (so even if there is privilege escalation you can track down who exploited it), but it should thus not be used by either sudo nor su, nor by things like PostgreSQL or Drizzle.

Right now what we’re going to have for certain are these services:

  • system-local-login (name kept for compatibility) will be used basically only by login — I’m actually tempted to provide /etc/pam.d/login directly as part of pambase, given that it is, yes, provided by shadow right now, but it’s also used by Busybox;
  • system-graphical-login will be used by all the graphical login managers: GDM, XDM, KDM, Slim, Qingy… the idea behind this one is that it is, by default, quiet; unlike what I originally planned, and what GDM now does, this one will not avoid running pam_mail, pam_lastlog and so on so forth; they will be, instead, put into their silent modes: the data will be updated, the variables will be set, but no output will come from them; unfortunately things like Qingy will cause double-setting of the same variables; that’s a problem for another time;
  • system-remote-login is the one service used by sshd (and theoretically by rsh/@rlogin@ if they made sense to be used);
  • system-services is the one used by the various cron daemons, atd, start-stop-daemon and so on: they have no authentication done, but they do have account validation and, most importantly, session support; as I said above, these should set the login uid to ensure that the audit framework knows who to blame for problems in here;
  • system-password is the service used by passwd and the other password changing tools; it only deals with the Unix stack and with (eventually) Gnome-Keyring;
  • system-auth-backends and system-login-backends are the two that give me more trouble to deal with; they have the actual calls to the backends used for authenticating; they are separate so that we can actually have them set up for optionality, so that only one is needed to succeed to allow the user to authenticate to the system, by using the substack option on the previous service; beside substack, the only other solution would have been to use the skip method I’ve been using up to now, and that I haven’t entirely stopped considering to be honest.

Also, among other things, I’ve removed the nullok option from the authentication and session support for pam_unix; this basically means that you can no longer have valid accounts without a password set; the idea is that this will not cause trouble with autologin features, but I’ll cross that bridge in due time. For now it should be enough to have an idea that the code is out there and how should be more or less be used.

Comments are, as usual, quite welcome.

It’s getting boring I know; more ConsoleKit braindumps

Since people insist that I don’t make myself enough verbose on the matter of how pambase gets implemented, here comes another post detailing some of the trouble me and Samuli are going through to make Gentoo a viable modern desktop.

First of all let’s make it clear what the target is: ConsoleKit is the modern implementation of the common necessity to provide different authorisation to users depending on whether they are connected on the local system or connecting from a remote system. The reason why this is useful on desktop systems is that you obviously don’t want somebody from a remote system to access your USB devices or cdroms, or soundcard while not being root.

Interestingly, the idea of this authorisation has always been tied tightly with PAM; the first try to get this working was the RedHat-generated patch that added the infamous pam_console module to Linux-PAM; one of my first problems to solve with Linux-PAM, and one of the first patches to be killed was indeed that which added this module. Unfortunately, the method used by pam_console was a very bad one: it changed the owners of device nodes in /dev, but if a session was abruptly interrupted, then it wouldn’t set them back correctly. Besides, it didn’t work that well when multiple users were logged in on different TTYs.

ConsoleKit handles this in a much different way, even though it still uses (mostly) PAM to do the work. Basically, when you open a new login session (and just login, not authentication for services), the PAM connector connects (sorry) via D-Bus to the daemon to tell it that there is now an open session; as long as that connection is open, the session is listed, and all the processes started from there are authorised. What’s the catch here? Well, to know which session a process belongs to, you have two obvious ways; neither of which is very reliable: you can check the parent process ID (which is not going to be fun when the process detaches into background), or you can check if it has the same open tty (which is not going to work when the program makes not use of ttys at all)., or you can check for the presence of an environment variable, but you will guess it’s a very bland way to solve the problem this latter one.

Luckily, Linux already provides a decent way to identify a session: the /proc/self/sessionid virtual file — but that one needs the kernel to support the Audit framework features. This is the reason why ConsoleKit is now asking you to enable that stuff in the kernel, it’s not just a mood swing, it’s rather a requirement to have proper session isolation. Unfortunately for this to work you also need that each session is created (and destroyed) with login — and we have PAM for that; indeed the module responsible for taking care of that is pam_loginuid that has been added in the latest (non-M4) version of pambase.

The bad side is, though, that it doesn’t help if pambase is fixed, if any other maintainer of a package using PAM is not listening to me (or insist that I shouldn’t dictate the PAM policies even though I’m the only one who seem to have a clue on how things have been asked to be supported for quite a while). This means that we have to fix all the graphical login managers (gdm, kdm, wdm, xdm, entrance, slim, qingy, …) to include the correct service file (system-graphical-login), so that the proper sessions are set up. Not just that, but as we were able to debug with Samuli, we need to fix both baselayout and openrc to use the system-services stack (so finally abiding to pam_mktemp as it was supposed to do since a very long time ago), since otherwise a service started not by the rc system but rather from a running logged-in session would inherit the root’s login session id, which is obviously a bad thing.

This was designed to work correctly with system-services, but as it turns out, unless I actually pay attention to each and every package that should use them, even when I actually coordinate integration of the new services into pambase with them, or I do the original changes myself, the end result is simply bad. This is why an audit is necessary as I said before.

I was intending to end this post with a description of the incompatibilities between Qingy and ConsoleKit, but after writing a few paragraph, I decided that without enough diagrams of what’s going on, there is no way I can actually provide you with a description of it that can be understood by those who haven’t studied PAM and login themselves. So for now I’ll close on this page, and will post during the week the notes on qingy.

But I’ll also have to warn you that for the next weeks I’m quite swamped with finishing the documentation of one job and starting the work on a new one, so the normal Gentoo stuff is going to stay hidden for a while; if you wish to help with testing or motivation it’s certainly appreciated. I’ll see to provide a testing pambase ebuild on the repository itself so that those of you who feel daring enough can get to test it. As a homework for anyone who’s interested, feel free to open bugs about desktop managers in tree and official overlays – with pam-bugs@g.o in CC – if they should be migrated to system-graphical-login once the new pambase is released.

Hey host, give me a new login please!

One of the reasons why I’ve been spending all this time rewriting and extending pambase lately has been that Samuli asked for my help to sort out the ConsoleKit problems he’s been seeing for the past months. Authorisation problems with both XFCE and (less often) GNOME are mostly due to a misconfigured or misbehaving ConsoleKit, and the main cause of that seems to be PAM-related.

Indeed, after a bit of poking around I came to the idea that PAM needs a whole audit and that the new pambase was really important to work on. As it happens, most of what I wrote yesterday tied with the need for the graphical manager and the text login to differentiate their session chains — there are bonus points because we can solve a few more problems with noisy modules at the same time, but that’s beside the point now.

So there has been two main issues here:

  • the nox11 option given to pam_ck_connector need to be dropped for X logins;
  • all the desktop managers need to move to use the system-login (now system-graphical-login) service, rather than using system-auth directly.

As messed up as this might be, now that I reached the end of the alley, I guess the right questions I had to ask were:

  • why none of the managers used the system-local-login stack as it was intended with pambase? the answer is actually what I wrote in the previous post: the noisy modules (motd/mail/lastlog) caused hiccups and noise on login with GDM and the others; which is now solved by using a different service for them;
  • why was nox11 added to the system-login service? Because when I was suggested to set it up, whoever gave me the line (I don’t remember who was, I didn’t know enough about ConsoleKit to come up with it myself — and I still don’t know much about it) only considered it to be used with GDM; since GDM takes care of creating the session itself, there is no need for the PAM module to do so.

Unfortunately, as it happens, GNOME is no longer the only environment to use ConsoleKit, and thus GDM not the only desktop manager used by users that should be authorized by it. The other desktop managers, though, are not going to integrate ConsoleKit themselves (heck, PAM was designed with this need in mind) so they should be using the module without the nox11 option. So what happens if we disable it? Well, GDM will create its own session after the one from the PAM module is created; the session coming from PAM will result unused, but won’t hinder much. It’s an acceptable compromise as well. A more solid situation you’d have if you simply disable ConsoleKit by USE flags on gdm, so that only the PAM version is applied — at the time of writing this, the ebuild does not allow you to do this though. For whatever reason they decided it was a good idea to use a “same” dependency between the ConsoleKit support in GDM and pambase even though it would rather be a “either or” dependency: either in GDM or in PAM.

So this should solve the problems (once applied of course) for GDM, KDM and XDM. Unfortunately Slim, which is the manager Samuli suggested me to begin testing with, still doesn’t work. Oh, ConsoleKit creates the session, all right, but it is not marked as local at all. Why is that?

Well, among the attributes PAM applications can provide to the modules to test against is one called PAM_RHOST that stands for remote-host; XDM, GDM and KDM only set this if the DISPLAY variable does not start with a colon, which mean that we’re displaying on a remote server; ConsoleKit decides that the session isn’t local as soon as it finds a rhost value; on the other hand Slim sets the rhost to localhost in all cases (and so does the sample pam_env configuration file that we don’t actually execute anyway). This basically means that even once the PAM issues are all sorted out, Slim-initiated sessions will result non-local.

Now, where was I? Ah yes, I have to just make sure that all the ebuilds in portage call the right service. Piece of cake, right?

PAM, logging in and changing passwords

I’ve been spending the past ten days/two weeks handling two full-time job at once; one was Windows-related so it won’t have any direct effect in what I’d be posting on the blog, the other involved Amazon EC2, so you’ll be seeing more rants sorry I meant posts on the topic soon. But first, …

Thanks to Constanze who became a full-fledged developer (congratulations!), I’ve been able to breath a bit more widely for what concerns PAM; another positive note comes from Eray becoming developer as well, which means I can get someone looking at pam_krb5 package. Which means I can get back to work on the M4-powered pambase package so that hopefully before end of the year we’re going to get it in testing at least. Additionally, user prometheanfire on #gentoo-hardened provided me with a sample configuration for LDAP that should make it much easier to implement it on pambase.

But the situation starts to become much more complicated; for instance, the ConsoleKit situation is so intricated that making it behave as intended is actually quite difficult: the invocation of the module is different whether we’re going to authenticate a text login or an X11 login session; some time ago we also found the hard way that some graphical login managers fail badly when you print too much information on the PAM output channel (such as Messages of the Day, the last login data, and mail status). This all results in having to have different sessions for local text and local graphical logins. I have a huge headache already when I start to think about XDMCP already.

This turn of events also makes me think that I should simply drop the system-login service that I’ve used in the previous iterations. The reason to use and include this service was to avoid duplication, but with M4, duplication is avoided during build time, not after install. This should make available only the three “leaf” services: system-remote-login (with optional ABL support), system-local-login (not renamed for compatibility reasons) with text-based login, and (by default) mail/motd/lastlogin modules; system-graphical-login with support for X11-based ConsoleKit sessions as well as without the extra verbose modules.

A note here: somebody asked me why of the minimal USE flag for pambase; the reason is relatively simple: even though the output of those can easily be discarded, they will be kept loaded in memory by processes such as sshd and fcron; dropping the modules from the services mean also reducing the memory usage of those process, minimally, but it does.

After the login process is sorted out there is another problem here and it has to do with changing passwords; I’ve said that before, but I’ll repeat it here. When the new pambase will be put in place, software that is able to change password will have to be updated to use a different service to do so; this will hinder the changing of password through sshd that was noted in the comments of one of my previous posts, but it is necessary if we want to have proper restriction among login methods.

The problem is that with PAM design, for what concern changing passwords, you end up with either you have to know all the currently in-use authentication methods or you have to know only one of the authentication methods and then you change all the authentication method to the new value or you change only one authentication method to the new value.

The end result is that I can’t think of any way to do what would make sense: change the token only for the systems that actually use the current password provided. Lacking this the situation is that we cannot have a single tool to do everything, so we’re going to have to stick with many different password-changing tools: passwd, chpasswd and their cousins will only require the Unix password and will only change the Unix password. You’re going to use separate tools for Kerberos, LDAP, SSH keys, PKCS#11 tokens, …

While it might sound as suboptimal it’s a compromise that actually make pambase manageable without having to resort to actual custom Linux-PAM implementations. I hope you can all agree on that.

Anyway, this only acts as a braindump; I hope I’ll be able to set up real documentation about the pambase system at one point or another, including some simple drawing to show how the authentication flow actually happens. Unfortunately if you remember, I noted that OpenOffice is the only decent software I can find to write flowcharts; unfortunately that is both cumbersome to add to a GIT repository, cumbersome to auto-produce results (when what it exports is what you wanted), and finally quite expensive in term of dependencies. I should probably try Inkscape back, possibly tied with rsvg (now that gdk-pixbuf works without X) would be a decent choice.