One of the problems with running services on a unix box is that port numbers below 1024 are restricted. A process cannot bind to a low numbered port unless it is owned by the super-user. In the context of tclhttpd this means we have to launch the tcl process using the root account and then drop privileges as soon as we have bound our listening sockets by switching to another user identity. This can be done quite handily using the TclX extension and tclhttpd has support for this. But I have an aversion to running script interpreters as root.

One solution that is often used with scripted services like tclhttpd is to operate on a non-restricted port and have firewall rules rewrite the incoming traffic to send it from port 80 to your service port (perhaps 8080). With firewalls supporting NAT redirection this is a simple solution but once we consider ipv6 we have a problem. IPv6 has no need for NAT and the Linux ip6tables firewall does not provide a means to redirect packets to a different port.

An ideal solution is offered by the new Linux capabilities that is now available since kernel 2.6.24 and can be found in the latest Karmic Koala Ubuntu Server versions. Capabilities permits much more finely grained permissions assignments than the traditional mechanism of 'setuid root'. In particular we can assign our process exactly the permission required: permission to bind restricted ports - and no other permissions. So now we can set this capability and run the executable image using the correct user id from start to finish.

As a specific example, I use a tclkit-cli executable to run my tclhttpd service. I copied it into the tclhttpd tree and named it tclhttpd as this helps the init.d daemon tools to manage the process. I then used the setcap utility from the libcap2-bin package to set the correct capability. In this case we want to be able to bind the restricted ports and that is the CAP_NET_BIND_SERVICE capability.

cp /opt/bin/tclkit-cli tclhttpd
setcap 'cap_net_bind_service=+ep' tclhttpd

The capability flags above raise the effective and permitted flags for the cap_net_bind_service capability. capabilities(7) explains what all this means but basically as we did not raise the inherited flag any child processes will not have this capability.

Now I have my server listening on ipv4 and ipv6 without messing with the firewall and without requiring to be started by root. With the installation is a suitable file to automate the restart of the service it is all up and running.

It is interesting to note that this method can be used to remove the setuid bit from other programs. For instance, the ping utility requires the CAP_NET_RAW capability and does not need root access if this is provided. Once capabilities spread through the linux distributions this should help make systems just that little bit more secure.