source code open - smack
[framework/security/smack.git] / utils / common.c
1 /*
2  * This file is part of libsmack.
3  *
4  * Copyright (C) 2011 Intel Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * version 2.1 as published by the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA
19  *
20  * Authors:
21  * Jarkko Sakkinen <jarkko.sakkinen@intel.com>
22  * Brian McGillion <brian.mcgillion@intel.com>
23  */
24
25 #include "common.h"
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <sys/vfs.h>
31 #include <fcntl.h>
32 #include <sys/smack.h>
33 #include <ftw.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #define SMACKFS_MAGIC 0x43415d53
39 #define CAT_MAX_COUNT 240
40 #define CAT_MAX_VALUE 63
41 #define LEVEL_MAX 255
42 #define NUM_LEN 4
43
44 #define CIPSO_POS(i)   (SMACK_LABEL_LEN + 1 + NUM_LEN + NUM_LEN + i * NUM_LEN)
45 #define CIPSO_MAX_SIZE CIPSO_POS(CAT_MAX_COUNT)
46 #define CIPSO_NUM_LEN_STR "%-4d"
47
48 #define BUF_SIZE 512
49
50 struct cipso_mapping {
51         char label[SMACK_LABEL_LEN + 1];
52         int cats[CAT_MAX_VALUE];
53         int ncats;
54         int level;
55         struct cipso_mapping *next;
56 };
57
58 struct cipso {
59         struct cipso_mapping *first;
60         struct cipso_mapping *last;
61 };
62
63 static int apply_rules_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
64 static int apply_cipso_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
65 static struct cipso *cipso_new(int fd);
66 static void cipso_free(struct cipso *cipso);
67 static int cipso_apply(struct cipso *cipso);
68
69 int is_smackfs_mounted(void)
70 {
71         struct statfs sfs;
72         int ret;
73
74         do {
75                 ret = statfs(SMACKFS_MNT, &sfs);
76         } while (ret < 0 && errno == EINTR);
77
78         if (ret)
79                 return -1;
80
81         if (sfs.f_type == SMACKFS_MAGIC)
82                 return 1;
83
84         return 0;
85 }
86
87 int clear(void)
88 {
89         int fd;
90         int ret;
91
92         if (is_smackfs_mounted() != 1)
93                 return -1;
94
95         fd = open(SMACKFS_MNT "/load2", O_RDONLY);
96         if (fd < 0)
97                 return -1;
98
99         ret = apply_rules_file(fd, 1);
100         close(fd);
101         return ret;
102 }
103
104 int apply_rules(const char *path, int clear)
105 {
106         struct stat sbuf;
107         int fd;
108         int ret;
109
110         errno = 0;
111         if (stat(path, &sbuf))
112                 return -1;
113
114         if (S_ISDIR(sbuf.st_mode))
115                 return nftw(path, apply_rules_cb, 1, FTW_PHYS|FTW_ACTIONRETVAL);
116
117         fd = open(path, O_RDONLY);
118         if (fd < 0)
119                 return -1;
120
121         ret = apply_rules_file(fd, clear);
122         close(fd);
123         return ret;
124 }
125
126 int apply_cipso(const char *path)
127 {
128         struct stat sbuf;
129         int fd;
130         int ret;
131
132         errno = 0;
133         if (stat(path, &sbuf))
134                 return -1;
135
136         if (S_ISDIR(sbuf.st_mode))
137                 return nftw(path, apply_cipso_cb, 1, FTW_PHYS|FTW_ACTIONRETVAL);
138
139         fd = open(path, O_RDONLY);
140         if (fd < 0)
141                 return -1;
142
143         ret = apply_cipso_file(fd);
144         close(fd);
145         return ret;
146 }
147
148 int apply_rules_file(int fd, int clear)
149 {
150         struct smack_accesses *rules = NULL;
151         int ret = 0;
152
153         if (smack_accesses_new(&rules))
154                 return -1;
155
156         if (smack_accesses_add_from_file(rules, fd)) {
157                 smack_accesses_free(rules);
158                 return -1;
159         }
160
161         if (!clear)
162                 ret = smack_accesses_apply(rules);
163         else
164                 ret = smack_accesses_clear(rules);
165
166         smack_accesses_free(rules);
167
168         return ret;
169 }
170
171 int apply_cipso_file(int fd)
172 {
173         struct cipso *cipso = NULL;
174         int ret;
175
176         cipso = cipso_new(fd);
177         if (cipso == NULL)
178                 return -1;
179
180         ret = cipso_apply(cipso);
181         cipso_free(cipso);
182         if (ret)
183                 return -1;
184
185         return 0;
186 }
187
188 static int apply_rules_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
189 {
190         int fd;
191         int ret;
192
193         if (typeflag == FTW_D)
194                 return ftwbuf->level ? FTW_SKIP_SUBTREE : FTW_CONTINUE;
195         else if (typeflag != FTW_F)
196                 return FTW_STOP;
197
198         fd = open(fpath, O_RDONLY);
199         if (fd < 0)
200                 return -1;
201
202         ret = apply_rules_file(fd, 0) ? FTW_STOP : FTW_CONTINUE;
203         close(fd);
204         return ret;
205 }
206
207 static int apply_cipso_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
208 {
209         int fd;
210         int ret;
211
212         if (typeflag == FTW_D)
213                 return ftwbuf->level ? FTW_SKIP_SUBTREE : FTW_CONTINUE;
214         else if (typeflag != FTW_F)
215                 return FTW_STOP;
216
217         fd = open(fpath, O_RDONLY);
218         if (fd < 0)
219                 return -1;
220
221         ret = apply_rules_file(fd, 0) ? FTW_STOP : FTW_CONTINUE;
222         close(fd);
223         return ret;
224 }
225
226 static struct cipso *cipso_new(int fd)
227 {
228         struct cipso *cipso = NULL;
229         struct cipso_mapping *mapping = NULL;
230         FILE *file = NULL;
231         char buf[BUF_SIZE];
232         char *label, *level, *cat, *ptr;
233         long int val;
234         int i;
235         int newfd;
236
237         newfd = dup(fd);
238         if (newfd == -1)
239                 return NULL;
240
241         file = fdopen(newfd, "r");
242         if (file == NULL) {
243                 close(newfd);
244                 return NULL;
245         }
246
247         cipso = calloc(sizeof(struct cipso), 1);
248         if (cipso == NULL) {
249                 fclose(file);
250                 return NULL;
251         }
252
253         while (fgets(buf, BUF_SIZE, file) != NULL) {
254                 mapping = calloc(sizeof(struct cipso_mapping), 1);
255                 if (mapping == NULL)
256                         goto err_out;
257
258                 label = strtok_r(buf, " \t\n", &ptr);
259                 level = strtok_r(NULL, " \t\n", &ptr);
260                 cat = strtok_r(NULL, " \t\n", &ptr);
261                 if (label == NULL || cat == NULL || level == NULL ||
262                     strlen(label) > SMACK_LABEL_LEN) {
263                         errno = EINVAL;
264                         goto err_out;
265                 }
266
267                 strcpy(mapping->label, label);
268
269                 errno = 0;
270                 val = strtol(level, NULL, 10);
271                 if (errno)
272                         goto err_out;
273
274                 if (val < 0 || val > LEVEL_MAX) {
275                         errno = ERANGE;
276                         goto err_out;
277                 }
278
279                 mapping->level = val;
280
281                 for (i = 0; i < CAT_MAX_COUNT && cat != NULL; i++) {
282                         errno = 0;
283                         val = strtol(cat, NULL, 10);
284                         if (errno)
285                                 goto err_out;
286
287                         if (val < 0 || val > CAT_MAX_VALUE) {
288                                 errno = ERANGE;
289                                 goto err_out;
290                         }
291
292                         mapping->cats[i] = val;
293
294                         cat = strtok_r(NULL, " \t\n", &ptr);
295                 }
296
297                 mapping->ncats = i;
298
299                 if (cipso->first == NULL) {
300                         cipso->first = cipso->last = mapping;
301                 } else {
302                         cipso->last->next = mapping;
303                         cipso->last = mapping;
304                 }
305         }
306
307         if (ferror(file))
308                 goto err_out;
309
310         fclose(file);
311         return cipso;
312 err_out:
313         fclose(file);
314         cipso_free(cipso);
315         free(mapping);
316         return NULL;
317 }
318
319 static void cipso_free(struct cipso *cipso)
320 {
321         if (cipso == NULL)
322                 return;
323
324         struct cipso_mapping *mapping = cipso->first;
325         struct cipso_mapping *next_mapping = NULL;
326
327         while (mapping != NULL) {
328                 next_mapping = mapping->next;
329                 free(mapping);
330                 mapping = next_mapping;
331         }
332 }
333
334 static int cipso_apply(struct cipso *cipso)
335 {
336         struct cipso_mapping *m = NULL;
337         char buf[CIPSO_MAX_SIZE];
338         int fd;
339         int i;
340
341         fd = open(SMACKFS_MNT "/cipso2", O_WRONLY);
342         if (fd < 0)
343                 return -1;
344
345         for (m = cipso->first; m != NULL; m = m->next) {
346                 sprintf(buf, "%s ", m->label);
347                 sprintf(&buf[SMACK_LABEL_LEN + 1], CIPSO_NUM_LEN_STR, m->level);
348                 sprintf(&buf[SMACK_LABEL_LEN + 1 + NUM_LEN], CIPSO_NUM_LEN_STR, m->ncats);
349
350                 for (i = 0; i < m->ncats; i++)
351                         sprintf(&buf[CIPSO_POS(i)], CIPSO_NUM_LEN_STR, m->cats[i]);
352
353                 if (write(fd, buf, strlen(buf)) < 0) {
354                         close(fd);
355                         return -1;
356                 }
357         }
358
359         close(fd);
360         return 0;
361 }