(struct database_dyn): Add propagate field.
[kopensolaris-gnu/glibc.git] / nscd / selinux.c
index 91c1442..f123d68 100644 (file)
@@ -1,5 +1,5 @@
 /* SELinux access controls for nscd.
 /* SELinux access controls for nscd.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
 
    This file is part of the GNU C Library.
    Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <syslog.h>
 #include <stdio.h>
 #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 <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"
 #endif
 
 #include "dbg_log.h"
@@ -114,11 +116,28 @@ static int audit_fd = -1;
 static void
 log_callback (const char *fmt, ...)
 {
 static void
 log_callback (const char *fmt, ...)
 {
-  va_list ap;
+  if (audit_fd >= 0)
+    {
+      va_list ap;
+      va_start (ap, fmt);
+
+      char *buf;
+      int e = vasprintf (&buf, fmt, ap);
+      if (e < 0)
+       {
+         buf = alloca (BUFSIZ);
+         vsnprintf (buf, BUFSIZ, fmt, ap);
+       }
+
+      /* FIXME: need to attribute this to real user, using getuid for now */
+      audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
+                                 NULL, getuid ());
 
 
-  va_start (ap, fmt);
-  audit_log_avc (audit_fd, AUDIT_USER_AVC, fmt, ap);
-  va_end (ap);
+      if (e >= 0)
+       free (buf);
+
+      va_end (ap);
+    }
 }
 
 /* Initialize the connection to the audit system */
 }
 
 /* Initialize the connection to the audit system */
@@ -126,9 +145,95 @@ static void
 audit_init (void)
 {
   audit_fd = audit_open ();
 audit_init (void)
 {
   audit_fd = audit_open ();
-  if (audit_fd < 0)
-     dbg_log (_("Failed opening connection to the audit subsystem"));
+  if (audit_fd < 0
+      /* If kernel doesn't support audit, bail out */
+      && 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
 #endif /* HAVE_LIBAUDIT */
 
 /* Determine if we are running on an SELinux kernel. Set selinux_enabled