diff --git a/configure.ac b/configure.ac index 94e2c9a1..697b3299 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,13 @@ PKG_CHECK_MODULES([LIBPCRE], [libpcre], HAVE_LIBPCRE=yes; AC_DEFINE(HAVE_LIBPCRE fi ]) +PKG_CHECK_MODULES([LIBCAP], [libcap], HAVE_LIBCAP=yes; AC_DEFINE(HAVE_LIBCAP, 1), +[AC_LIB_HAVE_LINKFLAGS(pcre,, [#include ], [cap_get_proc();]) + if test x$ac_cv_libcap = xyes; then + AC_SUBST([LIBCAP_LIBS], [$LIBCAP]) + fi +]) + AC_ARG_ENABLE([dns], [AS_HELP_STRING([--disable-dns], [Disable DNS resolution])], [dns="$withval"], [dns=yes]) diff --git a/src/Makefile.am b/src/Makefile.am index ecc1f376..1004e072 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,4 +33,4 @@ sniproxy_SOURCES = sniproxy.c \ tls.c \ tls.h -sniproxy_LDADD = $(LIBEV_LIBS) $(LIBPCRE_LIBS) $(LIBUDNS_LIBS) +sniproxy_LDADD = $(LIBEV_LIBS) $(LIBPCRE_LIBS) $(LIBUDNS_LIBS) $(LIBCAP_LIBS) diff --git a/src/sniproxy.c b/src/sniproxy.c index c833c25a..1197591e 100644 --- a/src/sniproxy.c +++ b/src/sniproxy.c @@ -35,6 +35,10 @@ #include #include #include +#ifdef HAVE_LIBCAP +#include +#include +#endif #include #include #include @@ -235,6 +239,30 @@ drop_perms(const char *username, const char *groupname) { gid = group->gr_gid; } +#ifdef HAVE_LIBCAP + cap_t caps; + cap_value_t cap_list[1]; + + /* add permitted flag to capability needed for IP_TRANSPARENT */ + if (CAP_IS_SUPPORTED(CAP_NET_RAW)) { + caps = cap_get_proc(); + if (caps == NULL) + fatal("cap_get_proc(): %s", strerror(errno)); + + cap_list[0] = CAP_NET_RAW; + if (cap_set_flag(caps, CAP_PERMITTED, 1, cap_list, CAP_SET) == -1) + fatal("cap_set_flags(): %s", strerror(errno)); + + if (cap_set_proc(caps) == -1) + fatal("cap_set_proc(): %s", strerror(errno)); + + cap_free(caps); + + /* keep capabilities after setuid */ + prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); + } +#endif + /* drop any supplementary groups */ if (setgroups(1, &gid) < 0) fatal("setgroups(): %s", strerror(errno)); @@ -245,6 +273,35 @@ drop_perms(const char *username, const char *groupname) { if (setuid(user->pw_uid) < 0) fatal("setuid(): %s", strerror(errno)); + +#ifdef HAVE_LIBCAP + /* enable capability needed for IP_TRANSPARENT */ + if (CAP_IS_SUPPORTED(CAP_NET_RAW)) { + caps = cap_get_proc(); + if (caps == NULL) + fatal("cap_get_proc(): %s", strerror(errno)); + + /* remove every capability from the list */ + cap_clear(caps); + cap_list[0] = CAP_NET_RAW; + /* take back capability */ + if (cap_set_flag(caps, CAP_PERMITTED, 1, cap_list, CAP_SET) == -1) + fatal("cap_set_flags(): %s", strerror(errno)); + /* take back capability */ + if (cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1) + fatal("cap_set_flags(): %s", strerror(errno)); + + if (cap_set_proc(caps) == -1) + fatal("back cap_set_proc(): %s", strerror(errno)); + /* from now on it the new capability list is active, + * no other capabilities may be enabled */ + + cap_free(caps); + + /* disable keeping capabilities across setuid */ + prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0); + } +#endif } static void