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
[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
......
......@@ -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)
;;
......
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