aboutsummaryrefslogtreecommitdiff
path: root/nscd
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2006-04-26 16:29:29 +0000
committerUlrich Drepper <drepper@redhat.com>2006-04-26 16:29:29 +0000
commit1f063dcadb802c57759e2ca2bf9c08e108bb3d70 (patch)
tree9405434ef42f90e6a2591ac60e36aacb8454edb5 /nscd
parentcf86bbe6da1d90170e0ee09b5baae15332c917f2 (diff)
downloadglibc-1f063dcadb802c57759e2ca2bf9c08e108bb3d70.zip
glibc-1f063dcadb802c57759e2ca2bf9c08e108bb3d70.tar.gz
glibc-1f063dcadb802c57759e2ca2bf9c08e108bb3d70.tar.bz2
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/Makefile5
-rw-r--r--nscd/connections.c10
-rw-r--r--nscd/selinux.c87
-rw-r--r--nscd/selinux.h12
4 files changed, 111 insertions, 3 deletions
diff --git a/nscd/Makefile b/nscd/Makefile
index 0b35964..9c98018 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 d975b18..b24e7fb 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 c59251f..f123d68 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 b9eb053..9ce0628 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