]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Author: Henrik Nordstrom <henrik@henriknordstrom.net>
authorAmos Jeffries <squid3@treenet.co.nz>
Thu, 29 Oct 2009 08:52:53 +0000 (21:52 +1300)
committerAmos Jeffries <squid3@treenet.co.nz>
Thu, 29 Oct 2009 08:52:53 +0000 (21:52 +1300)
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
src/tools.cc

index b0576a7ec4ca3607810e786fa791ddb9f0b96225..9aa18580413211e9df37fcd9d30050b58f6240a9 100644 (file)
@@ -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 <sys/capability.h>]], [[
-                    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 <stdlib.h>
+#include <stddef.h>
+#include <sys/capability.h>
+]], [[
+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 <sys/types.h>
 #include <sys/ipc.h>
 #include <sys/msg.h>])
@@ -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
index 311f007fc36698bccefc512d164938c62662a247..53fc272774dc32b7646e791a0908d1fa952f0a1e 100644 (file)
@@ -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 *