diff options
author | Ulrich Drepper <drepper@redhat.com> | 2006-04-26 16:29:29 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2006-04-26 16:29:29 +0000 |
commit | 1f063dcadb802c57759e2ca2bf9c08e108bb3d70 (patch) | |
tree | 9405434ef42f90e6a2591ac60e36aacb8454edb5 /nscd | |
parent | cf86bbe6da1d90170e0ee09b5baae15332c917f2 (diff) | |
download | glibc-1f063dcadb802c57759e2ca2bf9c08e108bb3d70.tar glibc-1f063dcadb802c57759e2ca2bf9c08e108bb3d70.tar.gz glibc-1f063dcadb802c57759e2ca2bf9c08e108bb3d70.tar.bz2 glibc-1f063dcadb802c57759e2ca2bf9c08e108bb3d70.zip |
2006-04-26 James Antill <james.antill@redhat.com>
Ulrich Drepper <drepper@redhat.com>
* 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.
Diffstat (limited to 'nscd')
-rw-r--r-- | nscd/Makefile | 5 | ||||
-rw-r--r-- | nscd/connections.c | 10 | ||||
-rw-r--r-- | nscd/selinux.c | 87 | ||||
-rw-r--r-- | nscd/selinux.h | 12 |
4 files changed, 111 insertions, 3 deletions
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 <stdlib.h> #include <syslog.h> #include <unistd.h> +#include <sys/prctl.h> #include <selinux/av_permissions.h> #include <selinux/avc.h> #include <selinux/flask.h> #include <selinux/selinux.h> #ifdef HAVE_LIBAUDIT -#include <libaudit.h> +# include <libaudit.h> #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 <mjricka@epoch.ncsc.mil>, 2004. @@ -22,6 +22,9 @@ #define _SELINUX_H 1 #include "nscd.h" +#ifdef HAVE_LIBCAP +# include <sys/capabilities.h> +#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 |