diff --git a/ChangeLog b/ChangeLog index 3a2d0a47ff..3980c3c59c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2006-04-26 James Antill + Ulrich Drepper + + * config.make.in: Add have-libcap. + * configure.in: Check for libcap. + * nscd/Makefile (selinux-LIBS): Add -lcap if possible. + * nscd/connections.c (finish_drop_privileges): When libcap is available + call preserve_capabilities and install_real_capabilities. + * nscd/selinux.c: Define preserve_capabilities and + install_real_capabilities. + * nscd/selinux.h: Declare preserve_capabilities and + install_real_capabilities. + 2006-04-26 Ulrich Drepper * locale/iso-4217.def: Update. diff --git a/config.make.in b/config.make.in index 292dea667b..bc8998cd1f 100644 --- a/config.make.in +++ b/config.make.in @@ -61,6 +61,7 @@ have-fpie = @libc_cv_fpie@ have-ssp = @libc_cv_ssp@ have-selinux = @have_selinux@ have-libaudit = @have_libaudit@ +have-libcap = @have_libcap@ have-cc-with-libunwind = @libc_cv_cc_with_libunwind@ fno-unit-at-a-time = @fno_unit_at_a_time@ bind-now = @bindnow@ diff --git a/configure b/configure index 82188b299b..b9c8ee8c39 100755 --- a/configure +++ b/configure @@ -313,7 +313,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi bindnow force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os subdirs add_ons add_on_subdirs base_machine submachine sysnames sysdeps_add_ons INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP CXX CXXFLAGS ac_ct_CXX AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF SYSINCLUDES CXX_SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_cc_with_libunwind libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_z_relro libc_cv_Bgroup libc_cv_libgcc_s_suffix libc_cv_as_needed ASFLAGS_config libc_cv_z_combreloc libc_cv_z_execstack libc_cv_fpie fno_unit_at_a_time libc_cv_ssp libc_cv_have_initfini no_whole_archive exceptions LIBGD have_libaudit have_selinux EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir libc_cv_forced_unwind use_ldconfig ldd_rewrite_script elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi bindnow force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os subdirs add_ons add_on_subdirs base_machine submachine sysnames sysdeps_add_ons INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP CXX CXXFLAGS ac_ct_CXX AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF SYSINCLUDES CXX_SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_cc_with_libunwind libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_z_relro libc_cv_Bgroup libc_cv_libgcc_s_suffix libc_cv_as_needed ASFLAGS_config libc_cv_z_combreloc libc_cv_z_execstack libc_cv_fpie fno_unit_at_a_time libc_cv_ssp libc_cv_have_initfini no_whole_archive exceptions LIBGD have_libaudit have_libcap have_selinux EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir libc_cv_forced_unwind use_ldconfig ldd_rewrite_script elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -6831,6 +6831,86 @@ _ACEOF fi + + # See if we have the libcap library + echo "$as_me:$LINENO: checking for cap_init in -lcap" >&5 +echo $ECHO_N "checking for cap_init in -lcap... $ECHO_C" >&6 +if test "${ac_cv_lib_cap_cap_init+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + 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. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char cap_init (); +int +main () +{ +cap_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_cap_cap_init=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_cap_cap_init=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_cap_cap_init" >&5 +echo "${ECHO_T}$ac_cv_lib_cap_cap_init" >&6 +if test $ac_cv_lib_cap_cap_init = yes; then + have_libcap=yes +else + have_libcap=no +fi + + if test "x$have_libcap" = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBCAP 1 +_ACEOF + + fi + fi @@ -8423,6 +8503,7 @@ s,@no_whole_archive@,$no_whole_archive,;t t s,@exceptions@,$exceptions,;t t s,@LIBGD@,$LIBGD,;t t s,@have_libaudit@,$have_libaudit,;t t +s,@have_libcap@,$have_libcap,;t t s,@have_selinux@,$have_selinux,;t t s,@EGREP@,$EGREP,;t t s,@sizeof_long_double@,$sizeof_long_double,;t t diff --git a/configure.in b/configure.in index 83f09de805..79fa32ec2b 100644 --- a/configure.in +++ b/configure.in @@ -1982,6 +1982,13 @@ if test "x$have_selinux" = xyes; then AC_DEFINE(HAVE_LIBAUDIT, 1, [SELinux libaudit support]) fi AC_SUBST(have_libaudit) + + # See if we have the libcap library + AC_CHECK_LIB(cap, cap_init, have_libcap=yes, have_libcap=no) + if test "x$have_libcap" = xyes; then + AC_DEFINE(HAVE_LIBCAP, 1, [SELinux libcap support]) + fi + AC_SUBST(have_libcap) fi AC_SUBST(have_selinux) diff --git a/nscd/Makefile b/nscd/Makefile index 0b35964e7b..9c98018217 100644 --- a/nscd/Makefile +++ b/nscd/Makefile @@ -55,10 +55,13 @@ all-nscd-modules := $(nscd-modules) selinux ifeq (yes,$(have-selinux)) ifeq (yes,$(have-libaudit)) libaudit = -laudit +ifeq (yes,$(have-libcap)) +libcap = -lcap +endif endif nscd-modules += selinux -selinux-LIBS := -lselinux $(libaudit) +selinux-LIBS := -lselinux $(libaudit) $(libcap) # The configure.in check for libselinux and its headers did not use # $SYSINCLUDES. The directory specified by --with-headers usually diff --git a/nscd/connections.c b/nscd/connections.c index d975b1818f..b24e7fb527 100644 --- a/nscd/connections.c +++ b/nscd/connections.c @@ -1859,6 +1859,11 @@ begin_drop_privileges (void) static void finish_drop_privileges (void) { +#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP + /* We need to preserve the capabilities to connect to the audit daemon. */ + cap_t new_caps = preserve_capabilities (); +#endif + if (setgroups (server_ngroups, server_groups) == -1) { dbg_log (_("Failed to run nscd as user '%s'"), server_user); @@ -1878,4 +1883,9 @@ finish_drop_privileges (void) perror ("setuid"); exit (4); } + +#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP + /* Remove the temporary capabilities. */ + install_real_capabilities (new_caps); +#endif } diff --git a/nscd/selinux.c b/nscd/selinux.c index c59251f1b5..f123d68b93 100644 --- a/nscd/selinux.c +++ b/nscd/selinux.c @@ -28,12 +28,13 @@ #include #include #include +#include #include #include #include #include #ifdef HAVE_LIBAUDIT -#include +# include #endif #include "dbg_log.h" @@ -149,6 +150,90 @@ audit_init (void) && errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT) dbg_log (_("Failed opening connection to the audit subsystem: %m")); } + + +# ifdef HAVE_LIBCAP +static const cap_value_t new_cap_list[] = + { CAP_AUDIT_WRITE }; +# define nnew_cap_list (sizeof (new_cap_list) / sizeof (new_cap_list[0])) +static const cap_value_t tmp_cap_list[] = + { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID }; +# define ntmp_cap_list (sizeof (tmp_cap_list) / sizeof (tmp_cap_list[0])) + +cap_t +preserve_capabilities (void) +{ + if (getuid () != 0) + /* Not root, then we cannot preserve anything. */ + return NULL; + + if (prctl (PR_SET_KEEPCAPS, 1) == -1) + { + dbg_log (_("Failed to set keep-capabilities")); + error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed")); + /* NOTREACHED */ + } + + cap_t tmp_caps = cap_init (); + cap_t new_caps; + if (tmp_caps != NULL) + new_caps = cap_init (); + + if (tmp_caps == NULL || new_caps == NULL) + { + if (tmp_caps != NULL) + free_caps (tmp_caps); + + dbg_log (_("Failed to initialize drop of capabilities")); + error (EXIT_FAILURE, 0, _("cap_init failed")); + } + + /* There is no reason why these should not work. */ + cap_set_flag (new_caps, CAP_PERMITTED, nnew_cap_list, new_cap_list, CAP_SET); + cap_set_flag (new_caps, CAP_EFFECTIVE, nnew_cap_list, new_cap_list, CAP_SET); + + cap_set_flag (tmp_caps, CAP_PERMITTED, ntmp_cap_list, tmp_cap_list, CAP_SET); + cap_set_flag (tmp_caps, CAP_EFFECTIVE, ntmp_cap_list, tmp_cap_list, CAP_SET); + + int res = cap_set_proc (tmp_caps); + + cap_free (tmp_caps); + + if (__builtin_expect (res != 0, 0)) + { + cap_free (new_caps); + dbg_log (_("Failed to drop capabilities\n")); + error (EXIT_FAILURE, 0, _("cap_set_proc failed")); + } + + return new_caps; +} + +void +install_real_capabilities (cap_t new_caps) +{ + /* If we have no capabilities there is nothing to do here. */ + if (new_caps == NULL) + return; + + if (cap_set_proc (new_caps)) + { + cap_free (new_caps); + dbg_log (_("Failed to drop capabilities")); + error (EXIT_FAILURE, 0, _("cap_set_proc failed")); + /* NOTREACHED */ + } + + cap_free (new_caps); + + if (prctl (PR_SET_KEEPCAPS, 0) == -1) + { + dbg_log (_("Failed to unset keep-capabilities")); + error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed")); + /* NOTREACHED */ + } +} +# endif /* HAVE_LIBCAP */ #endif /* HAVE_LIBAUDIT */ /* Determine if we are running on an SELinux kernel. Set selinux_enabled diff --git a/nscd/selinux.h b/nscd/selinux.h index b9eb053aa0..9ce0628486 100644 --- a/nscd/selinux.h +++ b/nscd/selinux.h @@ -1,5 +1,5 @@ /* Header for nscd SELinux access controls. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Matthew Rickard , 2004. @@ -22,6 +22,9 @@ #define _SELINUX_H 1 #include "nscd.h" +#ifdef HAVE_LIBCAP +# include +#endif #ifdef HAVE_SELINUX /* Global variable to tell if the kernel has SELinux support. */ @@ -42,6 +45,13 @@ extern int nscd_request_avc_has_perm (int fd, request_type req); extern void nscd_avc_cache_stats (struct avc_cache_stats *cstats); /* Display statistics on AVC usage. */ extern void nscd_avc_print_stats (struct avc_cache_stats *cstats); + +# ifdef HAVE_LIBCAP +/* Preserve capabilities to connect to connnect to the audit daemon. */ +extern cap_t preserve_capabilities (void); +/* Install final capabilities. */ +extern void install_real_capabilities (cap_t new_caps); +# endif #else # define selinux_enabled 0 # define nscd_avc_init() (void) 0