diff --git a/Makefile b/Makefile index 6f7f78c7b..009e18f01 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ CCFLAGS=-std=gnu11 -I$(IDIR) $(WARNFLAGS) -D_FILE_OFFSET_BITS=64 $(HARDENING_FLA # for dnsmasq we need the nettle crypto library and the gmp maths library # We link the two libraries statically. Although this increases the binary file size by about 1 MB, it saves about 5 MB of shared libraries and makes deployment easier #LIBS=-pthread -lnettle -lgmp -lhogweed -LIBS=-pthread -lrt -lcap -Wl,-Bstatic -L/usr/local/lib -lhogweed -lgmp -lnettle -Wl,-Bdynamic +LIBS=-pthread -lrt -Wl,-Bstatic -L/usr/local/lib -lhogweed -lgmp -lnettle -Wl,-Bdynamic # Flags for compiling with libidn : -lidn # Flags for compiling with libidn2: -lidn2 diff --git a/capabilities.c b/capabilities.c index 1a33fee83..a583f440f 100644 --- a/capabilities.c +++ b/capabilities.c @@ -8,36 +8,68 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ +// Definition of LINUX_CAPABILITY_VERSION_* +#define FTLDNS +#include "dnsmasq/dnsmasq.h" +#undef __USE_XOPEN #include "FTL.h" -#include bool check_capabilities() { - if(!cap_get_bound(CAP_NET_ADMIN)) + int capsize = 1; /* for header version 1 */ + cap_user_header_t hdr = NULL; + cap_user_data_t data = NULL; + + /* find version supported by kernel */ + hdr = calloc(sizeof(*hdr), capsize); + memset(hdr, 0, sizeof(*hdr)); + capget(hdr, NULL); + + if (hdr->version != LINUX_CAPABILITY_VERSION_1) + { + /* if unknown version, use largest supported version (3) */ + if (hdr->version != LINUX_CAPABILITY_VERSION_2) + hdr->version = LINUX_CAPABILITY_VERSION_3; + capsize = 2; + } + + data = calloc(sizeof(*data), capsize); + capget(hdr, data); /* Get current values, for verification */ + + bool missing = true; + if (!(data->permitted & (1 << CAP_NET_ADMIN))) { // Needed for ARP-injection (used when we're the DHCP server) logg("**************************************************************"); logg("WARNING: Required linux capability CAP_NET_ADMIN not available"); logg("**************************************************************"); - return false; + missing = true; } - if(!cap_get_bound(CAP_NET_RAW)) + if (!(data->permitted & (1 << CAP_NET_RAW))) { // Needed for raw socket access (necessary for ICMP) logg("************************************************************"); logg("WARNING: Required linux capability CAP_NET_RAW not available"); logg("************************************************************"); - return false; + missing = true; } - if(!cap_get_bound(CAP_NET_BIND_SERVICE)) + if (!(data->permitted & (1 << CAP_NET_BIND_SERVICE))) { // Necessary for dynamic port binding logg("*********************************************************************"); logg("WARNING: Required linux capability CAP_NET_BIND_SERVICE not available"); logg("*********************************************************************"); - return false; + missing = true; + } + if (!(data->permitted & (1 << CAP_SETUID))) + { + // Necessary for changing our own user ID ("daemonizing") + logg("*********************************************************************"); + logg("WARNING: Required linux capability CAP_SETUID not available"); + logg("*********************************************************************"); + missing = true; } // All okay! - return true; + return missing; }