Commit 0415ca35 authored by Evan Hunt's avatar Evan Hunt

Linux: use libcap for capability management if possible. [RT# 18026]

parent 69ec1b7e
2368. [port] Linux: use libcap for capability management if
possible. [RT# 18026]
2367. [bug] Improve counting of dns_resstatscounter_retry 2367. [bug] Improve counting of dns_resstatscounter_retry
[RT #18030] [RT #18030]
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id: os.c,v 1.83 2008/01/30 04:48:05 marka Exp $ */ /* $Id: os.c,v 1.84 2008/05/06 01:30:26 each Exp $ */
/*! \file */ /*! \file */
...@@ -69,7 +69,7 @@ static int devnullfd = -1; ...@@ -69,7 +69,7 @@ static int devnullfd = -1;
/* /*
* Linux defines: * Linux defines:
* (T) HAVE_LINUXTHREADS * (T) HAVE_LINUXTHREADS
* (C) HAVE_LINUX_CAPABILITY_H * (C) HAVE_SYS_CAPABILITY_H (or HAVE_LINUX_CAPABILITY_H)
* (P) HAVE_SYS_PRCTL_H * (P) HAVE_SYS_PRCTL_H
* The possible cases are: * The possible cases are:
* none: setuid() normally * none: setuid() normally
...@@ -116,16 +116,9 @@ static int dfd[2] = { -1, -1 }; ...@@ -116,16 +116,9 @@ static int dfd[2] = { -1, -1 };
static isc_boolean_t non_root = ISC_FALSE; static isc_boolean_t non_root = ISC_FALSE;
static isc_boolean_t non_root_caps = ISC_FALSE; static isc_boolean_t non_root_caps = ISC_FALSE;
#if defined(HAVE_CAPSET)
#undef _POSIX_SOURCE
#ifdef HAVE_SYS_CAPABILITY_H #ifdef HAVE_SYS_CAPABILITY_H
#include <sys/capability.h> #include <sys/capability.h>
#else #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 * 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 * 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); ...@@ -133,9 +126,15 @@ int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
* and <string.h>) on 2.3 kernels. * and <string.h>) on 2.3 kernels.
*/ */
#define _LINUX_FS_H #define _LINUX_FS_H
#include <linux/capability.h>
#include <sys/syscall.h> /* Required for syscall(). */ #include <syscall.h>
#include <linux/capability.h> /* Required for _LINUX_CAPABILITY_VERSION. */ #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 #ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h> /* Required for prctl(). */ #include <sys/prctl.h> /* Required for prctl(). */
...@@ -152,23 +151,24 @@ int capset(cap_user_header_t hdrp, const cap_user_data_t datap); ...@@ -152,23 +151,24 @@ int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
#endif /* HAVE_SYS_PRCTL_H */ #endif /* HAVE_SYS_PRCTL_H */
#ifndef SYS_capset #ifdef HAVE_LIBCAP
#ifndef __NR_capset #define SETCAPS_FUNC "cap_set_proc "
#include <asm/unistd.h> /* Slackware 4.0 needs this. */ #else
#endif typedef unsigned int cap_t;
#define SYS_capset __NR_capset #define SETCAPS_FUNC "syscall(capset) "
#endif #endif /* HAVE_LIBCAP */
#endif
static void static void
linux_setcaps(unsigned int caps) { linux_setcaps(cap_t caps) {
#ifndef HAVE_LIBCAP
struct __user_cap_header_struct caphead; struct __user_cap_header_struct caphead;
struct __user_cap_data_struct cap; struct __user_cap_data_struct cap;
#endif
char strbuf[ISC_STRERRORSIZE]; char strbuf[ISC_STRERRORSIZE];
if ((getuid() != 0 && !non_root_caps) || non_root) if ((getuid() != 0 && !non_root_caps) || non_root)
return; return;
#ifndef HAVE_LIBCAP
memset(&caphead, 0, sizeof(caphead)); memset(&caphead, 0, sizeof(caphead));
caphead.version = _LINUX_CAPABILITY_VERSION; caphead.version = _LINUX_CAPABILITY_VERSION;
caphead.pid = 0; caphead.pid = 0;
...@@ -176,46 +176,74 @@ linux_setcaps(unsigned int caps) { ...@@ -176,46 +176,74 @@ linux_setcaps(unsigned int caps) {
cap.effective = caps; cap.effective = caps;
cap.permitted = caps; cap.permitted = caps;
cap.inheritable = 0; cap.inheritable = 0;
#ifdef HAVE_CAPSET #endif
if (capset(&caphead, &cap) < 0 ) { #ifdef HAVE_LIBCAP
isc__strerror(errno, strbuf, sizeof(strbuf)); if (cap_set_proc(caps) < 0) {
ns_main_earlyfatal("capset failed: %s:"
" please ensure that the capset kernel"
" module is loaded. see insmod(8)",
strbuf);
}
#else #else
if (syscall(SYS_capset, &caphead, &cap) < 0) { if (syscall(SYS_capset, &caphead, &cap) < 0) {
#endif
isc__strerror(errno, strbuf, sizeof(strbuf)); 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" " please ensure that the capset kernel"
" module is loaded. see insmod(8)", " module is loaded. see insmod(8)",
strbuf); 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 static void
linux_initialprivs(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. * We don't need most privileges, so we drop them right away.
* Later on linux_minprivs() will be called, which will drop our * Later on linux_minprivs() will be called, which will drop our
* capabilities to the minimum needed to run the server. * capabilities to the minimum needed to run the server.
*/ */
INIT_CAP;
caps = 0;
/* /*
* We need to be able to bind() to privileged ports, notably port 53! * 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. * We need chroot() initially too.
*/ */
caps |= (1 << CAP_SYS_CHROOT); SET_CAP(CAP_SYS_CHROOT);
#if defined(HAVE_SYS_PRCTL_H) || !defined(HAVE_LINUXTHREADS) #if defined(HAVE_SYS_PRCTL_H) || !defined(HAVE_LINUXTHREADS)
/* /*
...@@ -224,19 +252,19 @@ linux_initialprivs(void) { ...@@ -224,19 +252,19 @@ linux_initialprivs(void) {
* tried) or we're not using threads. If either of these is * tried) or we're not using threads. If either of these is
* true, we want the setuid capability. * true, we want the setuid capability.
*/ */
caps |= (1 << CAP_SETUID); SET_CAP(CAP_SETUID);
#endif #endif
/* /*
* Since we call initgroups, we need this. * 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 * Without this, we run into problems reading a configuration file
* owned by a non-root user and non-world-readable on startup. * 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 * XXX We might want to add CAP_SYS_RESOURCE, though it's not
...@@ -245,15 +273,21 @@ linux_initialprivs(void) { ...@@ -245,15 +273,21 @@ linux_initialprivs(void) {
* of files, the stack size, data size, and core dump size to * of files, the stack size, data size, and core dump size to
* support named.conf options, this is now being added to test. * support named.conf options, this is now being added to test.
*/ */
caps |= (1 << CAP_SYS_RESOURCE); SET_CAP(CAP_SYS_RESOURCE);
linux_setcaps(caps); linux_setcaps(caps);
} }
static void static void
linux_minprivs(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 * Drop all privileges except the ability to bind() to privileged
* ports. * ports.
...@@ -262,8 +296,7 @@ linux_minprivs(void) { ...@@ -262,8 +296,7 @@ linux_minprivs(void) {
* chroot() could be used to escape from the chrooted area. * chroot() could be used to escape from the chrooted area.
*/ */
caps = 0; SET_CAP(CAP_NET_BIND_SERVICE);
caps |= (1 << CAP_NET_BIND_SERVICE);
/* /*
* XXX We might want to add CAP_SYS_RESOURCE, though it's not * XXX We might want to add CAP_SYS_RESOURCE, though it's not
...@@ -272,7 +305,7 @@ linux_minprivs(void) { ...@@ -272,7 +305,7 @@ linux_minprivs(void) {
* of files, the stack size, data size, and core dump size to * of files, the stack size, data size, and core dump size to
* support named.conf options, this is now being added to test. * support named.conf options, this is now being added to test.
*/ */
caps |= (1 << CAP_SYS_RESOURCE); SET_CAP(CAP_SYS_RESOURCE);
linux_setcaps(caps); linux_setcaps(caps);
} }
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id: config.h.in,v 1.98 2008/04/28 23:43:24 marka Exp $ */ /* $Id: config.h.in,v 1.99 2008/05/06 01:30:26 each Exp $ */
/*! \file */ /*! \file */
...@@ -160,9 +160,6 @@ int sigwait(const unsigned int *set, int *sig); ...@@ -160,9 +160,6 @@ int sigwait(const unsigned int *set, int *sig);
/* Define to enable "rrset-order fixed" syntax. */ /* Define to enable "rrset-order fixed" syntax. */
#undef DNS_RDATASET_FIXED #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. */ /* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H #undef HAVE_DLFCN_H
...@@ -181,6 +178,9 @@ int sigwait(const unsigned int *set, int *sig); ...@@ -181,6 +178,9 @@ int sigwait(const unsigned int *set, int *sig);
/* Define to 1 if you have the `c' library (-lc). */ /* Define to 1 if you have the `c' library (-lc). */
#undef HAVE_LIBC #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). */ /* Define to 1 if you have the `c_r' library (-lc_r). */
#undef HAVE_LIBC_R #undef HAVE_LIBC_R
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
# #
# $Id: configure,v 1.427 2008/04/28 23:43:24 marka Exp $ # $Id: configure,v 1.428 2008/05/06 01:31:11 each Exp $
# #
# Portions Copyright (C) 1996-2001 Nominum, Inc. # Portions Copyright (C) 1996-2001 Nominum, Inc.
# #
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# From configure.in Revision: 1.442 . # From configure.in Revision: 1.443 .
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61. # Generated by GNU Autoconf 2.61.
# #
...@@ -27592,36 +27592,19 @@ fi ...@@ -27592,36 +27592,19 @@ fi
done done
for ac_func in capset { echo "$as_me:$LINENO: checking for cap_set_proc in -lcap" >&5
do echo $ECHO_N "checking for cap_set_proc in -lcap... $ECHO_C" >&6; }
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` if test "${ac_cv_lib_cap_cap_set_proc+set}" = set; then
{ 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 $ECHO_N "(cached) $ECHO_C" >&6 echo $ECHO_N "(cached) $ECHO_C" >&6
else else
cat >conftest.$ac_ext <<_ACEOF ac_check_lib_save_LIBS=$LIBS
LIBS="-lcap $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */ /* confdefs.h. */
_ACEOF _ACEOF
cat confdefs.h >>conftest.$ac_ext cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */ /* 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. /* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC Use char because int might match the return type of a GCC
...@@ -27629,18 +27612,11 @@ cat >>conftest.$ac_ext <<_ACEOF ...@@ -27629,18 +27612,11 @@ cat >>conftest.$ac_ext <<_ACEOF
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
#endif #endif
char $ac_func (); char cap_set_proc ();
/* 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
int int
main () main ()
{ {
return $ac_func (); return cap_set_proc ();
; ;
return 0; return 0;
} }
...@@ -27663,27 +27639,28 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ...@@ -27663,27 +27639,28 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
test ! -s conftest.err test ! -s conftest.err
} && test -s conftest$ac_exeext && } && test -s conftest$ac_exeext &&
$as_test_x conftest$ac_exeext; then $as_test_x conftest$ac_exeext; then
eval "$as_ac_var=yes" ac_cv_lib_cap_cap_set_proc=yes
else else
echo "$as_me: failed program was:" >&5 echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5 sed 's/^/| /' conftest.$ac_ext >&5
eval "$as_ac_var=no" ac_cv_lib_cap_cap_set_proc=no
fi fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi fi
ac_res=`eval echo '${'$as_ac_var'}'` { echo "$as_me:$LINENO: result: $ac_cv_lib_cap_cap_set_proc" >&5
{ echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_cv_lib_cap_cap_set_proc" >&6; }
echo "${ECHO_T}$ac_res" >&6; } if test $ac_cv_lib_cap_cap_set_proc = yes; then
if test `eval echo '${'$as_ac_var'}'` = yes; then
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 #define HAVE_LIBCAP 1
_ACEOF _ACEOF
LIBS="-lcap $LIBS"
fi fi
done
;; ;;
no) no)
......
...@@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl ...@@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl
esyscmd([sed "s/^/# /" COPYRIGHT])dnl esyscmd([sed "s/^/# /" COPYRIGHT])dnl
AC_DIVERT_POP()dnl AC_DIVERT_POP()dnl
AC_REVISION($Revision: 1.442 $) AC_REVISION($Revision: 1.443 $)
AC_INIT(lib/dns/name.c) AC_INIT(lib/dns/name.c)
AC_PREREQ(2.59) AC_PREREQ(2.59)
...@@ -1891,7 +1891,7 @@ AC_ARG_ENABLE(linux-caps, ...@@ -1891,7 +1891,7 @@ AC_ARG_ENABLE(linux-caps,
case "$enable_linux_caps" in case "$enable_linux_caps" in
yes|'') yes|'')
AC_CHECK_HEADERS(linux/capability.h sys/capability.h) AC_CHECK_HEADERS(linux/capability.h sys/capability.h)
AC_CHECK_FUNCS(capset) AC_CHECK_LIB(cap, cap_set_proc)
;; ;;
no) no)
;; ;;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment