1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Dan Walsh
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "selinux-access.h"
30 #include <selinux/selinux.h>
31 #include <selinux/avc.h>
41 #include "selinux-util.h"
44 static bool initialized = false;
54 static int bus_get_selinux_security_context(
60 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
70 r = sd_bus_call_method(
72 "org.freedesktop.DBus",
73 "/org/freedesktop/DBus",
74 "org.freedesktop.DBus",
75 "GetConnectionSELinuxSecurityContext",
81 r = sd_bus_message_read_array(m, 'y', &p, &sz);
93 static int bus_get_audit_data(
96 struct auditstruct *audit) {
105 r = sd_bus_get_owner_pid(bus, name, &pid);
109 r = audit_loginuid_from_pid(pid, &audit->loginuid);
113 r = get_process_uid(pid, &audit->uid);
117 r = get_process_gid(pid, &audit->gid);
121 r = get_process_cmdline(pid, 0, true, &audit->cmdline);
129 Any time an access gets denied this callback will be called
130 with the aduit data. We then need to just copy the audit data into the msgbuf.
132 static int audit_callback(
134 security_class_t cls,
138 struct auditstruct *audit = (struct auditstruct *) auditdata;
140 snprintf(msgbuf, msgbufsize,
141 "auid=%d uid=%d gid=%d%s%s%s%s%s%s",
145 (audit->path ? " path=\"" : ""),
146 strempty(audit->path),
147 (audit->path ? "\"" : ""),
148 (audit->cmdline ? " cmdline=\"" : ""),
149 strempty(audit->cmdline),
150 (audit->cmdline ? "\"" : ""));
152 msgbuf[msgbufsize-1] = 0;
158 Any time an access gets denied this callback will be called
159 code copied from dbus. If audit is turned on the messages will go as
160 user_avc's into the /var/log/audit/audit.log, otherwise they will be
163 _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
169 if (get_audit_fd() >= 0) {
170 _cleanup_free_ char *buf = NULL;
173 r = vasprintf(&buf, fmt, ap);
177 audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
184 log_metav(LOG_USER | LOG_INFO, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
191 Function must be called once to initialize the SELinux AVC environment.
193 If you want to cleanup memory you should need to call selinux_access_finish.
195 static int access_init(void) {
198 if (avc_open(NULL, 0)) {
199 log_error("avc_open() failed: %m");
203 selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
204 selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
206 if (security_getenforce() < 0){
214 static int selinux_access_init(sd_bus_error *error) {
225 return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux.");
231 void selinux_access_free(void) {
240 static int get_audit_data(
242 sd_bus_message *message,
243 struct auditstruct *audit) {
250 sender = sd_bus_message_get_sender(message);
252 return bus_get_audit_data(bus, sender, audit);
254 fd = sd_bus_get_fd(bus);
259 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len);
263 audit->uid = ucred.uid;
264 audit->gid = ucred.gid;
266 r = audit_loginuid_from_pid(ucred.pid, &audit->loginuid);
270 r = get_process_cmdline(ucred.pid, 0, true, &audit->cmdline);
278 This function returns the security context of the remote end of the dbus
279 connections. Whether it is on the bus or a local connection.
281 static int get_calling_context(
283 sd_bus_message *message,
285 security_context_t *ret) {
291 If sender exists then
292 if sender is NULL this indicates a local connection. Grab the fd
293 from dbus and do an getpeercon to peers process context
295 sender = sd_bus_message_get_sender(message);
297 return bus_get_selinux_security_context(bus, sender, error, ret);
299 fd = sd_bus_get_fd(bus);
303 r = getpeercon(fd, ret);
311 This function communicates with the kernel to check whether or not it should
313 If the machine is in permissive mode it will return ok. Audit messages will
314 still be generated if the access would be denied in enforcing mode.
316 int selinux_access_check(
318 sd_bus_message *message,
320 const char *permission,
321 sd_bus_error *error) {
323 security_context_t scon = NULL, fcon = NULL;
324 const char *tclass = NULL;
325 struct auditstruct audit;
336 r = selinux_access_init(error);
340 audit.uid = audit.loginuid = (uid_t) -1;
341 audit.gid = (gid_t) -1;
342 audit.cmdline = NULL;
345 r = get_calling_context(bus, message, error, &scon);
350 /* Get the file context of the unit file */
352 r = getfilecon(path, &fcon);
354 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path);
362 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
369 get_audit_data(bus, message, &audit);
372 r = selinux_check_access(scon, fcon, tclass, permission, &audit);
374 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
376 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);
383 if (r && security_getenforce() != 1) {
384 sd_bus_error_free(error);
393 int selinux_access_check(
395 sd_bus_message *message,
397 const char *permission,
398 sd_bus_error *error) {
403 void selinux_access_free(void) {