]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/selinux-access.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / core / selinux-access.c
CommitLineData
e2417e41
DW
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Dan Walsh
7
8 systemd is free software; you can redistribute it and/or modify it
03e22642
KS
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
e2417e41
DW
11 (at your option) any later version.
12
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
03e22642 16 Lesser General Public License for more details.
e2417e41 17
03e22642 18 You should have received a copy of the GNU Lesser General Public License
e2417e41
DW
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
e2417e41
DW
22#include "selinux-access.h"
23
24#ifdef HAVE_SELINUX
e2417e41
DW
25
26#include <stdio.h>
27#include <string.h>
28#include <errno.h>
ffc227c9 29#include <limits.h>
e2417e41
DW
30#include <selinux/selinux.h>
31#include <selinux/avc.h>
94d56326 32#include <sys/socket.h>
e2417e41
DW
33#ifdef HAVE_AUDIT
34#include <libaudit.h>
35#endif
ffc227c9 36
718db961
LP
37#include "sd-bus.h"
38#include "bus-util.h"
ffc227c9
LP
39#include "util.h"
40#include "log.h"
ffc227c9
LP
41#include "audit.h"
42#include "selinux-util.h"
43#include "audit-fd.h"
5b12334d 44#include "strv.h"
e2417e41 45
cad45ba1 46static bool initialized = false;
e2417e41 47
5b12334d
LP
48struct audit_info {
49 sd_bus_creds *creds;
e2417e41 50 const char *path;
5b12334d 51 const char *cmdline;
e2417e41
DW
52};
53
e2417e41
DW
54/*
55 Any time an access gets denied this callback will be called
dec23413 56 with the audit data. We then need to just copy the audit data into the msgbuf.
e2417e41 57*/
cad45ba1
LP
58static int audit_callback(
59 void *auditdata,
60 security_class_t cls,
61 char *msgbuf,
62 size_t msgbufsize) {
63
5b12334d
LP
64 const struct audit_info *audit = auditdata;
65 uid_t uid = 0, login_uid = 0;
66 gid_t gid = 0;
dec23413
ZJS
67 char login_uid_buf[DECIMAL_STR_MAX(uid_t)] = "n/a";
68 char uid_buf[DECIMAL_STR_MAX(uid_t)] = "n/a";
69 char gid_buf[DECIMAL_STR_MAX(gid_t)] = "n/a";
5b12334d 70
dec23413
ZJS
71 if (sd_bus_creds_get_audit_login_uid(audit->creds, &login_uid) >= 0)
72 snprintf(login_uid_buf, sizeof(login_uid_buf), UID_FMT, login_uid);
73 if (sd_bus_creds_get_uid(audit->creds, &uid) >= 0)
74 snprintf(uid_buf, sizeof(uid_buf), UID_FMT, uid);
75 if (sd_bus_creds_get_gid(audit->creds, &gid) >= 0)
76 snprintf(gid_buf, sizeof(gid_buf), GID_FMT, gid);
cad45ba1 77
e2417e41 78 snprintf(msgbuf, msgbufsize,
dec23413
ZJS
79 "auid=%s uid=%s gid=%s%s%s%s%s%s%s",
80 login_uid_buf, uid_buf, gid_buf,
5b12334d
LP
81 audit->path ? " path=\"" : "", strempty(audit->path), audit->path ? "\"" : "",
82 audit->cmdline ? " cmdline=\"" : "", strempty(audit->cmdline), audit->cmdline ? "\"" : "");
d67227c8 83
cad45ba1 84 msgbuf[msgbufsize-1] = 0;
d67227c8 85
e2417e41
DW
86 return 0;
87}
88
89/*
90 Any time an access gets denied this callback will be called
91 code copied from dbus. If audit is turned on the messages will go as
92 user_avc's into the /var/log/audit/audit.log, otherwise they will be
93 sent to syslog.
94*/
44b601bc 95_printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
e2417e41
DW
96 va_list ap;
97
e2417e41 98#ifdef HAVE_AUDIT
c1165f82 99 if (get_audit_fd() >= 0) {
ace188cf
LP
100 _cleanup_free_ char *buf = NULL;
101 int r;
e2417e41 102
5b12334d 103 va_start(ap, fmt);
ace188cf 104 r = vasprintf(&buf, fmt, ap);
7f1736f7 105 va_end(ap);
cad45ba1 106
ace188cf
LP
107 if (r >= 0) {
108 audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
109 return 0;
110 }
e2417e41
DW
111 }
112#endif
5b12334d
LP
113
114 va_start(ap, fmt);
12f1caf4 115 log_internalv(LOG_AUTH | LOG_INFO, 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
e2417e41 116 va_end(ap);
cad45ba1 117
e2417e41
DW
118 return 0;
119}
120
121/*
122 Function must be called once to initialize the SELinux AVC environment.
123 Sets up callbacks.
124 If you want to cleanup memory you should need to call selinux_access_finish.
125*/
126static int access_init(void) {
718db961 127 int r = 0;
e2417e41
DW
128
129 if (avc_open(NULL, 0)) {
56f64d95 130 log_error_errno(errno, "avc_open() failed: %m");
e2417e41
DW
131 return -errno;
132 }
133
cad45ba1
LP
134 selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
135 selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
e2417e41 136
718db961
LP
137 if (security_getenforce() < 0){
138 r = -errno;
139 avc_destroy();
140 }
cad45ba1 141
e2417e41
DW
142 return r;
143}
144
8a188de9 145static int mac_selinux_access_init(sd_bus_error *error) {
e2417e41
DW
146 int r;
147
cad45ba1 148 if (initialized)
e2417e41
DW
149 return 0;
150
6baa7db0 151 if (!mac_selinux_use())
718db961
LP
152 return 0;
153
154 r = access_init();
155 if (r < 0)
156 return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux.");
e2417e41 157
cad45ba1 158 initialized = true;
e2417e41
DW
159 return 0;
160}
8a188de9 161#endif
e2417e41 162
8a188de9 163void mac_selinux_access_free(void) {
718db961 164
8a188de9 165#ifdef HAVE_SELINUX
ffc227c9
LP
166 if (!initialized)
167 return;
168
169 avc_destroy();
170 initialized = false;
8a188de9 171#endif
ffc227c9
LP
172}
173
e2417e41
DW
174/*
175 This function communicates with the kernel to check whether or not it should
176 allow the access.
177 If the machine is in permissive mode it will return ok. Audit messages will
178 still be generated if the access would be denied in enforcing mode.
179*/
8a188de9 180int mac_selinux_generic_access_check(
718db961 181 sd_bus_message *message,
cad45ba1
LP
182 const char *path,
183 const char *permission,
718db961 184 sd_bus_error *error) {
cad45ba1 185
8a188de9 186#ifdef HAVE_SELINUX
5b12334d
LP
187 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
188 const char *tclass = NULL, *scon = NULL;
189 struct audit_info audit_info = {};
190 _cleanup_free_ char *cl = NULL;
191 security_context_t fcon = NULL;
192 char **cmdline = NULL;
718db961 193 int r = 0;
c3090674 194
cad45ba1
LP
195 assert(message);
196 assert(permission);
197 assert(error);
198
6baa7db0 199 if (!mac_selinux_use())
cad45ba1
LP
200 return 0;
201
8a188de9 202 r = mac_selinux_access_init(error);
ffc227c9
LP
203 if (r < 0)
204 return r;
205
5b12334d
LP
206 r = sd_bus_query_sender_creds(
207 message,
208 SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|
209 SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_AUDIT_LOGIN_UID|
8fd00193
LP
210 SD_BUS_CREDS_SELINUX_CONTEXT|
211 SD_BUS_CREDS_AUGMENT /* get more bits from /proc */,
5b12334d
LP
212 &creds);
213 if (r < 0)
214 goto finish;
e2417e41 215
5b12334d 216 r = sd_bus_creds_get_selinux_context(creds, &scon);
718db961 217 if (r < 0)
e2417e41 218 goto finish;
cad45ba1 219
e2417e41 220 if (path) {
718db961
LP
221 /* Get the file context of the unit file */
222
e2417e41
DW
223 r = getfilecon(path, &fcon);
224 if (r < 0) {
718db961 225 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path);
e2417e41
DW
226 goto finish;
227 }
228
718db961 229 tclass = "service";
e2417e41 230 } else {
e2417e41
DW
231 r = getcon(&fcon);
232 if (r < 0) {
718db961 233 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
e2417e41
DW
234 goto finish;
235 }
718db961
LP
236
237 tclass = "system";
e2417e41
DW
238 }
239
5b12334d
LP
240 sd_bus_creds_get_cmdline(creds, &cmdline);
241 cl = strv_join(cmdline, " ");
242
243 audit_info.creds = creds;
244 audit_info.path = path;
245 audit_info.cmdline = cl;
e2417e41 246
5b12334d 247 r = selinux_check_access((security_context_t) scon, fcon, tclass, permission, &audit_info);
718db961
LP
248 if (r < 0)
249 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
e2417e41 250
5b12334d 251 log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, cl, r);
cad45ba1 252
e2417e41 253finish:
e2417e41
DW
254 freecon(fcon);
255
5b12334d 256 if (r < 0 && security_getenforce() != 1) {
718db961 257 sd_bus_error_free(error);
e2417e41
DW
258 r = 0;
259 }
260
261 return r;
8a188de9
WC
262#else
263 return 0;
264#endif
e2417e41
DW
265}
266
8a188de9 267int mac_selinux_unit_access_check_strv(char **units,
e94937df
LN
268 sd_bus_message *message,
269 Manager *m,
270 const char *permission,
271 sd_bus_error *error) {
8a188de9 272#ifdef HAVE_SELINUX
e94937df
LN
273 char **i;
274 Unit *u;
275 int r;
276
277 STRV_FOREACH(i, units) {
278 u = manager_get_unit(m, *i);
279 if (u) {
8a188de9 280 r = mac_selinux_unit_access_check(u, message, permission, error);
e94937df
LN
281 if (r < 0)
282 return r;
283 }
284 }
8a188de9 285#endif
e94937df
LN
286 return 0;
287}