| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- |
| * audit.c - libaudit integration for SELinux and AppArmor |
| * |
| * Based on apparmor.c, selinux.c |
| * |
| * Copyright © 2014-2015 Canonical, Ltd. |
| * Copyright © 2015 Collabora Ltd. |
| * |
| * Licensed under the Academic Free License version 2.1 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #include <config.h> |
| #include "audit.h" |
| |
| #ifdef HAVE_ERRNO_H |
| #include <errno.h> |
| #endif |
| |
| #ifdef HAVE_LIBAUDIT |
| #include <cap-ng.h> |
| #include <libaudit.h> |
| #endif |
| |
| #include <dbus/dbus-internals.h> |
| #ifdef DBUS_UNIX |
| #include <dbus/dbus-userdb.h> |
| #endif |
| |
| #ifdef HAVE_LIBAUDIT |
| static int audit_fd = -1; |
| #endif |
| |
| /** |
| * Open the libaudit fd if appropriate. |
| */ |
| void |
| bus_audit_init (BusContext *context) |
| { |
| #ifdef HAVE_LIBAUDIT |
| int i; |
| |
| capng_get_caps_process (); |
| |
| /* Work around a bug in libcap-ng < 0.7.7: it leaks a fd, which isn't |
| * close-on-exec. Assume it will be one of the first few fds. */ |
| for (i = 3; i < 42; i++) |
| _dbus_fd_set_close_on_exec (i); |
| |
| if (!capng_have_capability (CAPNG_EFFECTIVE, CAP_AUDIT_WRITE)) |
| return; |
| |
| audit_fd = audit_open (); |
| |
| if (audit_fd < 0) |
| { |
| int e = errno; |
| |
| /* If kernel doesn't support audit, bail out */ |
| if (e == EINVAL || e == EPROTONOSUPPORT || e == EAFNOSUPPORT) |
| return; |
| |
| bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, |
| "Failed to open connection to the audit subsystem: %s", |
| _dbus_strerror (e)); |
| } |
| #endif /* HAVE_LIBAUDIT */ |
| } |
| |
| /** |
| * If libaudit is in use and it would be appropriate to write audit records, |
| * return the libaudit fd. Otherwise return -1. |
| */ |
| int |
| bus_audit_get_fd (void) |
| { |
| #ifdef HAVE_LIBAUDIT |
| if (audit_fd >= 0) |
| { |
| return audit_fd; |
| } |
| #endif |
| |
| return -1; |
| } |
| |
| /** |
| * Close the libaudit fd. |
| */ |
| void |
| bus_audit_shutdown (void) |
| { |
| #ifdef HAVE_LIBAUDIT |
| audit_close (audit_fd); |
| #endif /* HAVE_LIBAUDIT */ |
| } |
| |
| /* The !HAVE_LIBAUDIT case lives in dbus-sysdeps-util-unix.c */ |
| #ifdef HAVE_LIBAUDIT |
| /** |
| * 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; |
| } |
| |
| /* If we were root */ |
| if (_dbus_geteuid () == 0) |
| { |
| int rc; |
| int have_audit_write; |
| |
| have_audit_write = capng_have_capability (CAPNG_PERMITTED, CAP_AUDIT_WRITE); |
| capng_clear (CAPNG_SELECT_BOTH); |
| /* Only attempt to retain CAP_AUDIT_WRITE if we had it when |
| * starting. See: |
| * https://bugs.freedesktop.org/show_bug.cgi?id=49062#c9 |
| */ |
| if (have_audit_write) |
| capng_update (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, |
| CAP_AUDIT_WRITE); |
| rc = capng_change_id (uid, gid, CAPNG_DROP_SUPP_GRP); |
| 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; |
| } |
| } |
| |
| return TRUE; |
| } |
| #endif |