mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 12:50:00 -04:00
Linux: use libcap for capability management if possible. [RT# 18026]
This commit is contained in:
parent
69ec1b7eb3
commit
0415ca35ad
5 changed files with 105 additions and 92 deletions
3
CHANGES
3
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]
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* 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 */
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* 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 */
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
61
configure
vendored
61
configure
vendored
|
|
@ -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.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.
|
||||
#
|
||||
|
|
@ -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.442 .
|
||||
# From configure.in Revision: 1.443 .
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.61.
|
||||
#
|
||||
|
|
@ -27592,36 +27592,19 @@ fi
|
|||
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
|
||||
|
|
@ -27629,18 +27612,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;
|
||||
}
|
||||
|
|
@ -27663,27 +27639,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)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl
|
|||
esyscmd([sed "s/^/# /" COPYRIGHT])dnl
|
||||
AC_DIVERT_POP()dnl
|
||||
|
||||
AC_REVISION($Revision: 1.442 $)
|
||||
AC_REVISION($Revision: 1.443 $)
|
||||
|
||||
AC_INIT(lib/dns/name.c)
|
||||
AC_PREREQ(2.59)
|
||||
|
|
@ -1891,7 +1891,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)
|
||||
;;
|
||||
|
|
|
|||
Loading…
Reference in a new issue