diff options
| -rw-r--r-- | ChangeLog | 11 | ||||
| -rw-r--r-- | bus/bus.c | 10 | ||||
| -rw-r--r-- | bus/selinux.c | 54 | ||||
| -rw-r--r-- | configure.in | 22 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps-util-unix.c | 104 | ||||
| -rw-r--r-- | dbus/dbus-transport.c | 4 | 
6 files changed, 192 insertions, 13 deletions
| @@ -1,3 +1,14 @@ +2007-06-13  Havoc Pennington  <hp@redhat.com> + +	* configure.ac, bus/selinux.c, dbus/dbus-sysdeps-unix-util.c: add +	libaudit support, no clue what this means really but now we have +	it. Patches from Fedora package. + +	* bus/bus.c (bus_context_new): move selinux initialization after +	changing to daemon user, patch from Fedora package + +	* dbus/dbus-transport.c (auth_via_unix_user_function): fix a typo +  2007-06-12  Havoc Pennington  <hp@redhat.com>  	* dbus/dbus-message.c (dbus_message_iter_open_container): improve @@ -739,11 +739,6 @@ bus_context_new (const DBusString *config_file,        _dbus_string_free (&pid);      } -  if (!bus_selinux_full_init ()) -    { -      _dbus_warn ("SELinux initialization failed\n"); -    } -    if (!process_config_postinit (context, parser, error))      {        _DBUS_ASSERT_ERROR_IS_SET (error); @@ -767,6 +762,11 @@ bus_context_new (const DBusString *config_file,  	  goto failed;  	}      } + +  if (!bus_selinux_full_init ()) +    { +      _dbus_warn ("SELinux initialization failed\n"); +    }    dbus_server_free_data_slot (&server_data_slot); diff --git a/bus/selinux.c b/bus/selinux.c index e5f26da2..c2138380 100644 --- a/bus/selinux.c +++ b/bus/selinux.c @@ -38,6 +38,9 @@  #include <selinux/flask.h>  #include <signal.h>  #include <stdarg.h> +#ifdef HAVE_LIBAUDIT +#include <libaudit.h> +#endif /* HAVE_LIBAUDIT */  #endif /* HAVE_SELINUX */  #define BUS_SID_FROM_SELINUX(sid)  ((BusSELinuxID*) (sid)) @@ -100,11 +103,50 @@ static const struct avc_lock_callback lock_cb =   * @param variable argument list   */  #ifdef HAVE_SELINUX + +#ifdef HAVE_LIBAUDIT +static int audit_fd = -1; +#endif + +static void +audit_init(void) +{ +#ifdef HAVE_LIBAUDIT   +  audit_fd = audit_open (); + +  if (audit_fd < 0) +    { +      /* If kernel doesn't support audit, bail out */ +      if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) +        return; +      /* If user bus, bail out */ +      if (errno == EPERM && getuid() != 0) +        return; +      _dbus_warn ("Failed opening connection to the audit subsystem"); +    } +#endif /* HAVE_LIBAUDIT */ +} +  static void   log_callback (const char *fmt, ...)   {    va_list ap; +    va_start(ap, fmt); + +#ifdef HAVE_LIBAUDIT +  if (audit_fd >= 0) +  { +    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, +                               NULL, getuid()); +    return; +  } +#endif /* HAVE_LIBAUDIT */ +      vsyslog (LOG_INFO, fmt, ap);    va_end(ap);  } @@ -303,6 +345,8 @@ bus_selinux_full_init (void)    freecon (bus_context); +  audit_init (); +    return TRUE;  #else    return TRUE; @@ -925,12 +969,18 @@ bus_selinux_shutdown (void)      {        sidput (bus_sid);        bus_sid = SECSID_WILD; -       +  #ifdef DBUS_ENABLE_VERBOSE_MODE -      bus_avc_print_stats (); +  +      if (_dbus_is_verbose())  +        bus_avc_print_stats (); +   #endif /* DBUS_ENABLE_VERBOSE_MODE */        avc_destroy (); +#ifdef HAVE_LIBAUDIT +      audit_close (audit_fd); +#endif /* HAVE_LIBAUDIT */      }  #endif /* HAVE_SELINUX */  } diff --git a/configure.in b/configure.in index 4836342f..4bdc535d 100644 --- a/configure.in +++ b/configure.in @@ -56,6 +56,7 @@ AC_ARG_ENABLE(doxygen-docs, AS_HELP_STRING([--enable-doxygen-docs],[build DOXYGE  AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov],[compile with coverage profiling instrumentation (gcc only)]),enable_gcov=$enableval,enable_gcov=no)  AC_ARG_ENABLE(abstract-sockets, AS_HELP_STRING([--enable-abstract-sockets],[use abstract socket namespace (linux only)]),enable_abstract_sockets=$enableval,enable_abstract_sockets=auto)  AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto) +AC_ARG_ENABLE(libaudit,          [  --enable-libaudit    build audit daemon support for SELinux],enable_libaudit=$enableval,enable_libaudit=auto)  AC_ARG_ENABLE(dnotify, AS_HELP_STRING([--enable-dnotify],[build with dnotify support (linux only)]),enable_dnotify=$enableval,enable_dnotify=auto)  AC_ARG_ENABLE(kqueue, AS_HELP_STRING([--enable-kqueue],[build with kqueue support]),enable_kqueue=$enableval,enable_kqueue=auto)  AC_ARG_ENABLE(console-owner-file, AS_HELP_STRING([--enable-console-owner-file],[enable console owner file]),enable_console_owner_file=$enableval,enable_console_owner_file=auto) @@ -904,6 +905,27 @@ fi  AM_CONDITIONAL(HAVE_CONSOLE_OWNER_FILE, test x$have_console_owner_file = xyes) +# libaudit detection +if test x$enable_libaudit = xno ; then +    have_libaudit=no; +else +    # See if we have audit daemon & capabilities library +    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,  +                 have_libaudit=yes, have_libaudit=no) +    fi +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" +    AC_DEFINE(HAVE_LIBAUDIT,1,[audit daemon SELinux support]) +fi +  #### Set up final flags  DBUS_CLIENT_CFLAGS=  DBUS_CLIENT_LIBS="$THREAD_LIBS" diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c index 339b8f96..e81c752e 100644 --- a/dbus/dbus-sysdeps-util-unix.c +++ b/dbus/dbus-sysdeps-util-unix.c @@ -43,6 +43,11 @@  #include <sys/socket.h>  #include <dirent.h>  #include <sys/un.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> @@ -273,7 +278,11 @@ _dbus_change_to_daemon_user  (const char    *user,    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)) @@ -284,6 +293,58 @@ _dbus_change_to_daemon_user  (const char    *user,        return FALSE;      } +#ifdef HAVE_LIBAUDIT +  we_were_root = _dbus_getuid () == 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. @@ -303,7 +364,7 @@ _dbus_change_to_daemon_user  (const char    *user,        dbus_set_error (error, _dbus_error_from_errno (errno),                        "Failed to set GID to %lu: %s", gid,                        _dbus_strerror (errno)); -      return FALSE; +      goto fail;      }    if (setuid (uid) < 0) @@ -311,10 +372,45 @@ _dbus_change_to_daemon_user  (const char    *user,        dbus_set_error (error, _dbus_error_from_errno (errno),                        "Failed to set UID to %lu: %s", uid,                        _dbus_strerror (errno)); -      return FALSE; +      goto fail;      } -  return TRUE; +#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;  }  /** Installs a UNIX signal handler diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index d738cc0c..0e27dd13 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -516,9 +516,9 @@ auth_via_unix_user_function (DBusTransport *transport)    connection = transport->connection;    unix_user_function = transport->unix_user_function;    unix_user_data = transport->unix_user_data; -  uid = _dbus_credentials_get_unix_uid (auth_identity), +  uid = _dbus_credentials_get_unix_uid (auth_identity); -    _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); +  _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);    _dbus_connection_unlock (connection);    allow = (* unix_user_function) (connection, | 
