OpenSSH will flat-out refuse to bind to privileged ports unless the user id of the logged in user is 0 (root). The relevant lines of code are:
if (!options.allow_tcp_forwarding ||
no_port_forwarding_flag ||
(!want_reply && listen_port == 0) ||
(listen_port != 0 && listen_port < IPPORT_RESERVED &&
pw->pw_uid != 0)) {
success = 0;
packet_send_debug("Server has disabled port forwarding.");
Source: http://www.openssh.com/cgi-bin/cvsweb/src/usr.bin/ssh/serverloop.c?annotate=1.162 lines 1092-1098
If you're curious, pw
is of type struct passwd *
and on linux is defined in /usr/include/pwd.h
It turns out that setting +i on the wrapper does not add the capability to the CAP_INHERITABLE
set for the wrapper process, thus it is not passed through exec
. I therefore had to manually add CAP_DAC_OVERRIDE
to CAP_INHERITABLE
before calling execl
:
#include <sys/capability.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv[]) {
cap_t caps = cap_get_proc();
printf("Capabilities: %s\n", cap_to_text(caps, NULL));
cap_value_t newcaps[1] = { CAP_DAC_OVERRIDE, };
cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET);
cap_set_proc(caps);
printf("Capabilities: %s\n", cap_to_text(caps, NULL));
cap_free(caps);
return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}
In addition, I had to add cap_dac_override
to the permitted file capabilities set on /usr/bin/net
and set the effective bit:
~ $ sudo setcap cap_dac_override=p ./registerdns
~ $ sudo setcap cap_dac_override=ei /usr/bin/net
~ $ ./registerdns
Capabilities = cap_dac_override+p
Capabilities = cap_dac_override+ip
Successfully registered hostname with DNS
I think I now fully understand what's happening:
- The wrapper needs
CAP_DAC_OVERRIDE
in its permitted set so it can add it to its inheritable set.
- The wrapper's process inheritable set is different than its file inheritable set, so setting +i on the file is useless; the wrapper must explicitly add
CAP_DAC_OVERRIDE
to CAP_INHERITABLE
using cap_set_flag
/cap_set_proc
.
- The
net
file needs to have CAP_DAC_OVERRIDE
in its inheritable set so that it can in fact inherit the capability from the wrapper into its CAP_PERMITTED
set. It also needs the effective bit to be set so that it will be automatically promoted to CAP_EFFECTIVE
.
Best Answer
Extended permissions such as access control lists set by
setfacl
and capability flags set bysetcap
are stored in the same place as traditional permissions and set[ug]id flags set bychmod
: in the file's inode.(They may actually be stored in a separate block on the disk, because an inode has a fixed size which has room for the traditional permission bits but not for the potentially unbounded extended permissions. But that only matters in rare cases, such as having to care that
setcap
could run out of disk space. But evenchmod
could run out of disk space on a system that uses deduplication!)GNU ls doesn't display a file's setcap attributes. You can display them with
getcap
. You can list all the extended attributes withgetfattr -d -m -
; the setcap attribute is calledsecurity.capability
and it is encoded in a binary format whichgetcap
decodes for you.