51

I would like to run applications I'm working on that binds to port numbers less than 1000 without requiring root access.

I'm using Linux Mint and have root access to set it up. I would ideally like to be able to do it over SSH.

Also happy hear if it isn't possible or I shouldn't be doing it, if that is the case.

EDIT: Mostly I'm happy to use higher port numbers for development, but Flash is expecting a socket policy on port 843. Currently I have to run the app as root and therefore I can't run it from my Makefile which is a PITA.

tarn
  • 615
  • 1
  • 5
  • 7
  • 8
    It isn't possible and you shouldn't be doing it :) (and if you have to do it, suexec and drop privileges after binding) – Tzarium May 10 '11 at 10:48
  • @Tzarium - Appreciate that straight answer, although not what I wanted to hear :) Will sadly mark as accepted shortly. – tarn May 10 '11 at 11:25
  • 3
    @Tzarium It's not only possible but easy if your system supports filesystem capabilities. See @joeforker's `setcap` answer below. – Gerald Combs May 10 '11 at 15:43
  • Authbind is also a good answer (from Simon below). This is very possible, in several different ways... – Shane Madden May 10 '11 at 15:57
  • 1
    Duplicates: http://serverfault.com/questions/84360/regular-user-using-ports-below-1024 http://serverfault.com/questions/182413/is-it-possible-to-run-dhcpd3-as-non-root-user-in-a-chroot-jail http://serverfault.com/questions/133415/how-to-allow-non-root-user-to-listen-on-privileged-port http://serverfault.com/questions/245374/using-selinux-to-force-linux-to-allow-programs-to-bind-to-port-numbers-lower-than http://stackoverflow.com/questions/413807/is-there-a-way-for-non-root-processes-to-bind-to-privileged-ports-1024-on-li http://stackoverflow.com/questions/2444591/ – joeforker May 10 '11 at 17:13

4 Answers4

47

Of course this is possible. You only need to give the binary CAP_NET_BIND_SERVICE.

sudo setcap cap_net_bind_service=ep some-binary

In Linux, the things root can do have been broken up into a set of capabilities. CAP_NET_BIND_SERVICE is the ability to bind to ports <= 1024.

It's probably even possible to use AppArmor, SELinux, or another Linux security module (LSM) to grant the program access to bind that one port specifically, but I think this would be a waste of time. Security is not really based on port numbers to the degree it was in the distant past.

Here's a script for OSX to forward ports 80 and 443 to unprivileged ports:

echo " 
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
rdr pass inet proto tcp from any to any port 443 -> 127.0.0.1 port 8443
" | sudo pfctl -ef -
joeforker
  • 2,349
  • 4
  • 25
  • 34
  • Awesome, this is the answer I wanted. Will try that tonight. Thanks. – tarn May 10 '11 at 23:43
  • A little bit of extra info on *why* this is the only approach that works: http://www.kneuro.net/cgi-bin/lxr/http/source/net/ipv4/af_inet.c?a=alpha#L486 . `PROT_SOCK`=1024, and `snum` is the targeted port. – BMDan May 14 '11 at 16:02
  • For bonus points: check out AccessFS for a real brain-twist. – BMDan May 14 '11 at 16:08
  • 1
    `authbind` works as well and allows for per-port and user/group based control, just remember to set up `/etc/authbind/byports` accordingly (a lot of people seem to install `authbind` then just expect it to work out-of-the-box). – Jason C Mar 21 '15 at 21:18
  • is there a similar approach on osx ? – svassr Dec 12 '16 at 18:49
  • 2
    FWIW, docker run has [--cap-add option](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities). – Taylan Jul 06 '20 at 08:10
  • What packages need to be compiled against `libcap` in order for this to work? Can I use it in every shell wrapper style script if my `libc` is using `libcap` (I mean `capsh` command specifically)? – Alireza Mohamadi Nov 15 '20 at 11:05
41

Another way of getting your daemon to respond to requests from a lower port number is to use iptables or similar to redirect a lower numbered port to the higher numbered port that your daemon is listening on:

sudo iptables -A PREROUTING -t nat -p tcp --dport 80 -j REDIRECT --to-port 8080

Substitute 80 with the port to expose, and 8080 with your application listener port.

Elad Nava
  • 293
  • 3
  • 10
James C
  • 784
  • 1
  • 6
  • 8
  • Ok, that sounds like a workable workaround. I will look into that, Thanks. – tarn May 10 '11 at 11:20
  • 4
    That's what I've done before and it works fine: `iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 843 -j REDIRECT --to-port 8430` (this redirects incoming connections on port 843 to port 8430) – Andrew Lambert May 10 '11 at 17:07
  • 7
    Unlike setcap, any program, not just the program you designated, will be able to listen on the unprivileged port. – joeforker May 10 '11 at 17:14
8

I think there is a way to do it but im not 100% sure if this would work.

its the binding of the port that requires root, not the application's using it, so the below method may work but you need to have sudo access in the first place.

First you start your process as root user using sudo myApp, once the port has been bound you can switch the owner of the process to a non-privileged user.

RobertPitt
  • 410
  • 3
  • 12
  • 2
    That will run the application as root and potentially expose the system to security risks. Works but the iptables redirect is more secure. – HampusLi May 10 '11 at 12:16
  • 4
    This is the way almost all daemons work; root starts them (init), they open the necessary ports, then chance their UID/GID to an unprivileged user. – Chris S May 10 '11 at 13:07
8

I dimly remember a library called "authbind" that does what you need, by wrapping the bind() system call (via a LD_PRELOAD library), and, if a privileged port is requested, spawning a setuid root program that receives a copy of the file descriptor, then verifies the application is indeed permitted to bind to the port, performs the bind() and exits.

Not sure about the project status, but the method should be fairly straightforward to (re)implement if required.

Simon Richter
  • 3,209
  • 17
  • 17
  • 1
    authbind is great. install authbind; touch /etc/authbind/byport/{80,443}; chown /etc/authbind/byport/*; chmod u+x /etc/authbind/byport/* ; authbind ./myprog – joeforker May 24 '20 at 23:39