From ee9029b8fb1ebfa7545dcb739f338fef46f0223c Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 28 Jan 2020 20:31:46 +0300 Subject: [PATCH] pppd: Check CAP_NET_RAW capability on Linux rather than requiring euid 0 Introduce USE_LIBCAP option turned on by default for the linux build. Provide an option to check that we are capable to admin the network wihout root via CAP_NET_RAW libcap option. Requires libcap library. Fallback to geteuid method in case of Solaris and Linux without libcap. Signed-off-by: Alexey Andreev --- pppd/Makefile.linux | 8 ++++++++ pppd/main.c | 7 +++---- pppd/pppd.h | 1 + pppd/sys-linux.c | 41 +++++++++++++++++++++++++++++++++++++++++ pppd/sys-solaris.c | 14 ++++++++++++++ 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux index 22837c504..d461b4835 100644 --- a/pppd/Makefile.linux +++ b/pppd/Makefile.linux @@ -79,6 +79,9 @@ PLUGIN=y # Enable EAP SRP-SHA1 authentication (requires libsrp) #USE_SRP=y +# Use libcap (requires libcap) +USE_LIBCAP=y + # Use libutil; test if logwtmp is declared in to detect ifeq ($(shell echo '\#include ' | $(CC) -E - 2>/dev/null | grep -q logwtmp && echo yes),yes) USE_LIBUTIL=y @@ -148,6 +151,11 @@ CFLAGS += -DHAVE_CRYPT_H=1 LIBS += -lcrypt endif +ifdef USE_LIBCAP +CFLAGS += -DUSE_CAP +LIBS += -lcap +endif + ifdef USE_LIBUTIL CFLAGS += -DHAVE_LOGWTMP=1 LIBS += -lutil diff --git a/pppd/main.c b/pppd/main.c index 87a5d2921..6af3b9b00 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -360,11 +360,10 @@ main(int argc, char *argv[]) setlogmask(LOG_UPTO(LOG_DEBUG)); /* - * Check that we are running as root. + * Check that we are capable to admin the network. */ - if (geteuid() != 0) { - option_error("must be root to run %s, since it is not setuid-root", - argv[0]); + if (!net_capable()) { + option_error("must have CAP_NET_RAW or root privilege to run %s", argv[0]); exit(EXIT_NOT_ROOT); } diff --git a/pppd/pppd.h b/pppd/pppd.h index 612902f55..520405d2f 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -622,6 +622,7 @@ void sys_init(void); /* Do system-dependent initialization */ void sys_cleanup(void); /* Restore system state before exiting */ int sys_check_options(void); /* Check options specified */ void sys_close(void); /* Clean up in a child before execing */ +int net_capable __P((void)); /* Test for any access to the net management */ int ppp_available(void); /* Test whether ppp kernel support exists */ int get_pty(int *, int *, char *, int); /* Get pty master/slave */ int open_ppp_loopback(void); /* Open loopback for demand-dialling */ diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index b7972b908..d13d7d6df 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -144,6 +144,11 @@ #include #endif +#ifdef USE_CAP +#include +#include +#endif /* USE_CAP */ + #ifdef INET6 #ifndef _LINUX_IN6_H /* @@ -2329,6 +2334,42 @@ ppp_registered(void) return ret; } +/*********************************************************** + * + * net_capable - check for any access to the net management + */ + +int net_capable(void) +{ + int ok = 0; +#ifdef USE_CAP + /* + * Check that we are capable to admin the network. + */ + cap_t cap; + cap_flag_value_t cap_flag_value; + cap = cap_get_pid(getpid()); + if (cap != 0) { + if (cap_get_flag(cap, CAP_NET_RAW, CAP_EFFECTIVE, &cap_flag_value) == 0) { + if (cap_flag_value == CAP_SET) + ok = 1; + } + if (cap_get_flag(cap, CAP_NET_RAW, CAP_PERMITTED, &cap_flag_value) == 0) { + if (cap_flag_value == CAP_SET) + ok = 1; + } + } +#else /* USE_CAP */ + /* + * Check that we are running as root. + */ + if (geteuid() == 0) { + ok = 1; + } +#endif /* USE_CAP */ + return ok; +} + /******************************************************************** * * ppp_available - check whether the system has any ppp interfaces diff --git a/pppd/sys-solaris.c b/pppd/sys-solaris.c index e0cd0be32..171a4a97d 100644 --- a/pppd/sys-solaris.c +++ b/pppd/sys-solaris.c @@ -852,6 +852,20 @@ daemon(int nochdir, int noclose) } #endif +/*********************************************************** + * + * net_capable - check for any access to the net management + */ + +int net_capable(void) +{ + int ok = 0; + if (geteuid() == 0) { + ok = 1; + } + return ok; +} + /* * ppp_available - check whether the system has any ppp interfaces */