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