diff options
Diffstat (limited to 'dbus/dbus-sysdeps.c')
-rw-r--r-- | dbus/dbus-sysdeps.c | 95 |
1 files changed, 92 insertions, 3 deletions
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 79f764d6..4092ae91 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -38,6 +38,13 @@ #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 */ + #include <pwd.h> #include <time.h> #include <locale.h> @@ -3281,6 +3288,55 @@ _dbus_change_identity (dbus_uid_t uid, dbus_gid_t gid, DBusError *error) { + int priv = FALSE; + +#ifdef HAVE_LIBAUDIT + /* 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. + */ + cap_t new_caps = NULL; + + priv = !getuid(); + if (priv) + { + 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\n"); + 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)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to drop capabilities\n"); + cap_free(tmp_caps); + goto fail; + } + cap_free(tmp_caps); + } +#endif /* HAVE_LIBAUDIT */ + /* Set GID first, or the setuid may remove our permission * to change the GID */ @@ -3289,7 +3345,7 @@ _dbus_change_identity (dbus_uid_t uid, 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) @@ -3297,10 +3353,43 @@ _dbus_change_identity (dbus_uid_t uid, 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 (priv) + { + if (cap_set_proc(new_caps)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to drop capabilities\n"); + goto fail; + } + cap_free(new_caps); + + if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) == -1) + { /* should always work, if it did above */ + 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 (priv) + { + /* 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 |