From ef72742ea7d6e9d4936d74eba0a4754c0fd4cc2a Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 3 Mar 2019 08:47:34 +0100 Subject: [PATCH 1/2] Open raw sockets when adding hosts, not when doing the pinging This allows this to run as non-root again, without this, oping will have dropped privileges before trying to ping, which then fails to open the necessary raw sockets. Fixes: octo#34 Patch from https://github.com/tfheen/liboping/commit/a88c51f38dafa1fba9118045176754bec05d3c94?diff=split --- src/liboping.c | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/src/liboping.c b/src/liboping.c index 5253e8c..4344b71 100644 --- a/src/liboping.c +++ b/src/liboping.c @@ -1344,41 +1344,10 @@ int ping_send (pingobj_t *obj) struct timeval nowtime; struct timeval timeout; - _Bool need_ipv4_socket = 0; - _Bool need_ipv6_socket = 0; - for (ptr = obj->head; ptr != NULL; ptr = ptr->next) { ptr->latency = -1.0; ptr->recv_ttl = -1; - - if (ptr->addrfamily == AF_INET) - need_ipv4_socket = 1; - else if (ptr->addrfamily == AF_INET6) - need_ipv6_socket = 1; - } - - if (!need_ipv4_socket && !need_ipv6_socket) - { - ping_set_error (obj, "ping_send", "No hosts to ping"); - return (-1); - } - - if (need_ipv4_socket && obj->fd4 == -1) - { - obj->fd4 = ping_open_socket(obj, AF_INET); - if (obj->fd4 == -1) - return (-1); - ping_set_ttl (obj, obj->ttl); - ping_set_qos (obj, obj->qos); - } - if (need_ipv6_socket && obj->fd6 == -1) - { - obj->fd6 = ping_open_socket(obj, AF_INET6); - if (obj->fd6 == -1) - return (-1); - ping_set_ttl (obj, obj->ttl); - ping_set_qos (obj, obj->qos); } if (gettimeofday (&nowtime, NULL) == -1) @@ -1701,6 +1670,22 @@ int ping_host_add (pingobj_t *obj, const char *host) ph->table_next = obj->table[ph->ident % PING_TABLE_LEN]; obj->table[ph->ident % PING_TABLE_LEN] = ph; + if (ph->addrfamily == AF_INET && obj->fd4 == -1) + { + obj->fd4 = ping_open_socket(obj, AF_INET); + if (obj->fd4 == -1) + return (-1); + ping_set_ttl (obj, obj->ttl); + ping_set_qos (obj, obj->qos); + } + if (ph->addrfamily == AF_INET6 && obj->fd6 == -1) + { + obj->fd6 = ping_open_socket(obj, AF_INET6); + if (obj->fd6 == -1) + return (-1); + ping_set_ttl (obj, obj->ttl); + ping_set_qos (obj, obj->qos); + } return (0); } /* int ping_host_add */ From f7dd15231330c07b16075a88e76de6dc918e3a9b Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 3 Mar 2019 10:38:06 +0100 Subject: [PATCH 2/2] Manage effecfive cap_net_raw management added: Set (enable) to create the raw socket then cleared. --- configure.ac | 25 +++++++++++++++++---- src/Makefile.am | 2 ++ src/liboping.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 6ac83f9..e86b13f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.65]) AC_INIT([liboping], - [1.10.0], + [1.10.0.1], [liboping@verplant.org], [], [http://noping.cc/]) @@ -24,7 +24,7 @@ AC_SUBST(LIBOPING_PATCH) # ABI version LIBOPING_CURRENT=3 -LIBOPING_REVISION=0 +LIBOPING_REVISION=1 LIBOPING_AGE=3 AC_SUBST(LIBOPING_CURRENT) AC_SUBST(LIBOPING_REVISION) @@ -62,7 +62,7 @@ AC_SUBST([pkgconfigdir]) # Checks for header files. AC_HEADER_STDC AC_HEADER_TIME -AC_CHECK_HEADERS([math.h signal.h fcntl.h inttypes.h netdb.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h locale.h langinfo.h]) +AC_CHECK_HEADERS([math.h signal.h fcntl.h inttypes.h netdb.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h locale.h langinfo.h sys/capability.h]) # This sucks, but what can I do..? AC_CHECK_HEADERS(netinet/in_systm.h, [], [], @@ -239,6 +239,20 @@ AC_ARG_ENABLE(debug, [AS_HELP_STRING([--enable-debug], [Enable extensive debuggi ], []) AM_CONDITIONAL(BUILD_WITH_DEBUG, test "x$enable_debug" = "xyes") +AC_ARG_ENABLE(effective-cap, + [ --enable-effective-cap enable effective capabilities management (default is yes) ], + [case "${enableval}" in + yes) enable_effective_cap="yes";; + no) enable_effective_cap="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-effective-cap) ;; + esac], + [enable_effective_cap="yes"] +) +if test "$enable_effective_cap" = "yes"; then + AC_DEFINE(_EFFECTIVE_CAPABILITIES_MANAGEMENT_, 1, [Defined if the effective capabilities management is enabled.]) +fi + + AC_ARG_WITH(perl-bindings, [AS_HELP_STRING([--with-perl-bindings@<:@=OPTIONS@:>@], [Options passed to "perl Makefile.PL".])], [ if test "x$withval" != "xno" && test "x$withval" != "xyes" @@ -267,9 +281,12 @@ AC_SUBST(PERL_BINDINGS_OPTIONS) AC_SUBST(BINDINGS) # Checks for library functions. +AC_C_INLINE AC_FUNC_MALLOC AC_FUNC_STRERROR_R -AC_CHECK_FUNCS([gettimeofday memset modf select socket sqrt strcasecmp strdup strerror strncasecmp strtoul]) +AC_FUNC_STRTOD +AC_CHECK_FUNCS([gettimeofday memset modf select socket sqrt strcasecmp strdup strerror strncasecmp strtoul nl_langinfo setlocale strtol]) + AC_CONFIG_FILES([Makefile src/Makefile src/liboping.pc src/mans/Makefile bindings/Makefile]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index b8571aa..29b3eed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,9 @@ lib_LTLIBRARIES = liboping.la liboping_la_SOURCES = oping.h liboping.c liboping_la_CPPFLAGS = $(AM_CPPFLAGS) +liboping_la_CPPFLAGS += `pkg-config --cflags libcap` liboping_la_LDFLAGS = $(AM_LDFLAGS) -version-info @LIBOPING_CURRENT@:@LIBOPING_REVISION@:@LIBOPING_AGE@ +liboping_la_LDFLAGS += `pkg-config --libs libcap` liboping_la_LIBADD = $(LIBOPING_PC_LIBS_PRIVATE) pkgconfig_DATA = liboping.pc diff --git a/src/liboping.c b/src/liboping.c index 4344b71..45ef981 100644 --- a/src/liboping.c +++ b/src/liboping.c @@ -73,6 +73,10 @@ # include #endif +#ifdef HAVE_SYS_CAPABILITY_H +# include +#endif + #if HAVE_NETINET_IN_SYSTM_H # include #endif @@ -967,6 +971,58 @@ static void ping_free (pinghost_t *ph) free (ph); } +#if defined(HAVE_SYS_CAPABILITY_H) && defined(_EFFECTIVE_CAPABILITIES_MANAGEMENT_) +static inline void manage_effective_cap_net_raw(pingobj_t *obj,const cap_flag_value_t operation) +{ + const uid_t euid = geteuid(); + if (euid != 0) + { + if ((CAP_IS_SUPPORTED(CAP_SETFCAP)) && (CAP_IS_SUPPORTED(CAP_SETPCAP))) + { + cap_t capabilities = cap_get_proc(); + if (capabilities) + { + const cap_value_t caps[] = + { + CAP_NET_RAW + }; + const int ncaps = sizeof(caps)/sizeof(caps[0]); + if (cap_set_flag(capabilities,CAP_EFFECTIVE,ncaps,caps,operation) == 0) + { + if (cap_set_proc(capabilities) != 0) + { + const int error = errno; + ping_set_errno (obj, error); + dprintf ("cap_set_proc(3) error %d",error); + } + } + else + { + const int error = errno; + ping_set_errno (obj, error); + dprintf ("cap_set_flag(3) error %d",error); + } + cap_free(capabilities); + capabilities = NULL; + } + else + { + const int error = errno; + ping_set_errno (obj, error); + dprintf ("cap_get_proc(3) error %d",error); + } + } + else + { + ping_set_errno (obj, EPERM); + ping_set_error (obj,"ping_open_socket","System doesn't have capabilities support enabled"); + } + } +} +#else /* defined(HAVE_SYS_CAPABILITY_H) && defined(_EFFECTIVE_CAPABILITIES_MANAGEMENT_) */ +#define manage_effective_cap_net_raw(obj,operation) +#endif /* defined(HAVE_SYS_CAPABILITY_H) && defined(_EFFECTIVE_CAPABILITIES_MANAGEMENT_) */ + /* ping_open_socket opens, initializes and returns a new raw socket to use for * ICMPv4 or ICMPv6 packets. addrfam must be either AF_INET or AF_INET6. On * error, -1 is returned and obj->errmsg is set appropriately. */ @@ -975,11 +1031,15 @@ static int ping_open_socket(pingobj_t *obj, int addrfam) int fd; if (addrfam == AF_INET6) { + manage_effective_cap_net_raw(obj,CAP_SET); fd = socket(addrfam, SOCK_RAW, IPPROTO_ICMPV6); + manage_effective_cap_net_raw(obj,CAP_CLEAR); } else if (addrfam == AF_INET) { + manage_effective_cap_net_raw(obj,CAP_SET); fd = socket(addrfam, SOCK_RAW, IPPROTO_ICMP); + manage_effective_cap_net_raw(obj,CAP_CLEAR); } else /* this should not happen */ {