selinux-access.c revision 03e22642617f360a6b55cb853bcf59604754ea5d
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/***
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen This file is part of systemd.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Copyright 2012 Dan Walsh
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen systemd is free software; you can redistribute it and/or modify it
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen under the terms of the GNU Lesser General Public License as published by
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen (at your option) any later version.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen systemd is distributed in the hope that it will be useful, but
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Lesser General Public License for more details.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen You should have received a copy of the GNU Lesser General Public License
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen***/
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include "selinux-access.h"
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen#ifdef HAVE_SELINUX
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen#include <stdio.h>
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen#include <string.h>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <errno.h>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <limits.h>
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen#include <selinux/selinux.h>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <selinux/avc.h>
d122f9ee3a0e3c02ff8100a3dcd1866e90a6537aTom Gundersen#ifdef HAVE_AUDIT
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen#include <libaudit.h>
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#endif
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#include <dbus.h>
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#include "util.h"
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#include "log.h"
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#include "bus-errors.h"
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#include "dbus-common.h"
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#include "audit.h"
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen#include "selinux-util.h"
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen#include "audit-fd.h"
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstatic bool initialized = false;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersenstruct auditstruct {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen const char *path;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen char *cmdline;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen uid_t loginuid;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen uid_t uid;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen gid_t gid;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen};
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersenstatic int bus_get_selinux_security_context(
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen DBusConnection *connection,
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen const char *name,
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen char **scon,
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen DBusError *error) {
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen DBusMessageIter iter, sub;
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen const char *bytes;
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen char *b;
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen int nbytes;
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen m = dbus_message_new_method_call(
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen DBUS_SERVICE_DBUS,
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen DBUS_PATH_DBUS,
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen DBUS_INTERFACE_DBUS,
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen "GetConnectionSELinuxSecurityContext");
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (!m) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return -ENOMEM;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (!dbus_message_append_args(
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen m,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen DBUS_TYPE_STRING, &name,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen DBUS_TYPE_INVALID)) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return -ENOMEM;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!reply)
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return -EIO;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (dbus_set_error_from_message(error, reply))
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return -EIO;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!dbus_message_iter_init(reply, &iter))
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return -EIO;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return -EIO;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen dbus_message_iter_recurse(&iter, &sub);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen dbus_message_iter_get_fixed_array(&sub, &bytes, &nbytes);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen b = strndup(bytes, nbytes);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!b)
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return -ENOMEM;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen *scon = b;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return 0;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen}
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstatic int bus_get_audit_data(
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen DBusConnection *connection,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen const char *name,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen struct auditstruct *audit,
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen DBusError *error) {
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen pid_t pid;
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering int r;
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen pid = bus_get_unix_process_id(connection, name, error);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering if (pid <= 0)
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering return -EIO;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering r = audit_loginuid_from_pid(pid, &audit->loginuid);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (r < 0)
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering return r;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering r = get_process_uid(pid, &audit->uid);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering if (r < 0)
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering return r;
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering r = get_process_gid(pid, &audit->gid);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering if (r < 0)
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering return r;
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen r = get_process_cmdline(pid, 0, true, &audit->cmdline);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (r < 0)
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return r;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen return 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen}
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/*
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen Any time an access gets denied this callback will be called
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen with the aduit data. We then need to just copy the audit data into the msgbuf.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen*/
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersenstatic int audit_callback(
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen void *auditdata,
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen security_class_t cls,
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen char *msgbuf,
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen size_t msgbufsize) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen struct auditstruct *audit = (struct auditstruct *) auditdata;
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen snprintf(msgbuf, msgbufsize,
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen "auid=%d uid=%d gid=%d%s%s%s%s%s%s",
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen audit->loginuid,
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen audit->uid,
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen audit->gid,
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen (audit->path ? " path=\"" : ""),
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen strempty(audit->path),
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen (audit->path ? "\"" : ""),
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen (audit->cmdline ? " cmdline=\"" : ""),
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen strempty(audit->cmdline),
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen (audit->cmdline ? "\"" : ""));
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen msgbuf[msgbufsize-1] = 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen}
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/*
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Any time an access gets denied this callback will be called
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen code copied from dbus. If audit is turned on the messages will go as
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen user_avc's into the /var/log/audit/audit.log, otherwise they will be
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen sent to syslog.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen*/
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen_printf_attr_(2, 3) static int log_callback(int type, const char *fmt, ...) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen va_list ap;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen va_start(ap, fmt);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#ifdef HAVE_AUDIT
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (get_audit_fd() >= 0) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen _cleanup_free_ char *buf = NULL;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen int r;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen r = vasprintf(&buf, fmt, ap);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen va_end(ap);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (r >= 0) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen va_start(ap, fmt);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen#endif
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen log_metav(LOG_USER | LOG_INFO, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen va_end(ap);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen return 0;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen}
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen/*
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen Function must be called once to initialize the SELinux AVC environment.
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen Sets up callbacks.
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen If you want to cleanup memory you should need to call selinux_access_finish.
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen*/
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int access_init(void) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (avc_open(NULL, 0)) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("avc_open() failed: %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return -errno;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (security_getenforce() >= 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = -errno;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen avc_destroy();
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int selinux_access_init(DBusError *error) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (initialized)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (use_selinux()) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = access_init();
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux.");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen initialized = true;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenvoid selinux_access_free(void) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (!initialized)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen avc_destroy();
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen initialized = false;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int get_audit_data(
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusConnection *connection,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusMessage *message,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen struct auditstruct *audit,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusError *error) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen const char *sender;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r, fd;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen struct ucred ucred;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen socklen_t len = sizeof(ucred);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen sender = dbus_message_get_sender(message);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (sender)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return bus_get_audit_data(connection, sender, audit, error);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (!dbus_connection_get_unix_fd(connection, &fd))
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return -EINVAL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to determine peer credentials: %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return -errno;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen audit->uid = ucred.uid;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen audit->gid = ucred.gid;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = audit_loginuid_from_pid(ucred.pid, &audit->loginuid);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = get_process_cmdline(ucred.pid, 0, true, &audit->cmdline);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen/*
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen This function returns the security context of the remote end of the dbus
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen connections. Whether it is on the bus or a local connection.
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen*/
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int get_calling_context(
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusConnection *connection,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusMessage *message,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen security_context_t *scon,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusError *error) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen const char *sender;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int fd;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen /*
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen If sender exists then
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if sender is NULL this indicates a local connection. Grab the fd
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen from dbus and do an getpeercon to peers process context
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen */
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen sender = dbus_message_get_sender(message);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (sender) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = bus_get_selinux_security_context(connection, sender, scon, error);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r >= 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("bus_get_selinux_security_context failed: %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (!dbus_connection_get_unix_fd(connection, &fd)) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("bus_connection_get_unix_fd failed %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return -EINVAL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = getpeercon(fd, scon);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("getpeercon failed %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return -errno;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen/*
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen This function communicates with the kernel to check whether or not it should
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen allow the access.
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen If the machine is in permissive mode it will return ok. Audit messages will
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen still be generated if the access would be denied in enforcing mode.
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen*/
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenint selinux_access_check(
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusConnection *connection,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusMessage *message,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen const char *path,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen const char *permission,
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusError *error) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen security_context_t scon = NULL, fcon = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r = 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen const char *tclass = NULL;
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen struct auditstruct audit;
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen assert(connection);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(message);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(permission);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(error);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (!use_selinux())
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen r = selinux_access_init(error);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r < 0)
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen return r;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen audit.uid = audit.loginuid = (uid_t) -1;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen audit.gid = (gid_t) -1;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen audit.cmdline = NULL;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen audit.path = path;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen r = get_calling_context(connection, message, &scon, error);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r < 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error("Failed to get caller's security context on: %m");
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen goto finish;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (path) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen tclass = "service";
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen /* get the file context of the unit file */
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen r = getfilecon(path, &fcon);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r < 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen r = -errno;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error("Failed to get security context on %s: %m",path);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen goto finish;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen } else {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen tclass = "system";
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen r = getcon(&fcon);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r < 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen r = -errno;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error("Failed to get current process context on: %m");
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen goto finish;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen (void) get_audit_data(connection, message, &audit, error);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen errno = 0;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen r = selinux_check_access(scon, fcon, tclass, permission, &audit);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (r < 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen r = -errno;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error("SELinux policy denies access.");
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, audit.cmdline, r);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersenfinish:
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen free(audit.cmdline);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen freecon(scon);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen freecon(fcon);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r && security_getenforce() != 1) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen dbus_error_init(error);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen r = 0;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen }
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen return r;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen}
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#else
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersenint selinux_access_check(
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen DBusConnection *connection,
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen DBusMessage *message,
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen const char *path,
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen const char *permission,
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen DBusError *error) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen return 0;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen}
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersenvoid selinux_access_free(void) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen}
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#endif
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen