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