Reputation: 14401
I'm writing a server and would like to check if the process has the capability to open a port below 1024, and use a port above 1024 otherwise.
How could this be done under Linux in C/C++?
The obvious solution is to just try, but that is less elegant as I use third party software (GstRtspServer) that will subsequently use the port I've chosen accordingly. So that solution would be to open port 554 and if successful close it and tell GstRtspServer to use port 554 and otherwise 8554.
Upvotes: 0
Views: 346
Reputation: 394
This is straightforward in C/C++ (check.c
):
#include <stdio.h>
#include <stdlib.h>
#include <sys/capability.h>
int main(int argc, char **argv) {
cap_t current = cap_get_proc();
if (current == NULL) {
perror("failed to get process capabilities");
exit(1);
}
cap_flag_value_t on;
if (cap_get_flag(current, CAP_NET_BIND_SERVICE, CAP_PERMITTED, &on) != 0) {
perror("failed to check cap_net_bind_service value");
exit(1);
}
printf("the current process %s permitted to use cap_net_bind_service\n",
on == CAP_SET ? "is" : "is not");
}
Compile and run it:
$ cc check.c -lcap
$ ./a.out
the current process is not permitted to use cap_net_bind_service
$ sudo setcap cap_net_bind_service=p ./a.out
$ ./a.out
the current process is permitted to use cap_net_bind_service
To actually use this capability, you can change that setcap
command to set cap_net_bind_service=ep
, or use libcap
's cap_fill()
and cap_set_proc()
to copy the Permitted flag values into the Effective flag.
Upvotes: 2
Reputation: 11
the comment of mr. Stark is right.
look at "man capabilities"
CAP_NET_BIND_SERVICE Bind a socket to Internet domain privileged ports (port numbers less than 1024).
see include/linux/capability.h and man of libcap-dev/capgetp.3
Upvotes: 1
Reputation: 505
An easy way is to make some assumptions that are probably going to be true most of the time: see if you are running as root using geteuid():
#include <unistd.h>
...
uid_t euid = geteuid();
if (euid == 0) {
you_can_open_ports_below_1024
}
The problem with this solution is that it will just probably work on most systems that you're likely to encounter ... unless it doesn't. Modern Unix systems have ways to allow non-root to have various permissions that ancient Unixes reserved for root only.
So really, the best (albeit inelegant) way is in fact to try to open the socket, and close it if successful. If not successful, you should check errno to see if it's permission, in-use, or whatever. If it's in-use, then you haven't really answered the question if you have permission, but the question is moot at that point.
As for trying to determine the process' capabilities, trying to write code to actually check the permissions explicitly will be a headache, be non-portable (even across different Linuxes, never mind Solaris, etc), and ultimately break as security procedures continue to evolve.
And by the way, it is also true that you might open it successfully, then close it, and then try to open it again and fail ... not because you don't have permission, but because some other program slipped in. That does not invalidate this method. The open/close cycle is checking for permission. If the subsequent open fails because it's in-use by somebody else, then that could have happened no matter how you check for permission.
Upvotes: 0