mirror of
https://github.com/moparisthebest/sslh
synced 2024-11-21 16:45:03 -05:00
Implement libcap support
Use libcap for saving CAP_NET_ADMIN (if --transparent is given) over a setuid(). We don’t need CAP_NET_BIND_SERVICE as the listening sockets are established before dropping root.
This commit is contained in:
parent
3f386b6541
commit
009faa64b7
6
Makefile
6
Makefile
@ -3,6 +3,7 @@
|
||||
VERSION=$(shell ./genver.sh -r)
|
||||
USELIBCONFIG=1 # Use libconfig? (necessary to use configuration files)
|
||||
USELIBWRAP= # Use libwrap?
|
||||
USELIBCAP= # Use libcap?
|
||||
COV_TEST= # Perform test coverage?
|
||||
PREFIX=/usr/local
|
||||
|
||||
@ -31,6 +32,11 @@ ifneq ($(strip $(USELIBCONFIG)),)
|
||||
CPPFLAGS+=-DLIBCONFIG
|
||||
endif
|
||||
|
||||
ifneq ($(strip $(USELIBCAP)),)
|
||||
LIBS:=$(LIBS) -lcap
|
||||
CPPFLAGS+=-DLIBCAP
|
||||
endif
|
||||
|
||||
all: sslh $(MAN) echosrv
|
||||
|
||||
.c.o: *.h
|
||||
|
31
README
31
README
@ -157,16 +157,21 @@ in inetd mode.
|
||||
sslh options: -i for inetd mode, --http to forward http
|
||||
connexions to port 80, and SSH connexions to port 22.
|
||||
|
||||
==== capapbilities support ====
|
||||
==== capabilities support ====
|
||||
|
||||
On Linux (only?), you can use POSIX capabilities to reduce a
|
||||
server's capabilities to the minimum it needs (see
|
||||
capabilities(8). For sslh, this is CAP_NET_ADMIN (to
|
||||
perform transparent proxy-ing) and CAP_NET_BIND_SERVICE (to
|
||||
bind to port 443 without being root).
|
||||
On Linux (only?), you can compile sslh with USELIBCAP=1 to
|
||||
make use of POSIX capabilities; this will save the required
|
||||
capabilities needed for transparent proxying for unprivileged
|
||||
processes.
|
||||
|
||||
The simplest way to use capabilities is to give them to the
|
||||
executable as root:
|
||||
Alternatively, you may use filesystem capabilities instead
|
||||
of starting sslh as root and asking it to drop privileges.
|
||||
You will need CAP_NET_BIND_SERVICE for listening on port 443
|
||||
and CAP_NET_ADMIN for transparent proxying (see
|
||||
capabilities(7)).
|
||||
|
||||
You can use the setcap(8) utility to give these capabilities
|
||||
to the executable:
|
||||
|
||||
# setcap cap_net_bind_service,cap_net_admin+pe sslh-select
|
||||
|
||||
@ -174,13 +179,9 @@ Then you can run sslh-select as an unpriviledged user, e.g.:
|
||||
|
||||
$ sslh-select -p myname:443 --ssh localhost:22 --ssl localhost:443
|
||||
|
||||
This has 2 advantages over starting as root with -u:
|
||||
- You no longer start as root (duh)
|
||||
- This enables transparent proxying.
|
||||
|
||||
Caveat: CAP_NET_ADMIN does give sslh too many rights, e.g.
|
||||
configuring the interface. If you're not going to use
|
||||
transparent proxying, just don't use it.
|
||||
transparent proxying, just don't use it (or use the libcap method).
|
||||
|
||||
==== Transparent proxy support ====
|
||||
|
||||
@ -192,8 +193,8 @@ simplifies IP-based access control (or makes it possible at
|
||||
all).
|
||||
|
||||
sslh needs extended rights to perform this: you'll need to
|
||||
give it cap_net_admin capabilities (see appropriate chapter)
|
||||
or run it as root (but don't do that).
|
||||
give it cap_net_admin capabilities manually or enable libcap
|
||||
support (see appropriate chapter).
|
||||
|
||||
The firewalling tables also need to be adjusted as follow
|
||||
(example to connect to https on 4443 -- adapt to your needs
|
||||
|
59
common.c
59
common.c
@ -37,6 +37,10 @@ struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */
|
||||
int allow_severity =0, deny_severity = 0;
|
||||
#endif
|
||||
|
||||
#ifdef LIBCAP
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
|
||||
/* check result and die, printing the offending address and error */
|
||||
void check_res_dumpdie(int res, struct addrinfo *addr, char* syscall)
|
||||
@ -509,6 +513,56 @@ void setup_syslog(const char* bin_name) {
|
||||
log_message(LOG_INFO, "%s %s started\n", server_type, VERSION);
|
||||
}
|
||||
|
||||
/* Ask OS to keep capabilities over a setuid(nonzero) */
|
||||
void set_keepcaps(int val) {
|
||||
#ifdef LIBCAP
|
||||
int res;
|
||||
res = prctl(PR_SET_KEEPCAPS, val, 0, 0, 0);
|
||||
if (res) {
|
||||
perror("prctl");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* set needed capabilities for effective and permitted, clear rest */
|
||||
void set_capabilities(void) {
|
||||
#ifdef LIBCAP
|
||||
int res;
|
||||
cap_t caps;
|
||||
cap_value_t cap_list[10];
|
||||
int ncap = 0;
|
||||
|
||||
if (transparent)
|
||||
cap_list[ncap++] = CAP_NET_ADMIN;
|
||||
|
||||
caps = cap_init();
|
||||
|
||||
#define _cap_set_flag(flag) do { \
|
||||
res = cap_clear_flag(caps, flag); \
|
||||
CHECK_RES_DIE(res, "cap_clear_flag(" #flag ")"); \
|
||||
if (ncap > 0) { \
|
||||
res = cap_set_flag(caps, flag, ncap, cap_list, CAP_SET); \
|
||||
CHECK_RES_DIE(res, "cap_set_flag(" #flag ")"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
_cap_set_flag(CAP_EFFECTIVE);
|
||||
_cap_set_flag(CAP_PERMITTED);
|
||||
|
||||
#undef _cap_set_flag
|
||||
|
||||
res = cap_set_proc(caps);
|
||||
CHECK_RES_DIE(res, "cap_set_proc");
|
||||
|
||||
res = cap_free(caps);
|
||||
if (res) {
|
||||
perror("cap_free");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We don't want to run as root -- drop privileges if required */
|
||||
void drop_privileges(const char* user_name)
|
||||
{
|
||||
@ -521,10 +575,15 @@ void drop_privileges(const char* user_name)
|
||||
if (verbose)
|
||||
fprintf(stderr, "turning into %s\n", user_name);
|
||||
|
||||
set_keepcaps(1);
|
||||
|
||||
res = setgid(pw->pw_gid);
|
||||
CHECK_RES_DIE(res, "setgid");
|
||||
res = setuid(pw->pw_uid);
|
||||
CHECK_RES_DIE(res, "setuid");
|
||||
|
||||
set_capabilities();
|
||||
set_keepcaps(0);
|
||||
}
|
||||
|
||||
/* Writes my PID */
|
||||
|
Loading…
Reference in New Issue
Block a user