]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
Switch to libcap-ng, avoid linking libdbus against libcap[-ng]
authorColin Walters <walters@verbum.org>
Thu, 28 Jan 2010 00:38:44 +0000 (19:38 -0500)
committerColin Walters <walters@verbum.org>
Thu, 28 Jan 2010 22:01:24 +0000 (17:01 -0500)
(Commit message written by Colin Walters <walters@verbum.org>)

A current Fedora goal is to convert projects to libcap-ng which
more easily allows dropping Linux capabilities.  For software
which also links to libdbus, it's problematic to link against
libcap as well.

Though really, libdbus should have never linked against libcap
in the first place, which is another thing this patch changes
by moving the libcap-using bits out of dbus/ and into bus/.

https://bugzilla.redhat.com/show_bug.cgi?id=518541

bus/selinux.c
bus/selinux.h
configure.in
dbus/dbus-sysdeps-util-unix.c
dbus/dbus-sysdeps.h

index df9a00b1c9825fb8d0418740bcc712c32a9ce90e..456723ac58458ca863003bec6c6c1466b1e12e48 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include <dbus/dbus-internals.h>
 #include <dbus/dbus-string.h>
+#include <dbus/dbus-userdb.h>
 #include "selinux.h"
 #include "services.h"
 #include "policy.h"
@@ -44,7 +45,9 @@
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <grp.h>
 #ifdef HAVE_LIBAUDIT
+#include <cap-ng.h>
 #include <libaudit.h>
 #endif /* HAVE_LIBAUDIT */
 #endif /* HAVE_SELINUX */
@@ -143,13 +146,17 @@ log_callback (const char *fmt, ...)
 #ifdef HAVE_LIBAUDIT
   if (audit_fd >= 0)
   {
-    char buf[PATH_MAX*2];
+    capng_get_caps_process();
+    if (capng_have_capability(CAPNG_EFFECTIVE, CAP_AUDIT_WRITE))
+    {
+      char buf[PATH_MAX*2];
     
-    /* FIXME: need to change this to show real user */
-    vsnprintf(buf, sizeof(buf), fmt, ap);
-    audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
+      /* FIXME: need to change this to show real user */
+      vsnprintf(buf, sizeof(buf), fmt, ap);
+      audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
                                NULL, getuid());
-    return;
+      return;
+    }
   }
 #endif /* HAVE_LIBAUDIT */
   
@@ -1010,3 +1017,104 @@ bus_selinux_shutdown (void)
 #endif /* HAVE_SELINUX */
 }
 
