]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Linux: use libcap for capability management if possible. [RT# 18026]
authorEvan Hunt <each@isc.org>
Tue, 6 May 2008 01:33:33 +0000 (01:33 +0000)
committerEvan Hunt <each@isc.org>
Tue, 6 May 2008 01:33:33 +0000 (01:33 +0000)
CHANGES
bin/named/unix/os.c
config.h.in
configure
configure.in

diff --git a/CHANGES b/CHANGES
index 69711d3c65ddf13d4e0affee936ba3ef675d5d26..639f6a86ff862fc2a38f4d793af1e4b5bfd72055 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+2368.   [port]          Linux: use libcap for capability management if
+                        possible. [RT# 18026]
+
 2367.   [bug]           Improve counting of dns_resstatscounter_retry
                         [RT #18030]
 
index 89e43054d3f26d5dbc67033d8355052e466b7624..16a4272a7b5cad42fe562a00355202a4f037625b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: os.c,v 1.79.128.4 2008/01/30 04:55:51 marka Exp $ */
+/* $Id: os.c,v 1.79.128.5 2008/05/06 01:32:51 each Exp $ */
 
 /*! \file */
 
@@ -69,7 +69,7 @@ static int devnullfd = -1;
 /*
  * Linux defines:
  *     (T) HAVE_LINUXTHREADS
- *     (C) HAVE_LINUX_CAPABILITY_H
+ *     (C) HAVE_SYS_CAPABILITY_H (or HAVE_LINUX_CAPABILITY_H)
  *     (P) HAVE_SYS_PRCTL_H
  * The possible cases are:
  *     none:   setuid() normally
@@ -116,16 +116,9 @@ static int dfd[2] = { -1, -1 };
 static isc_boolean_t non_root = ISC_FALSE;
 static isc_boolean_t non_root_caps = ISC_FALSE;
 
-#if defined(HAVE_CAPSET)
-#undef _POSIX_SOURCE
 #ifdef HAVE_SYS_CAPABILITY_H
 #include <sys/capability.h>
 #else
-#include <linux/capability.h>
-int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
-#endif
-#include <sys/prctl.h>
-#else
 /*%
  * We define _LINUX_FS_H to prevent it from being included.  We don't need
  * anything from it, and the files it includes cause warnings with 2.2
@@ -133,9 +126,15 @@ int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
  * and <string.h>) on 2.3 kernels.
  */
 #define _LINUX_FS_H
-
-#include <sys/syscall.h>       /* Required for syscall(). */
-#include <linux/capability.h>  /* Required for _LINUX_CAPABILITY_VERSION. */
+#include <linux/capability.h>
+#include <syscall.h>
+#ifndef SYS_capset
+#ifndef __NR_capset
+#include <asm/unistd.h> /* Slackware 4.0 needs this. */
+#endif /* __NR_capset */
+#define SYS_capset __NR_capset
+#endif /* SYS_capset */
+#endif /* HAVE_SYS_CAPABILITY_H */
 
 #ifdef HAVE_SYS_PRCTL_H
 #include <sys/prctl.h>         /* Required for prctl(). */
@@ -152,23 +151,24 @@ int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
 
 #endif /* HAVE_SYS_PRCTL_H */
 
-#ifndef SYS_capset
-#ifndef __NR_capset
-#include <asm/unistd.h> /* Slackware 4.0 needs this. */
-#endif
-#define SYS_capset __NR_capset
-#endif
-#endif
+#ifdef HAVE_LIBCAP
+#define SETCAPS_FUNC "cap_set_proc "
+#else
+typedef unsigned int cap_t;
+#define SETCAPS_FUNC "syscall(capset) "
+#endif /* HAVE_LIBCAP */
 
 static void
-linux_setcaps(unsigned int caps) {
+linux_setcaps(cap_t caps) {
+#ifndef HAVE_LIBCAP
        struct __user_cap_header_struct caphead;
        struct __user_cap_data_struct cap;
+#endif
        char strbuf[ISC_STRERRORSIZE];
 
        if ((getuid() != 0 && !non_root_caps) || non_root)
                return;
-
+#ifndef HAVE_LIBCAP
        memset(&caphead, 0, sizeof(caphead));
        caphead.version = _LINUX_CAPABILITY_VERSION;
        caphead.pid = 0;
@@ -176,46 +176,74 @@ linux_setcaps(unsigned int caps) {
        cap.effective = caps;
        cap.permitted = caps;
        cap.inheritable = 0;
-#ifdef HAVE_CAPSET
-       if (capset(&caphead, &cap) < 0 ) {
-               isc__strerror(errno, strbuf, sizeof(strbuf));
-               ns_main_earlyfatal("capset failed: %s:"
-                                  " please ensure that the capset kernel"
-                                  " module is loaded.  see insmod(8)",
-                                  strbuf);
-       }
+#endif
+#ifdef HAVE_LIBCAP
+       if (cap_set_proc(caps) < 0) {
 #else
        if (syscall(SYS_capset, &caphead, &cap) < 0) {
+#endif
                isc__strerror(errno, strbuf, sizeof(strbuf));
-               ns_main_earlyfatal("syscall(capset) failed: %s:"
+               ns_main_earlyfatal(SETCAPS_FUNC "failed: %s:"
                                   " please ensure that the capset kernel"
                                   " module is loaded.  see insmod(8)",
                                   strbuf);
        }
-#endif
 }
 
+#ifdef HAVE_LIBCAP
+#define SET_CAP(flag) \
+       do { \
+               capval = (flag); \
+               err = cap_set_flag(caps, CAP_EFFECTIVE, 1, &capval, CAP_SET); \
+               if (err == -1) { \
+                       isc__strerror(errno, strbuf, sizeof(strbuf)); \
+                       ns_main_earlyfatal("cap_set_proc failed: %s", strbuf); \
+               } \
+               \
+               err = cap_set_flag(caps, CAP_PERMITTED, 1, &capval, CAP_SET); \
+               if (err == -1) { \
+                       isc__strerror(errno, strbuf, sizeof(strbuf)); \
+                       ns_main_earlyfatal("cap_set_proc failed: %s", strbuf); \
+               } \
+       } while (0)
+#define INIT_CAP \
+       do { \
+               caps = cap_init(); \
+               if (caps == NULL) { \
+                       isc__strerror(errno, strbuf, sizeof(strbuf)); \
+                       ns_main_earlyfatal("cap_init failed: %s", strbuf); \
+               } \
+       } while (0)
+#else
+#define SET_CAP(flag) { caps |= (1 << (flag)); }
+#define INIT_CAP { caps = 0; }
+#endif /* HAVE_LIBCAP */
+
 static void
 linux_initialprivs(void) {
-       unsigned int caps;
+       cap_t caps;
+#ifdef HAVE_LIBCAP
+       cap_value_t capval;
+       char strbuf[ISC_STRERRORSIZE];
+       int err;
+#endif
 
        /*%
         * We don't need most privileges, so we drop them right away.
         * Later on linux_minprivs() will be called, which will drop our
         * capabilities to the minimum needed to run the server.
         */
-
-       caps = 0;
+       INIT_CAP;
 
        /*
         * We need to be able to bind() to privileged ports, notably port 53!
         */
-       caps |= (1 << CAP_NET_BIND_SERVICE);
+       SET_CAP(CAP_NET_BIND_SERVICE);
 
        /*
         * We need chroot() initially too.
         */
-       caps |= (1 << CAP_SYS_CHROOT);
+       SET_CAP(CAP_SYS_CHROOT);
 
 #if defined(HAVE_SYS_PRCTL_H) || !defined(HAVE_LINUXTHREADS)
        /*
@@ -224,19 +252,19 @@ linux_initialprivs(void) {
         * tried) or we're not using threads.  If either of these is
         * true, we want the setuid capability.
         */
-       caps |= (1 << CAP_SETUID);
+       SET_CAP(CAP_SETUID);
 #endif
 
        /*
         * Since we call initgroups, we need this.
         */
-       caps |= (1 << CAP_SETGID);
+       SET_CAP(CAP_SETGID);
 
        /*
         * Without this, we run into problems reading a configuration file
         * owned by a non-root user and non-world-readable on startup.
         */
-       caps |= (1 << CAP_DAC_READ_SEARCH);
+       SET_CAP(CAP_DAC_READ_SEARCH);
 
        /*
         * XXX  We might want to add CAP_SYS_RESOURCE, though it's not
@@ -245,15 +273,21 @@ linux_initialprivs(void) {
         * of files, the stack size, data size, and core dump size to
         * support named.conf options, this is now being added to test.
         */
-       caps |= (1 << CAP_SYS_RESOURCE);
+       SET_CAP(CAP_SYS_RESOURCE);
 
        linux_setcaps(caps);
 }
 
 static void
 linux_minprivs(void) {
-       unsigned int caps;
+       cap_t caps;
+#ifdef HAVE_LIBCAP
+       cap_value_t capval;
+       char strbuf[ISC_STRERRORSIZE];
+       int err;
+#endif
 
+       INIT_CAP;
        /*%
         * Drop all privileges except the ability to bind() to privileged
         * ports.
@@ -262,8 +296,7 @@ linux_minprivs(void) {
         * chroot() could be used to escape from the chrooted area.
         */
 
-       caps = 0;
-       caps |= (1 << CAP_NET_BIND_SERVICE);
+       SET_CAP(CAP_NET_BIND_SERVICE);
 
        /*
         * XXX  We might want to add CAP_SYS_RESOURCE, though it's not
@@ -272,7 +305,7 @@ linux_minprivs(void) {
         * of files, the stack size, data size, and core dump size to
         * support named.conf options, this is now being added to test.
         */
-       caps |= (1 << CAP_SYS_RESOURCE);
+       SET_CAP(CAP_SYS_RESOURCE);
 
        linux_setcaps(caps);
 }
index 2f211af5690626bc05d19b32e20ecb16d841fc70..e0fbcfc9ca5fe3c4419da1cab697fde019d353d0 100644 (file)
@@ -16,7 +16,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: config.h.in,v 1.90.60.7 2008/04/28 23:51:45 marka Exp $ */
+/* $Id: config.h.in,v 1.90.60.8 2008/05/06 01:32:51 each Exp $ */
 
 /*! \file */
 
@@ -160,9 +160,6 @@ int sigwait(const unsigned int *set, int *sig);
 /* Define to enable "rrset-order fixed" syntax. */
 #undef DNS_RDATASET_FIXED
 
-/* Define to 1 if you have the `capset' function. */
-#undef HAVE_CAPSET
-
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
 
@@ -181,6 +178,9 @@ int sigwait(const unsigned int *set, int *sig);
 /* Define to 1 if you have the `c' library (-lc). */
 #undef HAVE_LIBC
 
+/* Define to 1 if you have the `cap' library (-lcap). */
+#undef HAVE_LIBCAP
+
 /* Define to 1 if you have the `c_r' library (-lc_r). */
 #undef HAVE_LIBC_R
 
index 7bfb7a9075baf67063cf758415e010368a9903f8..7e616d0bec75ec066905ca5e20f04e92e2202141 100755 (executable)
--- a/configure
+++ b/configure
@@ -14,7 +14,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 #
-# $Id: configure,v 1.418.60.7 2008/04/28 23:51:45 marka Exp $
+# $Id: configure,v 1.418.60.8 2008/05/06 01:33:33 each Exp $
 #
 # Portions Copyright (C) 1996-2001  Nominum, Inc.
 #
@@ -29,7 +29,7 @@
 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-# From configure.in Revision: 1.432.60.8 .
+# From configure.in Revision: 1.432.60.9 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.61.
 #
 done
 
 
-for ac_func in capset
-do
-as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+{ echo "$as_me:$LINENO: checking for cap_set_proc in -lcap" >&5
+echo $ECHO_N "checking for cap_set_proc in -lcap... $ECHO_C" >&6; }
+if test "${ac_cv_lib_cap_cap_set_proc+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcap  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
 
 /* Override any GCC internal prototype to avoid an error.
    Use char because int might match the return type of a GCC
@@ -27678,18 +27661,11 @@ cat >>conftest.$ac_ext <<_ACEOF
 #ifdef __cplusplus
 extern "C"
 #endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
-
+char cap_set_proc ();
 int
 main ()
 {
-return $ac_func ();
+return cap_set_proc ();
   ;
   return 0;
 }
@@ -27712,27 +27688,28 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
         test ! -s conftest.err
        } && test -s conftest$ac_exeext &&
        $as_test_x conftest$ac_exeext; then
-  eval "$as_ac_var=yes"
+  ac_cv_lib_cap_cap_set_proc=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       eval "$as_ac_var=no"
+       ac_cv_lib_cap_cap_set_proc=no
 fi
 
 rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
       conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
 fi
-ac_res=`eval echo '${'$as_ac_var'}'`
-              { echo "$as_me:$LINENO: result: $ac_res" >&5
-echo "${ECHO_T}$ac_res" >&6; }
-if test `eval echo '${'$as_ac_var'}'` = yes; then
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_cap_cap_set_proc" >&5
+echo "${ECHO_T}$ac_cv_lib_cap_cap_set_proc" >&6; }
+if test $ac_cv_lib_cap_cap_set_proc = yes; then
   cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define HAVE_LIBCAP 1
 _ACEOF
 
+  LIBS="-lcap $LIBS"
+
 fi
-done
 
                ;;
        no)
index b1b092699c59da41836227ae93077ac5fca25757..4ffa8d7bbd63f8e108952b460d10ea23377a7e10 100644 (file)
@@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl
 esyscmd([sed "s/^/# /" COPYRIGHT])dnl
 AC_DIVERT_POP()dnl
 
-AC_REVISION($Revision: 1.432.60.8 $)
+AC_REVISION($Revision: 1.432.60.9 $)
 
 AC_INIT(lib/dns/name.c)
 AC_PREREQ(2.59)
@@ -1884,7 +1884,7 @@ AC_ARG_ENABLE(linux-caps,
 case "$enable_linux_caps" in
        yes|'')
                AC_CHECK_HEADERS(linux/capability.h sys/capability.h)
-               AC_CHECK_FUNCS(capset)
+               AC_CHECK_LIB(cap, cap_set_proc)
                ;;
        no)
                ;;