Skip to content

Effective net_raw capability management #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

AC_PREREQ([2.65])
AC_INIT([liboping],
[1.10.0],
[1.10.0.1],
[liboping@verplant.org],
[],
[http://noping.cc/])
Expand All @@ -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)
Expand Down Expand Up @@ -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, [], [],
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
107 changes: 76 additions & 31 deletions src/liboping.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@
# include <netdb.h>
#endif

#ifdef HAVE_SYS_CAPABILITY_H
# include <sys/capability.h>
#endif

#if HAVE_NETINET_IN_SYSTM_H
# include <netinet/in_systm.h>
#endif
Expand Down Expand Up @@ -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. */
Expand All @@ -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 */
{
Expand Down Expand Up @@ -1344,41 +1404,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)
Expand Down Expand Up @@ -1701,6 +1730,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 */

Expand Down