+/**
+ * Changes the user and group the bus is running as.
+ *
+ * @param user the user to become
+ * @param error return location for errors
+ * @returns #FALSE on failure
+ */
+dbus_bool_t
+_dbus_change_to_daemon_user  (const char    *user,
+                              DBusError     *error)
+{
+  dbus_uid_t uid;
+  dbus_gid_t gid;
+  DBusString u;
+
+  _dbus_string_init_const (&u, user);
+
+  if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "User '%s' does not appear to exist?",
+                      user);
+      return FALSE;
+    }
+
+#ifdef HAVE_LIBAUDIT
+  /* If we were root */
+  if (_dbus_geteuid () == 0)
+    {
+      int rc;
+
+      capng_clear (CAPNG_SELECT_BOTH);
+      capng_update (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+                    CAP_AUDIT_WRITE);
+      rc = capng_change_id (uid, gid, 0);
+      if (rc)
+        {
+          switch (rc) {
+            default:
+              dbus_set_error (error, DBUS_ERROR_FAILED,
+                              "Failed to drop capabilities: %s\n",
+                              _dbus_strerror (errno));
+              break;
+            case -4:
+              dbus_set_error (error, _dbus_error_from_errno (errno),
+                              "Failed to set GID to %lu: %s", gid,
+                              _dbus_strerror (errno));
+              break;
+            case -5:
+              _dbus_warn ("Failed to drop supplementary groups: %s\n",
+                          _dbus_strerror (errno));
+              break;
+            case -6:
+              dbus_set_error (error, _dbus_error_from_errno (errno),
+                              "Failed to set UID to %lu: %s", uid,
+                              _dbus_strerror (errno));
+              break;
+            case -7:
+              dbus_set_error (error, _dbus_error_from_errno (errno),
+                              "Failed to unset keep-capabilities: %s\n",
+                              _dbus_strerror (errno));
+              break;
+          }
+          return FALSE;
+        }
+    }
+#else
+  /* setgroups() only works if we are a privileged process,
+   * so we don't return error on failure; the only possible
+   * failure is that we don't have perms to do it.
+   *
+   * not sure this is right, maybe if setuid()
+   * is going to work then setgroups() should also work.
+   */
+  if (setgroups (0, NULL) < 0)
+    _dbus_warn ("Failed to drop supplementary groups: %s\n",
+                _dbus_strerror (errno));
+
+  /* Set GID first, or the setuid may remove our permission
+   * to change the GID
+   */
+  if (setgid (gid) < 0)
+    {
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "Failed to set GID to %lu: %s", gid,
+                      _dbus_strerror (errno));
+      return FALSE;
+    }
+
+  if (setuid (uid) < 0)
+    {
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "Failed to set UID to %lu: %s", uid,
+                      _dbus_strerror (errno));
+      return FALSE;
+    }
+#endif /* !HAVE_LIBAUDIT */
+
+ return TRUE;
+}
+
index 3bab36de48ec16ebcef263e5713b7a5b63838a72..f208fbebcfae395246403bd66bd3c94175779ae3 100644 (file)
@@ -68,5 +68,7 @@ BusSELinuxID* bus_selinux_init_connection_id (DBusConnection *connection,
 
 
 void bus_selinux_audit_init(void);
+dbus_bool_t _dbus_change_to_daemon_user (const char *user,
+                                         DBusError  *error);
 
 #endif /* BUS_SELINUX_H */
index 7feb1a93c9234dcfd42cff09383149181270d568..cb16eec4af30ab40d186c712837e767ded4ab102 100644 (file)
@@ -851,7 +851,7 @@ else
     AC_CHECK_LIB(audit, audit_log_user_avc_message, 
                  have_libaudit=yes, have_libaudit=no)
     if test x$have_libaudit = xyes ; then
-        AC_CHECK_LIB(cap, cap_set_proc, 
+        AC_CHECK_LIB(cap-ng, capng_clear,
                  have_libaudit=yes, have_libaudit=no)
     fi
 fi
@@ -859,8 +859,7 @@ fi
 AM_CONDITIONAL(HAVE_LIBAUDIT, test x$have_libaudit = xyes)
 
 if test x$have_libaudit = xyes ; then
-    SELINUX_LIBS="$SELINUX_LIBS -laudit"
-    LIBS="-lcap $LIBS"
+    SELINUX_LIBS="$SELINUX_LIBS -laudit -lcap-ng"
     AC_DEFINE(HAVE_LIBAUDIT,1,[audit daemon SELinux support])
 fi
 
index 83f74fe22a347d1f9558396eb5b6b7d8a45ebbf9..27cdbb014f727a2a004d8422819dd81121afaeda 100644 (file)
 #include <dirent.h>
 #include <sys/un.h>
 #include <syslog.h>
-#ifdef HAVE_LIBAUDIT
-#include <sys/prctl.h>
-#include <sys/capability.h>
-#include <libaudit.h>
-#endif /* HAVE_LIBAUDIT */
 
 #ifdef HAVE_SYS_SYSLIMITS_H
 #include <sys/syslimits.h>
@@ -308,155 +303,6 @@ _dbus_verify_daemon_user (const char *user)
   return _dbus_get_user_id_and_primary_group (&u, NULL, NULL);
 }
 
-/**
- * Changes the user and group the bus is running as.
- *
- * @param user the user to become
- * @param error return location for errors
- * @returns #FALSE on failure
- */
-dbus_bool_t
-_dbus_change_to_daemon_user  (const char    *user,
-                              DBusError     *error)
-{
-  dbus_uid_t uid;
-  dbus_gid_t gid;
-  DBusString u;
-#ifdef HAVE_LIBAUDIT
-  dbus_bool_t we_were_root;
-  cap_t new_caps;
-#endif
-  
-  _dbus_string_init_const (&u, user);
-  
-  if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "User '%s' does not appear to exist?",
-                      user);
-      return FALSE;
-    }
-  
-#ifdef HAVE_LIBAUDIT
-  we_were_root = _dbus_geteuid () == 0;
-  new_caps = NULL;
-  /* have a tmp set of caps that we use to transition to the usr/grp dbus should
-   * run as ... doesn't really help. But keeps people happy.
-   */
-    
-  if (we_were_root)
-    {
-      cap_value_t new_cap_list[] = { CAP_AUDIT_WRITE };
-      cap_value_t tmp_cap_list[] = { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
-      cap_t tmp_caps = cap_init();
-        
-      if (!tmp_caps || !(new_caps = cap_init ()))
-        {
-          dbus_set_error (error, DBUS_ERROR_FAILED,
-                          "Failed to initialize drop of capabilities: %s\n",
-                          _dbus_strerror (errno));
-
-          if (tmp_caps)
-            cap_free (tmp_caps);
-
-          return FALSE;
-        }
-
-      /* assume these work... */
-      cap_set_flag (new_caps, CAP_PERMITTED, 1, new_cap_list, CAP_SET);
-      cap_set_flag (new_caps, CAP_EFFECTIVE, 1, new_cap_list, CAP_SET);
-      cap_set_flag (tmp_caps, CAP_PERMITTED, 3, tmp_cap_list, CAP_SET);
-      cap_set_flag (tmp_caps, CAP_EFFECTIVE, 3, tmp_cap_list, CAP_SET);
-      
-      if (prctl (PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
-        {
-          dbus_set_error (error, _dbus_error_from_errno (errno),
-                          "Failed to set keep-capabilities: %s\n",
-                          _dbus_strerror (errno));
-          cap_free (tmp_caps);
-          goto fail;
-        }
-        
-      if (cap_set_proc (tmp_caps) == -1)
-        {
-          dbus_set_error (error, DBUS_ERROR_FAILED,
-                          "Failed to drop capabilities: %s\n",
-                          _dbus_strerror (errno));
-          cap_free (tmp_caps);
-          goto fail;
-        }
-      cap_free (tmp_caps);
-    }
-#endif /* HAVE_LIBAUDIT */
-  
-  /* setgroups() only works if we are a privileged process,
-   * so we don't return error on failure; the only possible
-   * failure is that we don't have perms to do it.
-   *
-   * not sure this is right, maybe if setuid()
-   * is going to work then setgroups() should also work.
-   */
-  if (setgroups (0, NULL) < 0)
-    _dbus_warn ("Failed to drop supplementary groups: %s\n",
-                _dbus_strerror (errno));
-  
-  /* Set GID first, or the setuid may remove our permission
-   * to change the GID
-   */
-  if (setgid (gid) < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to set GID to %lu: %s", gid,
-                      _dbus_strerror (errno));
-      goto fail;
-    }
-  
-  if (setuid (uid) < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to set UID to %lu: %s", uid,
-                      _dbus_strerror (errno));
-      goto fail;
-    }
-  
-#ifdef HAVE_LIBAUDIT
-  if (we_were_root)
-    {
-      if (cap_set_proc (new_caps))
-        {
-          dbus_set_error (error, DBUS_ERROR_FAILED,
-                          "Failed to drop capabilities: %s\n",
-                          _dbus_strerror (errno));
-          goto fail;
-        }
-      cap_free (new_caps);
-
-      /* should always work, if it did above */      
-      if (prctl (PR_SET_KEEPCAPS, 0, 0, 0, 0) == -1)
-        {
-          dbus_set_error (error, _dbus_error_from_errno (errno),
-                          "Failed to unset keep-capabilities: %s\n",
-                          _dbus_strerror (errno));
-          return FALSE;
-        }
-    }
-#endif
-
- return TRUE;
-
- fail:
-#ifdef HAVE_LIBAUDIT
- if (!we_were_root)
-   {
-     /* should always work, if it did above */
-     prctl (PR_SET_KEEPCAPS, 0, 0, 0, 0);
-     cap_free (new_caps);
-   }
-#endif
-
- return FALSE;
-}
-
 void 
 _dbus_init_system_log (void)
 {
index 30e7dff2c21264e761008f03b5bc9eabbbe9047b..b154f016f52bd001f46d0e96e19de8f3354044b1 100644 (file)
@@ -418,8 +418,6 @@ dbus_bool_t _dbus_become_daemon   (const DBusString *pidfile,
                                    dbus_bool_t       keep_umask);
 
 dbus_bool_t _dbus_verify_daemon_user    (const char *user);
-dbus_bool_t _dbus_change_to_daemon_user (const char *user,
-                                         DBusError  *error);
 
 dbus_bool_t _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
                                               DBusPipe         *print_pid_pipe,