]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/smack-setup.c
Merge pull request #538 from mischief/multiple-routers
[thirdparty/systemd.git] / src / core / smack-setup.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright (C) 2013 Intel Corporation
7 Authors:
8 Nathaniel Chen <nathaniel.chen@intel.com>
9
10 systemd is free software; you can redistribute it and/or modify it
11 under the terms of the GNU Lesser General Public License as published
12 by the Free Software Foundation; either version 2.1 of the License,
13 or (at your option) any later version.
14
15 systemd is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 ***/
23
24 #include <stdio.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include <dirent.h>
30
31 #include "macro.h"
32 #include "smack-setup.h"
33 #include "util.h"
34 #include "fileio.h"
35 #include "log.h"
36
37 #ifdef HAVE_SMACK
38
39 static int write_access2_rules(const char* srcdir) {
40 _cleanup_close_ int load2_fd = -1, change_fd = -1;
41 _cleanup_closedir_ DIR *dir = NULL;
42 struct dirent *entry;
43 char buf[NAME_MAX];
44 int dfd = -1;
45 int r = 0;
46
47 load2_fd = open("/sys/fs/smackfs/load2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
48 if (load2_fd < 0) {
49 if (errno != ENOENT)
50 log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/load2': %m");
51 return -errno; /* negative error */
52 }
53
54 change_fd = open("/sys/fs/smackfs/change-rule", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
55 if (change_fd < 0) {
56 if (errno != ENOENT)
57 log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/change-rule': %m");
58 return -errno; /* negative error */
59 }
60
61 /* write rules to load2 or change-rule from every file in the directory */
62 dir = opendir(srcdir);
63 if (!dir) {
64 if (errno != ENOENT)
65 log_warning_errno(errno, "Failed to opendir '%s': %m", srcdir);
66 return errno; /* positive on purpose */
67 }
68
69 dfd = dirfd(dir);
70 assert(dfd >= 0);
71
72 FOREACH_DIRENT(entry, dir, return 0) {
73 int fd;
74 _cleanup_fclose_ FILE *policy = NULL;
75
76 if (!dirent_is_file(entry))
77 continue;
78
79 fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
80 if (fd < 0) {
81 if (r == 0)
82 r = -errno;
83 log_warning_errno(errno, "Failed to open '%s': %m", entry->d_name);
84 continue;
85 }
86
87 policy = fdopen(fd, "re");
88 if (!policy) {
89 if (r == 0)
90 r = -errno;
91 safe_close(fd);
92 log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
93 continue;
94 }
95
96 /* load2 write rules in the kernel require a line buffered stream */
97 FOREACH_LINE(buf, policy,
98 log_error_errno(errno, "Failed to read line from '%s': %m",
99 entry->d_name)) {
100
101 _cleanup_free_ char *sbj = NULL, *obj = NULL, *acc1 = NULL, *acc2 = NULL;
102
103 if (isempty(truncate_nl(buf)))
104 continue;
105
106 /* if 3 args -> load rule : subject object access1 */
107 /* if 4 args -> change rule : subject object access1 access2 */
108 if (sscanf(buf, "%ms %ms %ms %ms", &sbj, &obj, &acc1, &acc2) < 3) {
109 log_error_errno(errno, "Failed to parse rule '%s' in '%s', ignoring.", buf, entry->d_name);
110 continue;
111 }
112
113 if (write(isempty(acc2) ? load2_fd : change_fd, buf, strlen(buf)) < 0) {
114 if (r == 0)
115 r = -errno;
116 log_error_errno(errno, "Failed to write '%s' to '%s' in '%s'",
117 buf, isempty(acc2) ? "/sys/fs/smackfs/load2" : "/sys/fs/smackfs/change-rule", entry->d_name);
118 }
119 }
120 }
121
122 return r;
123 }
124
125 static int write_cipso2_rules(const char* srcdir) {
126 _cleanup_close_ int cipso2_fd = -1;
127 _cleanup_closedir_ DIR *dir = NULL;
128 struct dirent *entry;
129 char buf[NAME_MAX];
130 int dfd = -1;
131 int r = 0;
132
133 cipso2_fd = open("/sys/fs/smackfs/cipso2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
134 if (cipso2_fd < 0) {
135 if (errno != ENOENT)
136 log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/cipso2': %m");
137 return -errno; /* negative error */
138 }
139
140 /* write rules to cipso2 from every file in the directory */
141 dir = opendir(srcdir);
142 if (!dir) {
143 if (errno != ENOENT)
144 log_warning_errno(errno, "Failed to opendir '%s': %m", srcdir);
145 return errno; /* positive on purpose */
146 }
147
148 dfd = dirfd(dir);
149 assert(dfd >= 0);
150
151 FOREACH_DIRENT(entry, dir, return 0) {
152 int fd;
153 _cleanup_fclose_ FILE *policy = NULL;
154
155 if (!dirent_is_file(entry))
156 continue;
157
158 fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
159 if (fd < 0) {
160 if (r == 0)
161 r = -errno;
162 log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
163 continue;
164 }
165
166 policy = fdopen(fd, "re");
167 if (!policy) {
168 if (r == 0)
169 r = -errno;
170 safe_close(fd);
171 log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
172 continue;
173 }
174
175 /* cipso2 write rules in the kernel require a line buffered stream */
176 FOREACH_LINE(buf, policy,
177 log_error_errno(errno, "Failed to read line from '%s': %m",
178 entry->d_name)) {
179
180 if (isempty(truncate_nl(buf)))
181 continue;
182
183 if (write(cipso2_fd, buf, strlen(buf)) < 0) {
184 if (r == 0)
185 r = -errno;
186 log_error_errno(errno, "Failed to write '%s' to '/sys/fs/smackfs/cipso2' in '%s'",
187 buf, entry->d_name);
188 break;
189 }
190 }
191 }
192
193 return r;
194 }
195
196 #endif
197
198 int mac_smack_setup(bool *loaded_policy) {
199
200 #ifdef HAVE_SMACK
201
202 int r;
203
204 assert(loaded_policy);
205
206 r = write_access2_rules("/etc/smack/accesses.d/");
207 switch(r) {
208 case -ENOENT:
209 log_debug("Smack is not enabled in the kernel.");
210 return 0;
211 case ENOENT:
212 log_debug("Smack access rules directory '/etc/smack/accesses.d/' not found");
213 return 0;
214 case 0:
215 log_info("Successfully loaded Smack policies.");
216 break;
217 default:
218 log_warning("Failed to load Smack access rules: %s, ignoring.",
219 strerror(abs(r)));
220 return 0;
221 }
222
223 #ifdef SMACK_RUN_LABEL
224 r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0);
225 if (r)
226 log_warning("Failed to set SMACK label \"%s\" on self: %s",
227 SMACK_RUN_LABEL, strerror(-r));
228 #endif
229
230 r = write_cipso2_rules("/etc/smack/cipso.d/");
231 switch(r) {
232 case -ENOENT:
233 log_debug("Smack/CIPSO is not enabled in the kernel.");
234 return 0;
235 case ENOENT:
236 log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
237 return 0;
238 case 0:
239 log_info("Successfully loaded Smack/CIPSO policies.");
240 break;
241 default:
242 log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.",
243 strerror(abs(r)));
244 return 0;
245 }
246
247 *loaded_policy = true;
248
249 #endif
250
251 return 0;
252 }