chiark / gitweb /
selinux: retest selinux after we loaded the policy
[elogind.git] / src / 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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
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>
25 #include <malloc.h>
26
27 #include "label.h"
28 #include "util.h"
29
30 #ifdef HAVE_SELINUX
31 #include <selinux/selinux.h>
32 #include <selinux/label.h>
33
34 static struct selabel_handle *label_hnd = NULL;
35
36 static int use_selinux_cached = -1;
37
38 static inline bool use_selinux(void) {
39
40         if (use_selinux_cached < 0)
41                 use_selinux_cached = is_selinux_enabled() > 0;
42
43         return use_selinux_cached;
44 }
45
46 void label_retest_selinux(void) {
47         use_selinux_cached = -1;
48 }
49
50 #endif
51
52 int label_init(void) {
53         int r = 0;
54
55 #ifdef HAVE_SELINUX
56         usec_t before_timestamp, after_timestamp;
57         struct mallinfo before_mallinfo, after_mallinfo;
58
59         if (!use_selinux())
60                 return 0;
61
62         if (label_hnd)
63                 return 0;
64
65         before_mallinfo = mallinfo();
66         before_timestamp = now(CLOCK_MONOTONIC);
67
68         label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
69         if (!label_hnd) {
70                 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
71                          "Failed to initialize SELinux context: %m");
72                 r = security_getenforce() == 1 ? -errno : 0;
73         } else  {
74                 char timespan[FORMAT_TIMESPAN_MAX];
75                 int l;
76
77                 after_timestamp = now(CLOCK_MONOTONIC);
78                 after_mallinfo = mallinfo();
79
80                 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
81
82                 log_info("Successfully loaded SELinux database in %s, size on heap is %iK.",
83                          format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp),
84                          (l+1023)/1024);
85         }
86 #endif
87
88         return r;
89 }
90
91 int label_fix(const char *path, bool ignore_enoent) {
92         int r = 0;
93
94 #ifdef HAVE_SELINUX
95         struct stat st;
96         security_context_t fcon;
97
98         if (!use_selinux() || !label_hnd)
99                 return 0;
100
101         r = lstat(path, &st);
102         if (r == 0) {
103                 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
104
105                 /* If there's no label to set, then exit without warning */
106                 if (r < 0 && errno == ENOENT)
107                         return 0;
108
109                 if (r == 0) {
110                         r = setfilecon(path, fcon);
111                         freecon(fcon);
112
113                         /* If the FS doesn't support labels, then exit without warning */
114                         if (r < 0 && errno == ENOTSUP)
115                                 return 0;
116                 }
117         }
118
119         if (r < 0) {
120                 /* Ignore ENOENT in some cases */
121                 if (ignore_enoent && errno == ENOENT)
122                         return 0;
123
124                 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
125                          "Unable to fix label of %s: %m", path);
126                 r = security_getenforce() == 1 ? -errno : 0;
127         }
128 #endif
129
130         return r;
131 }
132
133 void label_finish(void) {
134
135 #ifdef HAVE_SELINUX
136         if (use_selinux() && label_hnd)
137                 selabel_close(label_hnd);
138 #endif
139 }
140
141 int label_get_create_label_from_exe(const char *exe, char **label) {
142
143         int r = 0;
144
145 #ifdef HAVE_SELINUX
146         security_context_t mycon = NULL, fcon = NULL;
147         security_class_t sclass;
148
149         if (!use_selinux()) {
150                 *label = NULL;
151                 return 0;
152         }
153
154         r = getcon(&mycon);
155         if (r < 0)
156                 goto fail;
157
158         r = getfilecon(exe, &fcon);
159         if (r < 0)
160                 goto fail;
161
162         sclass = string_to_security_class("process");
163         r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
164         if (r == 0)
165                 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
166
167 fail:
168         if (r < 0 && security_getenforce() == 1)
169                 r = -errno;
170
171         freecon(mycon);
172         freecon(fcon);
173 #endif
174
175         return r;
176 }
177
178 int label_fifofile_set(const char *path) {
179         int r = 0;
180
181 #ifdef HAVE_SELINUX
182         security_context_t filecon = NULL;
183
184         if (!use_selinux() || !label_hnd)
185                 return 0;
186
187         if ((r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFIFO)) == 0) {
188                 if ((r = setfscreatecon(filecon)) < 0) {
189                         log_error("Failed to set SELinux file context on %s: %m", path);
190                         r = -errno;
191                 }
192
193                 freecon(filecon);
194         }
195
196         if (r < 0 && security_getenforce() == 0)
197                 r = 0;
198 #endif
199
200         return r;
201 }
202
203 int label_symlinkfile_set(const char *path) {
204         int r = 0;
205
206 #ifdef HAVE_SELINUX
207         security_context_t filecon = NULL;
208
209         if (!use_selinux() || !label_hnd)
210                 return 0;
211
212         if ((r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFLNK)) == 0) {
213                 if ((r = setfscreatecon(filecon)) < 0) {
214                         log_error("Failed to set SELinux file context on %s: %m", path);
215                         r = -errno;
216                 }
217
218                 freecon(filecon);
219         }
220
221         if (r < 0 && security_getenforce() == 0)
222                 r = 0;
223 #endif
224
225         return r;
226 }
227
228 int label_socket_set(const char *label) {
229
230 #ifdef HAVE_SELINUX
231         if (!use_selinux())
232                 return 0;
233
234         if (setsockcreatecon((security_context_t) label) < 0) {
235                 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
236                          "Failed to set SELinux context (%s) on socket: %m", label);
237
238                 if (security_getenforce() == 1)
239                         return -errno;
240         }
241 #endif
242
243         return 0;
244 }
245
246 void label_file_clear(void) {
247
248 #ifdef HAVE_SELINUX
249         if (!use_selinux())
250                 return;
251
252         setfscreatecon(NULL);
253 #endif
254 }
255
256 void label_socket_clear(void) {
257
258 #ifdef HAVE_SELINUX
259         if (!use_selinux())
260                 return;
261
262         setsockcreatecon(NULL);
263 #endif
264 }
265
266 void label_free(const char *label) {
267
268 #ifdef HAVE_SELINUX
269         if (!use_selinux())
270                 return;
271
272         freecon((security_context_t) label);
273 #endif
274 }
275
276 int label_mkdir(
277         const char *path,
278         mode_t mode) {
279
280         /* Creates a directory and labels it according to the SELinux policy */
281
282 #ifdef HAVE_SELINUX
283         int r;
284         security_context_t fcon = NULL;
285
286         if (use_selinux() && label_hnd) {
287
288                 if (path_is_absolute(path))
289                         r = selabel_lookup_raw(label_hnd, &fcon, path, mode);
290                 else {
291                         char *newpath = NULL;
292
293                         if (!(newpath = path_make_absolute_cwd(path)))
294                                 return -ENOMEM;
295
296                         r = selabel_lookup_raw(label_hnd, &fcon, newpath, mode);
297                         free(newpath);
298                 }
299
300                 if (r == 0)
301                         r = setfscreatecon(fcon);
302
303                 if (r < 0 && errno != ENOENT) {
304                         log_error("Failed to set security context %s for %s: %m", fcon, path);
305                         r = -errno;
306
307                         if (security_getenforce() == 1)
308                                 goto finish;
309                 }
310         }
311
312         if ((r = mkdir(path, mode)) < 0)
313                 r = -errno;
314
315 finish:
316         if (use_selinux() && label_hnd) {
317                 setfscreatecon(NULL);
318                 freecon(fcon);
319         }
320
321         return r;
322 #else
323         return mkdir(path, mode);
324 #endif
325 }