]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/label.c
core: move ManagerRunningAs to shared
[thirdparty/systemd.git] / src / shared / label.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e51bc1a2
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
e51bc1a2
LP
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
5430f7f2 16 Lesser General Public License for more details.
e51bc1a2 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
e51bc1a2
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <sys/stat.h>
24#include <unistd.h>
455a946f 25#include <malloc.h>
f13e30d2
LP
26#include <sys/socket.h>
27#include <sys/un.h>
e51bc1a2
LP
28
29#include "label.h"
30#include "util.h"
9eb977db 31#include "path-util.h"
e51bc1a2
LP
32
33#ifdef HAVE_SELINUX
34#include <selinux/selinux.h>
35#include <selinux/label.h>
36
37static struct selabel_handle *label_hnd = NULL;
38
4d4c7486
LP
39static int use_selinux_cached = -1;
40
e51bc1a2 41static inline bool use_selinux(void) {
e51bc1a2 42
4ef31082
LP
43 if (use_selinux_cached < 0)
44 use_selinux_cached = is_selinux_enabled() > 0;
e51bc1a2 45
4ef31082 46 return use_selinux_cached;
e51bc1a2
LP
47}
48
4d4c7486
LP
49void label_retest_selinux(void) {
50 use_selinux_cached = -1;
51}
52
e51bc1a2
LP
53#endif
54
0f9963a8 55int label_init(const char *prefix) {
e51bc1a2
LP
56 int r = 0;
57
58#ifdef HAVE_SELINUX
189583d7
LP
59 usec_t before_timestamp, after_timestamp;
60 struct mallinfo before_mallinfo, after_mallinfo;
e51bc1a2
LP
61
62 if (!use_selinux())
63 return 0;
64
c4dcdb9f
LP
65 if (label_hnd)
66 return 0;
67
189583d7
LP
68 before_mallinfo = mallinfo();
69 before_timestamp = now(CLOCK_MONOTONIC);
455a946f 70
0f9963a8 71 if (prefix) {
e9a5ef7c 72 struct selinux_opt options[] = {
0f9963a8 73 { .type = SELABEL_OPT_SUBSET, .value = prefix },
e9a5ef7c
KS
74 };
75
76 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
77 } else
78 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
79
e51bc1a2
LP
80 if (!label_hnd) {
81 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
82 "Failed to initialize SELinux context: %m");
049f8642 83 r = security_getenforce() == 1 ? -errno : 0;
871e5809 84 } else {
189583d7 85 char timespan[FORMAT_TIMESPAN_MAX];
455a946f 86 int l;
871e5809 87
189583d7
LP
88 after_timestamp = now(CLOCK_MONOTONIC);
89 after_mallinfo = mallinfo();
871e5809 90
189583d7 91 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
455a946f 92
107a2db9
LP
93 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
94 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp),
95 (l+1023)/1024);
455a946f 96 }
e51bc1a2
LP
97#endif
98
99 return r;
100}
101
c9bc0764 102int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
e51bc1a2
LP
103 int r = 0;
104
105#ifdef HAVE_SELINUX
106 struct stat st;
107 security_context_t fcon;
108
109 if (!use_selinux() || !label_hnd)
110 return 0;
111
112 r = lstat(path, &st);
113 if (r == 0) {
114 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
115
5a33f657
LP
116 /* If there's no label to set, then exit without warning */
117 if (r < 0 && errno == ENOENT)
118 return 0;
119
e51bc1a2 120 if (r == 0) {
81c3f1f6 121 r = lsetfilecon(path, fcon);
e51bc1a2 122 freecon(fcon);
d2dfce17
LP
123
124 /* If the FS doesn't support labels, then exit without warning */
125 if (r < 0 && errno == ENOTSUP)
126 return 0;
e51bc1a2
LP
127 }
128 }
5a33f657 129
e51bc1a2 130 if (r < 0) {
b4bd5144
LP
131 /* Ignore ENOENT in some cases */
132 if (ignore_enoent && errno == ENOENT)
133 return 0;
134
c9bc0764
LP
135 if (ignore_erofs && errno == EROFS)
136 return 0;
137
e51bc1a2
LP
138 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
139 "Unable to fix label of %s: %m", path);
049f8642 140 r = security_getenforce() == 1 ? -errno : 0;
e51bc1a2
LP
141 }
142#endif
143
144 return r;
145}
146
147void label_finish(void) {
148
149#ifdef HAVE_SELINUX
150 if (use_selinux() && label_hnd)
151 selabel_close(label_hnd);
152#endif
153}
154
189583d7 155int label_get_create_label_from_exe(const char *exe, char **label) {
e51bc1a2
LP
156
157 int r = 0;
158
159#ifdef HAVE_SELINUX
160 security_context_t mycon = NULL, fcon = NULL;
161 security_class_t sclass;
162
163 if (!use_selinux()) {
164 *label = NULL;
165 return 0;
166 }
167
168 r = getcon(&mycon);
169 if (r < 0)
170 goto fail;
171
172 r = getfilecon(exe, &fcon);
173 if (r < 0)
174 goto fail;
175
176 sclass = string_to_security_class("process");
177 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
178 if (r == 0)
179 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
180
181fail:
182 if (r < 0 && security_getenforce() == 1)
183 r = -errno;
184
185 freecon(mycon);
186 freecon(fcon);
187#endif
188
189 return r;
190}
191
e9a5ef7c 192int label_context_set(const char *path, mode_t mode) {
5c0532d1
LP
193 int r = 0;
194
195#ifdef HAVE_SELINUX
196 security_context_t filecon = NULL;
197
198 if (!use_selinux() || !label_hnd)
199 return 0;
200
e9a5ef7c 201 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
382241ee
LP
202 if (r < 0)
203 r = -errno;
204 else if (r == 0) {
205 r = setfscreatecon(filecon);
206 if (r < 0) {
5c0532d1
LP
207 log_error("Failed to set SELinux file context on %s: %m", path);
208 r = -errno;
209 }
210
211 freecon(filecon);
212 }
213
214 if (r < 0 && security_getenforce() == 0)
215 r = 0;
216#endif
217
218 return r;
219}
220
e51bc1a2
LP
221int label_socket_set(const char *label) {
222
223#ifdef HAVE_SELINUX
224 if (!use_selinux())
225 return 0;
226
227 if (setsockcreatecon((security_context_t) label) < 0) {
228 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
229 "Failed to set SELinux context (%s) on socket: %m", label);
230
231 if (security_getenforce() == 1)
232 return -errno;
233 }
234#endif
235
236 return 0;
237}
238
e9a5ef7c 239void label_context_clear(void) {
e51bc1a2
LP
240
241#ifdef HAVE_SELINUX
242 if (!use_selinux())
243 return;
244
245 setfscreatecon(NULL);
246#endif
247}
248
249void label_socket_clear(void) {
250
251#ifdef HAVE_SELINUX
252 if (!use_selinux())
253 return;
254
255 setsockcreatecon(NULL);
256#endif
257}
258
259void label_free(const char *label) {
260
261#ifdef HAVE_SELINUX
262 if (!use_selinux())
263 return;
264
265 freecon((security_context_t) label);
266#endif
267}
268
c66e7f04 269int label_mkdir(const char *path, mode_t mode, bool apply) {
e51bc1a2
LP
270
271 /* Creates a directory and labels it according to the SELinux policy */
e51bc1a2
LP
272#ifdef HAVE_SELINUX
273 int r;
274 security_context_t fcon = NULL;
275
c66e7f04 276 if (!apply || !use_selinux() || !label_hnd)
f13e30d2 277 goto skipped;
e51bc1a2 278
f13e30d2 279 if (path_is_absolute(path))
382241ee 280 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR);
f13e30d2
LP
281 else {
282 char *newpath;
e51bc1a2 283
f13e30d2
LP
284 newpath = path_make_absolute_cwd(path);
285 if (!newpath)
286 return -ENOMEM;
e51bc1a2 287
382241ee 288 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR);
f13e30d2
LP
289 free(newpath);
290 }
291
292 if (r == 0)
293 r = setfscreatecon(fcon);
e51bc1a2 294
f13e30d2
LP
295 if (r < 0 && errno != ENOENT) {
296 log_error("Failed to set security context %s for %s: %m", fcon, path);
e51bc1a2 297
f13e30d2 298 if (security_getenforce() == 1) {
e51bc1a2 299 r = -errno;
f13e30d2 300 goto finish;
e51bc1a2
LP
301 }
302 }
303
f13e30d2
LP
304 r = mkdir(path, mode);
305 if (r < 0)
e51bc1a2
LP
306 r = -errno;
307
308finish:
f13e30d2
LP
309 setfscreatecon(NULL);
310 freecon(fcon);
311
312 return r;
313
314skipped:
315#endif
316 return mkdir(path, mode) < 0 ? -errno : 0;
317}
318
319int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
320
321 /* Binds a socket and label its file system object according to the SELinux policy */
322
323#ifdef HAVE_SELINUX
324 int r;
325 security_context_t fcon = NULL;
326 const struct sockaddr_un *un;
327 char *path = NULL;
328
329 assert(fd >= 0);
330 assert(addr);
331 assert(addrlen >= sizeof(sa_family_t));
332
333 if (!use_selinux() || !label_hnd)
334 goto skipped;
335
336 /* Filter out non-local sockets */
337 if (addr->sa_family != AF_UNIX)
338 goto skipped;
339
340 /* Filter out anonymous sockets */
341 if (addrlen < sizeof(sa_family_t) + 1)
342 goto skipped;
343
344 /* Filter out abstract namespace sockets */
345 un = (const struct sockaddr_un*) addr;
346 if (un->sun_path[0] == 0)
347 goto skipped;
348
349 path = strndup(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
350 if (!path)
351 return -ENOMEM;
352
353 if (path_is_absolute(path))
382241ee 354 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
f13e30d2
LP
355 else {
356 char *newpath;
357
358 newpath = path_make_absolute_cwd(path);
359
360 if (!newpath) {
361 free(path);
362 return -ENOMEM;
363 }
364
382241ee 365 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
f13e30d2 366 free(newpath);
e51bc1a2
LP
367 }
368
f13e30d2
LP
369 if (r == 0)
370 r = setfscreatecon(fcon);
371
372 if (r < 0 && errno != ENOENT) {
373 log_error("Failed to set security context %s for %s: %m", fcon, path);
374
375 if (security_getenforce() == 1) {
376 r = -errno;
377 goto finish;
378 }
379 }
380
381 r = bind(fd, addr, addrlen);
382 if (r < 0)
383 r = -errno;
384
385finish:
386 setfscreatecon(NULL);
387 freecon(fcon);
388 free(path);
389
e51bc1a2 390 return r;
f13e30d2
LP
391
392skipped:
e51bc1a2 393#endif
f13e30d2 394 return bind(fd, addr, addrlen) < 0 ? -errno : 0;
e51bc1a2 395}