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>
32 #include <sys/socket.h>
42 #include "selinux-util.h"
45 static bool initialized = false;
55 static int bus_get_selinux_security_context(
61 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
71 r = sd_bus_call_method(
73 "org.freedesktop.DBus",
74 "/org/freedesktop/DBus",
75 "org.freedesktop.DBus",
76 "GetConnectionSELinuxSecurityContext",
82 r = sd_bus_message_read_array(m, 'y', &p, &sz);
94 static int bus_get_audit_data(
97 struct auditstruct *audit) {
106 r = sd_bus_get_owner_pid(bus, name, &pid);
110 r = audit_loginuid_from_pid(pid, &audit->loginuid);
114 r = get_process_uid(pid, &audit->uid);
118 r = get_process_gid(pid, &audit->gid);
122 r = get_process_cmdline(pid, 0, true, &audit->cmdline);
130 Any time an access gets denied this callback will be called
131 with the aduit data. We then need to just copy the audit data into the msgbuf.
133 static int audit_callback(
135 security_class_t cls,
139 struct auditstruct *audit = (struct auditstruct *) auditdata;
141 snprintf(msgbuf, msgbufsize,
142 "auid=%d uid=%d gid=%d%s%s%s%s%s%s",
146 (audit->path ? " path=\"" : ""),
147 strempty(audit->path),
148 (audit->path ? "\"" : ""),
149 (audit->cmdline ? " cmdline=\"" : ""),
150 strempty(audit->cmdline),
151 (audit->cmdline ? "\"" : ""));
153 msgbuf[msgbufsize-1] = 0;
159 Any time an access gets denied this callback will be called
160 code copied from dbus. If audit is turned on the messages will go as
161 user_avc's into the /var/log/audit/audit.log, otherwise they will be
164 _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
170 if (get_audit_fd() >= 0) {
171 _cleanup_free_ char *buf = NULL;
174 r = vasprintf(&buf, fmt, ap);
178 audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
185 log_metav(LOG_USER | LOG_INFO, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
192 Function must be called once to initialize the SELinux AVC environment.
194 If you want to cleanup memory you should need to call selinux_access_finish.
196 static int access_init(void) {
199 if (avc_open(NULL, 0)) {
200 log_error("avc_open() failed: %m");
204 selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
205 selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
207 if (security_getenforce() < 0){
215 static int selinux_access_init(sd_bus_error *error) {
226 return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux.");
232 void selinux_access_free(void) {
241 static int get_audit_data(
243 sd_bus_message *message,
244 struct auditstruct *audit) {
251 sender = sd_bus_message_get_sender(message);
253 return bus_get_audit_data(bus, sender, audit);
255 fd = sd_bus_get_fd(bus);
260 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len);
264 audit->uid = ucred.uid;
265 audit->gid = ucred.gid;
267 r = audit_loginuid_from_pid(ucred.pid, &audit->loginuid);
271 r = get_process_cmdline(ucred.pid, 0, true, &audit->cmdline);
279 This function returns the security context of the remote end of the dbus
280 connections. Whether it is on the bus or a local connection.
282 static int get_calling_context(
284 sd_bus_message *message,
286 security_context_t *ret) {
292 If sender exists then
293 if sender is NULL this indicates a local connection. Grab the fd
294 from dbus and do an getpeercon to peers process context
296 sender = sd_bus_message_get_sender(message);
298 return bus_get_selinux_security_context(bus, sender, error, ret);
300 fd = sd_bus_get_fd(bus);
304 r = getpeercon(fd, ret);
312 This function communicates with the kernel to check whether or not it should
314 If the machine is in permissive mode it will return ok. Audit messages will
315 still be generated if the access would be denied in enforcing mode.
317 int selinux_generic_access_check(
319 sd_bus_message *message,
321 const char *permission,
322 sd_bus_error *error) {
324 security_context_t scon = NULL, fcon = NULL;
325 const char *tclass = NULL;
326 struct auditstruct audit;
337 r = selinux_access_init(error);
341 audit.uid = audit.loginuid = (uid_t) -1;
342 audit.gid = (gid_t) -1;
343 audit.cmdline = NULL;
346 r = get_calling_context(bus, message, error, &scon);
351 /* Get the file context of the unit file */
353 r = getfilecon(path, &fcon);
355 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path);
363 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
370 get_audit_data(bus, message, &audit);
373 r = selinux_check_access(scon, fcon, tclass, permission, &audit);
375 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
377 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);
384 if (r && security_getenforce() != 1) {
385 sd_bus_error_free(error);
394 int selinux_generic_access_check(
396 sd_bus_message *message,
398 const char *permission,
399 sd_bus_error *error) {
404 void selinux_access_free(void) {