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