chiark / gitweb /
core: add new ConditionArchitecture() that checks the architecture returned by uname...
[elogind.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())
141                 return;
142
143         if (label_hnd)
144                 selabel_close(label_hnd);
145 #endif
146 }
147
148 int label_get_create_label_from_exe(const char *exe, char **label) {
149
150         int r = 0;
151
152 #ifdef HAVE_SELINUX
153         security_context_t mycon = NULL, fcon = NULL;
154         security_class_t sclass;
155
156         if (!use_selinux()) {
157                 *label = NULL;
158                 return 0;
159         }
160
161         r = getcon(&mycon);
162         if (r < 0)
163                 goto fail;
164
165         r = getfilecon(exe, &fcon);
166         if (r < 0)
167                 goto fail;
168
169         sclass = string_to_security_class("process");
170         r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
171         if (r == 0)
172                 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
173
174 fail:
175         if (r < 0 && security_getenforce() == 1)
176                 r = -errno;
177
178         freecon(mycon);
179         freecon(fcon);
180 #endif
181
182         return r;
183 }
184
185 int label_context_set(const char *path, mode_t mode) {
186         int r = 0;
187
188 #ifdef HAVE_SELINUX
189         security_context_t filecon = NULL;
190
191         if (!use_selinux() || !label_hnd)
192                 return 0;
193
194         r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
195         if (r < 0 && errno != ENOENT)
196                 r = -errno;
197         else if (r == 0) {
198                 r = setfscreatecon(filecon);
199                 if (r < 0) {
200                         log_error("Failed to set SELinux file context on %s: %m", path);
201                         r = -errno;
202                 }
203
204                 freecon(filecon);
205         }
206
207         if (r < 0 && security_getenforce() == 0)
208                 r = 0;
209 #endif
210
211         return r;
212 }
213
214 int label_socket_set(const char *label) {
215
216 #ifdef HAVE_SELINUX
217         if (!use_selinux())
218                 return 0;
219
220         if (setsockcreatecon((security_context_t) label) < 0) {
221                 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
222                          "Failed to set SELinux context (%s) on socket: %m", label);
223
224                 if (security_getenforce() == 1)
225                         return -errno;
226         }
227 #endif
228
229         return 0;
230 }
231
232 void label_context_clear(void) {
233
234 #ifdef HAVE_SELINUX
235         if (!use_selinux())
236                 return;
237
238         setfscreatecon(NULL);
239 #endif
240 }
241
242 void label_socket_clear(void) {
243
244 #ifdef HAVE_SELINUX
245         if (!use_selinux())
246                 return;
247
248         setsockcreatecon(NULL);
249 #endif
250 }
251
252 void label_free(const char *label) {
253
254 #ifdef HAVE_SELINUX
255         if (!use_selinux())
256                 return;
257
258         freecon((security_context_t) label);
259 #endif
260 }
261
262 int label_mkdir(const char *path, mode_t mode) {
263
264         /* Creates a directory and labels it according to the SELinux policy */
265 #ifdef HAVE_SELINUX
266         security_context_t fcon = NULL;
267         int r;
268
269         if (!use_selinux() || !label_hnd)
270                 goto skipped;
271
272         if (path_is_absolute(path))
273                 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR);
274         else {
275                 _cleanup_free_ char *newpath;
276
277                 newpath = path_make_absolute_cwd(path);
278                 if (!newpath)
279                         return -ENOMEM;
280
281                 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR);
282         }
283
284         if (r == 0)
285                 r = setfscreatecon(fcon);
286
287         if (r < 0 && errno != ENOENT) {
288                 log_error("Failed to set security context %s for %s: %m", fcon, path);
289
290                 if (security_getenforce() == 1) {
291                         r = -errno;
292                         goto finish;
293                 }
294         }
295
296         r = mkdir(path, mode);
297         if (r < 0)
298                 r = -errno;
299
300 finish:
301         setfscreatecon(NULL);
302         freecon(fcon);
303
304         return r;
305
306 skipped:
307 #endif
308         return mkdir(path, mode) < 0 ? -errno : 0;
309 }
310
311 int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
312
313         /* Binds a socket and label its file system object according to the SELinux policy */
314
315 #ifdef HAVE_SELINUX
316         security_context_t fcon = NULL;
317         const struct sockaddr_un *un;
318         char *path;
319         int r;
320
321         assert(fd >= 0);
322         assert(addr);
323         assert(addrlen >= sizeof(sa_family_t));
324
325         if (!use_selinux() || !label_hnd)
326                 goto skipped;
327
328         /* Filter out non-local sockets */
329         if (addr->sa_family != AF_UNIX)
330                 goto skipped;
331
332         /* Filter out anonymous sockets */
333         if (addrlen < sizeof(sa_family_t) + 1)
334                 goto skipped;
335
336         /* Filter out abstract namespace sockets */
337         un = (const struct sockaddr_un*) addr;
338         if (un->sun_path[0] == 0)
339                 goto skipped;
340
341         path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
342
343         if (path_is_absolute(path))
344                 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
345         else {
346                 _cleanup_free_ char *newpath;
347
348                 newpath = path_make_absolute_cwd(path);
349                 if (!newpath)
350                         return -ENOMEM;
351
352                 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
353         }
354
355         if (r == 0)
356                 r = setfscreatecon(fcon);
357
358         if (r < 0 && errno != ENOENT) {
359                 log_error("Failed to set security context %s for %s: %m", fcon, path);
360
361                 if (security_getenforce() == 1) {
362                         r = -errno;
363                         goto finish;
364                 }
365         }
366
367         r = bind(fd, addr, addrlen);
368         if (r < 0)
369                 r = -errno;
370
371 finish:
372         setfscreatecon(NULL);
373         freecon(fcon);
374
375         return r;
376
377 skipped:
378 #endif
379         return bind(fd, addr, addrlen) < 0 ? -errno : 0;
380 }
381
382 int label_apply(const char *path, const char *label) {
383         int r = 0;
384
385 #ifdef HAVE_SELINUX
386         if (!use_selinux())
387                 return 0;
388
389         r = setfilecon(path, (char *)label);
390 #endif
391         return r;
392 }