From 03ced8e57268081da1e53d61b68c79ed4b302408 Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Thu, 29 Oct 2009 21:52:53 +1300 Subject: [PATCH] Author: Henrik Nordstrom Use libcap functions instead of raw kernel interface Rework the Linux capabilities code to use the more stable libcap interface instead or raw kernel syscalls. Take two, making sure there is a sufficiently recent libcap-2.09 or later. --- configure.in | 57 +++++++++++++++++++++++++++++++++++----------------- src/tools.cc | 54 +++++++++++++++++++------------------------------ 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/configure.in b/configure.in index b0576a7ec4..9aa1858041 100644 --- a/configure.in +++ b/configure.in @@ -2491,28 +2491,49 @@ AC_CHECK_TYPE(socklen_t,AC_DEFINE(HAVE_SOCKLEN_T,1,[socklen_t is defined by the #endif]) dnl Check for libcap header (assume its not broken unless -use_caps=yes -AC_ARG_ENABLE(caps, AS_HELP_STRING([--disable-caps],[disable usage of Linux capabilities library to control privileges]), -[ if test "x$enableval" = "xyes" ; then - AC_MSG_RESULT(forced yes) +use_libcap=auto +AC_ARG_WITH(libcap, AS_HELP_STRING([--without-libcap],[disable usage of Linux capabilities library to control privileges]), +[ if test "x$withval" = "xyes" ; then + AC_MSG_RESULT(libcap forced enabled) + use_libcap=yes else - AC_MSG_RESULT(no) - use_caps=no + AC_MSG_RESULT(libcap forced disabled) + use_libcap=no fi -],[AC_MSG_RESULT(yes)]) -if test "x$use_caps" = "xyes"; then - dnl Check for libcap1 breakage or libcap2 fixed (assume broken unless found working) - libcap_broken=1 +]) +if test "x$use_libcap" != "xno"; then + # cap_clear_flag is the most recent libcap function we require + AC_CHECK_LIB(cap, cap_clear_flag) + if test "x$ac_cv_lib_cap_cap_clear_flag" = xyes; then + use_libcap=yes + else + if test "x$use_libcap" = "xyes"; then + AC_MSG_ERROR([libcap forced enabled but not available or not usable, requires libcap-2.09 or later]) + fi + use_libcap=no + fi +fi + +if test "x$use_libcap" = "xyes"; then + AC_DEFINE(USE_LIBCAP, 1, [use libcap to set capabilities required for TPROXY]) + dnl Check for libcap headader breakage. AC_CHECK_HEADERS(sys/capability.h) - AC_CACHE_CHECK([for operational libcap2], $libcap_broken, - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ - capget(NULL, NULL); - capset(NULL, NULL); - ]])],[libcap_broken=0],[]) + AC_CACHE_CHECK([for operational libcap2 headers], squid_cv_sys_capability_works, + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +]], [[ +capget(NULL, NULL); +capset(NULL, NULL); + ]])],[squid_cv_sys_capability_works=yes],[squid_cv_sys_capability_works=no]) ) - AC_DEFINE_UNQUOTED([LIBCAP_BROKEN],$libcap_broken,[if libcap2 is available and not clashing with libc]) + if test x$squid_cv_sys_capability_works != xyes; then + AC_DEFINE([LIBCAP_BROKEN],1,[if libcap2 headers are broken and clashing with glibc]) + fi fi + AC_CHECK_TYPE(mtyp_t,AC_DEFINE(HAVE_MTYP_T,1,[mtyp_t is defined by the system headers]),,[#include #include #include ]) @@ -3248,7 +3269,7 @@ if test "$LINUX_NETFILTER" = "no" ; then sleep 10 fi dnl Netfilter TPROXY depends on libcap but the NAT parts can still work. -if test "$LINUX_NETFILTER" = "yes" && test "$use_caps" != "yes" ; then +if test "$LINUX_NETFILTER" = "yes" && test "$use_libcap" != "yes" ; then AC_MSG_WARN([Missing needed capabilities (libcap or libcap2) for TPROXY]) AC_MSG_WARN([Linux Transparent Proxy support WILL NOT be enabled]) AC_MSG_WARN([Reduced support to Interception Proxy]) @@ -3258,7 +3279,7 @@ fi dnl Linux Netfilter/TPROXYv2 support requires some specific header files dnl Shamelessly copied from above if test "$LINUX_TPROXY2"; then - if test "$use_caps" = "yes"; then + if test "$use_libcap" = "yes"; then AC_MSG_CHECKING(if TPROXYv2 header files are installed) # hold on to your hats... if test "$ac_cv_header_linux_netfilter_ipv4_ip_tproxy_h" = "yes" && test "$LINUX_NETFILTER" = "yes"; then diff --git a/src/tools.cc b/src/tools.cc index 311f007fc3..53fc272774 100644 --- a/src/tools.cc +++ b/src/tools.cc @@ -1228,7 +1228,7 @@ strwordquote(MemBuf * mb, const char *str) void keepCapabilities(void) { -#if HAVE_PRCTL && defined(PR_SET_KEEPCAPS) && HAVE_SYS_CAPABILITY_H +#if HAVE_PRCTL && defined(PR_SET_KEEPCAPS) && USE_LIBCAP if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { IpInterceptor.StopTransparency("capability setting has failed."); @@ -1240,51 +1240,39 @@ static void restoreCapabilities(int keep) { /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */ -#if defined(_SQUID_LINUX_) - -#if HAVE_SYS_CAPABILITY_H -#ifndef _LINUX_CAPABILITY_VERSION_1 -#define _LINUX_CAPABILITY_VERSION_1 _LINUX_CAPABILITY_VERSION -#endif - cap_user_header_t head = (cap_user_header_t) xcalloc(1, sizeof(*head)); - cap_user_data_t cap = (cap_user_data_t) xcalloc(1, sizeof(*cap)); - - head->version = _LINUX_CAPABILITY_VERSION_1; - - if (capget(head, cap) != 0) { - debugs(50, DBG_IMPORTANT, "Can't get current capabilities"); - } else if (head->version != _LINUX_CAPABILITY_VERSION_1) { - debugs(50, DBG_IMPORTANT, "Invalid capability version " << head->version << " (expected " << _LINUX_CAPABILITY_VERSION_1 << ")"); +#if USE_LIBCAP + cap_t caps; + if (keep) + caps = cap_get_proc(); + else + caps = cap_init(); + if (!caps) { + IpInterceptor.StopTransparency("Can't get current capabilities"); } else { - - head->pid = 0; - - cap->inheritable = 0; - cap->effective = (1 << CAP_NET_BIND_SERVICE); + int ncaps = 0; + int rc = 0; + cap_value_t cap_list[10]; + cap_list[ncaps++] = CAP_NET_BIND_SERVICE; if (IpInterceptor.TransparentActive()) { - cap->effective |= (1 << CAP_NET_ADMIN); + cap_list[ncaps++] = CAP_NET_ADMIN; #if LINUX_TPROXY2 - cap->effective |= (1 << CAP_NET_BROADCAST); + cap_list[ncaps++] = CAP_NET_BROADCAST; #endif } - if (!keep) - cap->permitted &= cap->effective; + cap_clear_flag(caps, CAP_EFFECTIVE); + rc |= cap_set_flag(caps, CAP_EFFECTIVE, ncaps, cap_list, CAP_SET); + rc |= cap_set_flag(caps, CAP_PERMITTED, ncaps, cap_list, CAP_SET); - if (capset(head, cap) != 0) { + if (rc || cap_set_proc(caps) != 0) { IpInterceptor.StopTransparency("Error enabling needed capabilities."); } + cap_free(caps); } - - xfree(head); - xfree(cap); - -#else +#elif defined(_SQUID_LINUX_) IpInterceptor.StopTransparency("Missing needed capability support."); #endif /* HAVE_SYS_CAPABILITY_H */ - -#endif /* !defined(_SQUID_LINUX_) */ } void * -- 2.47.3