
<erl>
out(A) ->
       {ssi, "TAB.inc", "%%",[{"privbind", "choosen"}]}.
</erl>


<div id="entry">

<h1>Binding to privileged ports</h1>

<p>
  A common misfeature found on UN*X operating systems is the
  restriction that only root can bind to ports below 1024.
  Many a dollar has been wasted on workarounds and -often- the results are
  security holes.

</p>
<p>
  Both FreeBSD and Solaris have elegant configuration options to
  turn this feature off. On FreeBSD:

<div class="box">
      <verbatim>
	$ sysctl net.inet.ip.portrange.reservedhigh=0
      </verbatim>
</div>

the above is best added to your /etc/sysctl.conf
</p>
<p>
  Similarly on Solaris we can just configure away this misfeature.
  Assuming we want to run Yaws/SSL under a non-root user "erlang" on
  ports 80/443.
</p>
<p>
  On Solaris we can do that easily by granting the specific right to bind
  privileged ports <1024 (and only that) to "erlang" using:
</p>

<div class="box">
      <verbatim>
$ /usr/sbin/usermod -K defaultpriv=basic,net_privaddr erlang
      </verbatim>
</div>

<p>
And check the we get what we want through:
</p>


<div class="box">
      <verbatim>
$ grep erlang /etc/user_attr
erlang::::type=normal;defaultpriv=basic,net_privaddr

      </verbatim>
</div>


<p>
  On Linux, kernels later than 2.6.24, it's possible to do:
</p>
<div class="box">
      <verbatim>
$ setcap 'cap_net_bind_service=+ep' /usr/lib/erlang/erts-5.7.4/bin/beam
      </verbatim>
</div>

<p>
  The above command grants the capability of binding
  privileged ports to beam. Note, you have to grant the priviliges to the
  actual exectuable you are using.
<p>

<p>
  There are a couple
  of other options on Linux. One is to use an auxiliary program
  like authbind <em>http://packages.debian.org/stable/authbind</em>
  or privbind <em>http://sourceforge.net/projects/privbind/</em>
</p>
<p>
  These programs are run by root. Yaws writes its temporary
  JIT compiled files in $HOME/.yaws and this doesn't work that
  well with authbind/privbind. A non root user will try to
  write in /root/.yaws. The solution to this is to set the
  environment variable YAWSHOME. Yaws will then consider that to
  be HOME rather that $HOME.
</p>
<p>
  To start yaws under e.g privbind we can do:
</p>


<div class="box">
      <verbatim>
$ sudo YAWSHOME=/tmp/abc privbind -u klacke /home/klacke/bin/yaws \
    -c /home/klacke/yaws.conf -i

      </verbatim>
</div>

<p>
  The above command starts yaws as user <em>klacke</em> and bind
  to ports below 1024
</p>


<p>
  The authbind program is another option: Here is an example:
</p>
<div class="box">
      <verbatim>
touch /etc/authbind/byport/80
touch /etc/authbind/byport/443
chmod 500 /etc/authbind/byport/80
chmod 500 /etc/authbind/byport/443
chown bob /etc/authbind/byport/80
chown bob /etc/authbind/byport/443
YAWSHOME=/home/bob authbind yaws -c /home/bob/yaws.conf -i
      </verbatim>
</div>



<p>
Here is a description on how to do this on MacOs X. It's not exactly the same,
since we're still binding to non privileged ports. However,
edit /etc/sysctl and add:
</p>

<pre>
net.inet.ip.forwarding=1
</pre>

<p>
Then with ipfw as the firewall (turn off the gui firewall in system
preferences and manage own rules) use the ipfw rules like these - for
testing on your own box use something like:
</p>

<pre>
ipfw add fwd 127.0.0.1,8080 tcp from any to 127.0.0.1 dst-port 80 in
ipfw add fwd 127.0.0.1,8443 tcp from any to 127.0.0.1 dst-port 443 in
</pre>

<p>
set up yaws to use 8080 and 8443 in yaws.conf and then run as some non
root user.  When you browse to http://127.0.0.1 or https://127.0.0.1
you will see your pages that are actually on 8080 and 8443 internally
but will be forwarded via ipfw forwarding.
</p>


<p>

Yet another (more complicated way) for linux users is to hack the kernel.
Here is a patch I did for some version of the 2.6 series kernels .. you get the idea.
</p>


<verbatim>
[root@lax]ipv4 > diff -c af_inet.c*
*** af_inet.c   Wed Feb 23 23:31:35 2005
--- af_inet.c~  Thu Feb 17 18:13:13 2005
***************
*** 423,434 ****

        snum = ntohs(addr->sin_port);
        err = -EACCES;
- #if 0
-       /* removed by klacke */
        if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                goto out;
- #endif
-

        /*      We keep a pair of addresses. rcv_saddr is the one
         *      used by hash lookups, and saddr is used for transmit.
--- 423,430 ----
</verbatim>





<erl>
out(A) -> {ssi, "END2",[],[]}.
</erl>


