]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/smack-setup.c
util-lib: introduce dirent-util.[ch] for directory entry calls
[thirdparty/systemd.git] / src / core / smack-setup.c
CommitLineData
ffbd2c4d
NC
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
07630cea 24#include <dirent.h>
ffbd2c4d 25#include <errno.h>
ffbd2c4d 26#include <fcntl.h>
07630cea
LP
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
ffbd2c4d 30
a0956174 31#include "dirent-util.h"
3ffd4af2 32#include "fd-util.h"
8b197c3a 33#include "fileio.h"
ffbd2c4d 34#include "log.h"
07630cea 35#include "macro.h"
3ffd4af2 36#include "smack-setup.h"
07630cea
LP
37#include "string-util.h"
38#include "util.h"
ffbd2c4d 39
2b3e18de
KL
40#ifdef HAVE_SMACK
41
6656aefb
WC
42static int write_access2_rules(const char* srcdir) {
43 _cleanup_close_ int load2_fd = -1, change_fd = -1;
ffbd2c4d
NC
44 _cleanup_closedir_ DIR *dir = NULL;
45 struct dirent *entry;
46 char buf[NAME_MAX];
47 int dfd = -1;
a4783bd1 48 int r = 0;
ffbd2c4d 49
6656aefb
WC
50 load2_fd = open("/sys/fs/smackfs/load2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
51 if (load2_fd < 0) {
52 if (errno != ENOENT)
53 log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/load2': %m");
54 return -errno; /* negative error */
55 }
56
57 change_fd = open("/sys/fs/smackfs/change-rule", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
58 if (change_fd < 0) {
a4783bd1 59 if (errno != ENOENT)
6656aefb 60 log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/change-rule': %m");
a4783bd1 61 return -errno; /* negative error */
ffbd2c4d
NC
62 }
63
6656aefb 64 /* write rules to load2 or change-rule from every file in the directory */
a4783bd1 65 dir = opendir(srcdir);
ffbd2c4d 66 if (!dir) {
a4783bd1 67 if (errno != ENOENT)
6656aefb 68 log_warning_errno(errno, "Failed to opendir '%s': %m", srcdir);
a4783bd1 69 return errno; /* positive on purpose */
ffbd2c4d
NC
70 }
71
72 dfd = dirfd(dir);
fea7838e 73 assert(dfd >= 0);
ffbd2c4d
NC
74
75 FOREACH_DIRENT(entry, dir, return 0) {
a4783bd1 76 int fd;
ffbd2c4d 77 _cleanup_fclose_ FILE *policy = NULL;
ffbd2c4d 78
6656aefb
WC
79 if (!dirent_is_file(entry))
80 continue;
81
a4783bd1
ZJS
82 fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
83 if (fd < 0) {
84 if (r == 0)
85 r = -errno;
6656aefb 86 log_warning_errno(errno, "Failed to open '%s': %m", entry->d_name);
ffbd2c4d
NC
87 continue;
88 }
89
a4783bd1 90 policy = fdopen(fd, "re");
ffbd2c4d 91 if (!policy) {
a4783bd1
ZJS
92 if (r == 0)
93 r = -errno;
03e334a1 94 safe_close(fd);
6656aefb 95 log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
ffbd2c4d
NC
96 continue;
97 }
98
ffbd2c4d 99 /* load2 write rules in the kernel require a line buffered stream */
fea7838e 100 FOREACH_LINE(buf, policy,
6656aefb
WC
101 log_error_errno(errno, "Failed to read line from '%s': %m",
102 entry->d_name)) {
103
104 _cleanup_free_ char *sbj = NULL, *obj = NULL, *acc1 = NULL, *acc2 = NULL;
105
106 if (isempty(truncate_nl(buf)))
107 continue;
108
109 /* if 3 args -> load rule : subject object access1 */
110 /* if 4 args -> change rule : subject object access1 access2 */
111 if (sscanf(buf, "%ms %ms %ms %ms", &sbj, &obj, &acc1, &acc2) < 3) {
112 log_error_errno(errno, "Failed to parse rule '%s' in '%s', ignoring.", buf, entry->d_name);
113 continue;
114 }
115
116 if (write(isempty(acc2) ? load2_fd : change_fd, buf, strlen(buf)) < 0) {
a4783bd1 117 if (r == 0)
6656aefb
WC
118 r = -errno;
119 log_error_errno(errno, "Failed to write '%s' to '%s' in '%s'",
120 buf, isempty(acc2) ? "/sys/fs/smackfs/load2" : "/sys/fs/smackfs/change-rule", entry->d_name);
a4783bd1 121 }
6656aefb
WC
122 }
123 }
124
125 return r;
126}
127
128static int write_cipso2_rules(const char* srcdir) {
129 _cleanup_close_ int cipso2_fd = -1;
130 _cleanup_closedir_ DIR *dir = NULL;
131 struct dirent *entry;
132 char buf[NAME_MAX];
133 int dfd = -1;
134 int r = 0;
135
136 cipso2_fd = open("/sys/fs/smackfs/cipso2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
137 if (cipso2_fd < 0) {
138 if (errno != ENOENT)
139 log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/cipso2': %m");
140 return -errno; /* negative error */
141 }
142
143 /* write rules to cipso2 from every file in the directory */
144 dir = opendir(srcdir);
145 if (!dir) {
146 if (errno != ENOENT)
147 log_warning_errno(errno, "Failed to opendir '%s': %m", srcdir);
148 return errno; /* positive on purpose */
149 }
150
151 dfd = dirfd(dir);
152 assert(dfd >= 0);
153
154 FOREACH_DIRENT(entry, dir, return 0) {
155 int fd;
156 _cleanup_fclose_ FILE *policy = NULL;
157
158 if (!dirent_is_file(entry))
159 continue;
160
161 fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
162 if (fd < 0) {
163 if (r == 0)
164 r = -errno;
165 log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
166 continue;
167 }
168
169 policy = fdopen(fd, "re");
170 if (!policy) {
171 if (r == 0)
172 r = -errno;
173 safe_close(fd);
174 log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
175 continue;
176 }
177
178 /* cipso2 write rules in the kernel require a line buffered stream */
179 FOREACH_LINE(buf, policy,
180 log_error_errno(errno, "Failed to read line from '%s': %m",
181 entry->d_name)) {
182
183 if (isempty(truncate_nl(buf)))
184 continue;
185
186 if (write(cipso2_fd, buf, strlen(buf)) < 0) {
a4783bd1
ZJS
187 if (r == 0)
188 r = -errno;
6656aefb
WC
189 log_error_errno(errno, "Failed to write '%s' to '/sys/fs/smackfs/cipso2' in '%s'",
190 buf, entry->d_name);
a4783bd1
ZJS
191 break;
192 }
ffbd2c4d
NC
193 }
194 }
195
6656aefb 196 return r;
a4783bd1
ZJS
197}
198
2b3e18de 199#endif
ffbd2c4d 200
8a188de9 201int mac_smack_setup(bool *loaded_policy) {
2b3e18de
KL
202
203#ifdef HAVE_SMACK
204
a4783bd1
ZJS
205 int r;
206
e49d3c01
ŁS
207 assert(loaded_policy);
208
6656aefb 209 r = write_access2_rules("/etc/smack/accesses.d/");
a4783bd1
ZJS
210 switch(r) {
211 case -ENOENT:
212 log_debug("Smack is not enabled in the kernel.");
213 return 0;
214 case ENOENT:
6656aefb 215 log_debug("Smack access rules directory '/etc/smack/accesses.d/' not found");
a4783bd1
ZJS
216 return 0;
217 case 0:
218 log_info("Successfully loaded Smack policies.");
abbacb1d
NC
219 break;
220 default:
e53fc357 221 log_warning_errno(r, "Failed to load Smack access rules, ignoring: %m");
abbacb1d
NC
222 return 0;
223 }
224
8b197c3a 225#ifdef SMACK_RUN_LABEL
4c1fc3e4 226 r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0);
8b197c3a 227 if (r)
23446f01 228 log_warning_errno(r, "Failed to set SMACK label \"%s\" on self: %m", SMACK_RUN_LABEL);
8b197c3a
AK
229#endif
230
6656aefb 231 r = write_cipso2_rules("/etc/smack/cipso.d/");
abbacb1d
NC
232 switch(r) {
233 case -ENOENT:
234 log_debug("Smack/CIPSO is not enabled in the kernel.");
235 return 0;
236 case ENOENT:
6656aefb 237 log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
abbacb1d
NC
238 return 0;
239 case 0:
240 log_info("Successfully loaded Smack/CIPSO policies.");
b9289d4c 241 break;
a4783bd1 242 default:
e53fc357 243 log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m");
a4783bd1
ZJS
244 return 0;
245 }
2b3e18de 246
e49d3c01
ŁS
247 *loaded_policy = true;
248
2b3e18de
KL
249#endif
250
251 return 0;
ffbd2c4d 252}