Added forgotten -Wall -Wextra compilation options and fixed
[framework/security/smack.git] / libsmack / libsmack.c
1 /*
2  * This file is part of libsmack
3  *
4  * Copyright (C) 2010 Nokia Corporation
5  * Copyright (C) 2011 Intel Corporation
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  *
21  * Authors:
22  * Jarkko Sakkinen <jarkko.sakkinen@intel.com>
23  * Brian McGillion <brian.mcgillion@intel.com>
24  */
25
26 #include "sys/smack.h"
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36
37 #define LABEL_LEN 23
38 #define LOAD_LEN (2 * (LABEL_LEN + 1) + ACC_LEN)
39 #define ACC_LEN 5
40
41 #define ACC_R 0x01
42 #define ACC_W 0x02
43 #define ACC_X 0x04
44 #define ACC_A 0x08
45 #define ACC_T 0x10
46
47 #define KERNEL_FORMAT "%-23s %-23s %5s"
48 #define READ_BUF_SIZE 512
49 #define SMACKFS_MNT "/smack"
50 #define SELF_LABEL_FILE "/proc/self/attr/current"
51
52 struct smack_rule {
53         char subject[LABEL_LEN + 1];
54         char object[LABEL_LEN + 1];
55         int access_code;
56         struct smack_rule *next;
57 };
58
59 struct smack_accesses {
60         struct smack_rule *first;
61         struct smack_rule *last;
62 };
63
64 static int accesses_apply(struct smack_accesses *handle, int clear);
65 static inline int access_type_to_int(const char *access_type);
66 static inline void int_to_access_type_c(unsigned ac, char *str);
67 static inline void int_to_access_type_k(unsigned ac, char *str);
68
69 int smack_accesses_new(struct smack_accesses **accesses)
70 {
71         struct smack_accesses *result;
72
73         result = calloc(sizeof(struct smack_accesses), 1);
74         if (result == NULL)
75                 return -1;
76
77         *accesses = result;
78         return 0;
79 }
80
81 int smack_accesses_new_from_file(int fd, struct smack_accesses **accesses)
82 {
83         struct smack_accesses *result = NULL;
84         FILE *file = NULL;
85         char buf[READ_BUF_SIZE];
86         char *ptr;
87         const char *subject, *object, *access;
88         int newfd;
89
90         if (smack_accesses_new(&result))
91                 goto err_out;
92
93         newfd = dup(fd);
94         if (newfd == -1)
95                 goto err_out;
96
97         file = fdopen(newfd, "r");
98         if (file == NULL) {
99                 close(newfd);
100                 goto err_out;
101         }
102
103         while (fgets(buf, READ_BUF_SIZE, file) != NULL) {
104                 subject = strtok_r(buf, " \t\n", &ptr);
105                 object = strtok_r(NULL, " \t\n", &ptr);
106                 access = strtok_r(NULL, " \t\n", &ptr);
107
108                 if (subject == NULL || object == NULL || access == NULL ||
109                     strtok_r(NULL, " \t\n", &ptr) != NULL) {
110                         errno = EINVAL;
111                         goto err_out;
112                 }
113
114                 if (smack_accesses_add(result, subject, object, access))
115                         goto err_out;
116         }
117
118         if (ferror(file))
119                 goto err_out;
120
121         fclose(file);
122         *accesses = result;
123         return 0;
124 err_out:
125         fclose(file);
126         smack_accesses_free(result);
127         return -1;
128 }
129
130 void smack_accesses_free(struct smack_accesses *handle)
131 {
132         if (handle == NULL)
133                 return;
134
135         struct smack_rule *rule = handle->first;
136         struct smack_rule *next_rule = NULL;
137
138         while (rule != NULL) {
139                 next_rule = rule->next;
140                 free(rule);
141                 rule = next_rule;
142         }
143
144         free(handle);
145 }
146
147 int smack_accesses_save(struct smack_accesses *handle, int fd)
148 {
149         struct smack_rule *rule = handle->first;
150         char access_type[ACC_LEN + 1];
151         FILE *file;
152         int ret;
153         int newfd;
154
155         newfd = dup(fd);
156         if (newfd == -1)
157                 return -1;
158
159         file = fdopen(newfd, "w");
160         if (file == NULL) {
161                 close(newfd);
162                 return -1;
163         }
164
165         while (rule) {
166                 int_to_access_type_c(rule->access_code, access_type);
167
168                 ret = fprintf(file, "%s %s %s\n",
169                               rule->subject, rule->object, access_type);
170                 if (ret < 0) {
171                         fclose(file);
172                         return -1;
173                 }
174
175                 rule = rule->next;
176         }
177
178         fclose(file);
179         return 0;
180 }
181
182 int smack_accesses_apply(struct smack_accesses *handle)
183 {
184         return accesses_apply(handle, 0);
185 }
186
187 int smack_accesses_clear(struct smack_accesses *handle)
188 {
189         return accesses_apply(handle, 1);
190 }
191
192 int smack_accesses_add(struct smack_accesses *handle, const char *subject,
193                        const char *object, const char *access_type)
194 {
195         struct smack_rule *rule = NULL;
196
197         rule = calloc(sizeof(struct smack_rule), 1);
198         if (rule == NULL)
199                 return -1;
200
201         strncpy(rule->subject, subject, LABEL_LEN + 1);
202         strncpy(rule->object, object, LABEL_LEN + 1);
203         rule->access_code = access_type_to_int(access_type);
204
205         if (handle->first == NULL) {
206                 handle->first = handle->last = rule;
207         } else {
208                 handle->last->next = rule;
209                 handle->last = rule;
210         }
211
212         return 0;
213 }
214
215 int smack_have_access(const char *subject, const char *object,
216                       const char *access_type)
217 {
218         char buf[LOAD_LEN + 1];
219         char access_type_k[ACC_LEN + 1];
220         unsigned access_code;
221         int ret;
222         int fd;
223
224         access_code = access_type_to_int(access_type);
225         int_to_access_type_k(access_code, access_type_k);
226
227         ret = snprintf(buf, LOAD_LEN + 1, KERNEL_FORMAT, subject, object,
228                        access_type_k);
229         if (ret < 0)
230                 return -1;
231
232         fd = open(SMACKFS_MNT "/access", O_RDWR);
233         if (fd < 0)
234                 return -1;
235
236         ret = write(fd, buf, LOAD_LEN);
237         if (ret < 0) {
238                 close(fd);
239                 return -1;
240         }
241
242         ret = read(fd, buf, 1);
243         close(fd);
244         if (ret < 0)
245                 return -1;
246
247         return buf[0] == '1';
248 }
249
250 int smack_new_label_from_self(char **label)
251 {
252         char *result;
253         int fd;
254         int ret;
255
256         result = calloc(LABEL_LEN + 1, 1);
257         if (result == NULL)
258                 return -1;
259
260         fd = open(SELF_LABEL_FILE, O_RDONLY);
261         if (fd < 0) {
262                 free(result);
263                 return -1;
264         }
265
266         ret = read(fd, result, LABEL_LEN);
267         close(fd);
268         if (ret < 0) {
269                 free(result);
270                 return -1;
271         }
272
273         *label = result;
274         return 0;
275 }
276
277 int smack_new_label_from_socket(int fd, char **label)
278 {
279         char dummy;
280         int ret;
281         socklen_t length = 1;
282         char *result;
283
284         ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, &dummy, &length);
285         if (ret < 0 && errno != ERANGE)
286                 return -1;
287
288         result = calloc(length, 1);
289         if (result == NULL)
290                 return -1;
291
292         ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, result, &length);
293         if (ret < 0) {
294                 free(result);
295                 return -1;
296         }
297
298         *label = result;
299         return 0;
300 }
301
302 static int accesses_apply(struct smack_accesses *handle, int clear)
303 {
304         char buf[LOAD_LEN + 1];
305         char access_type[ACC_LEN + 1];
306         struct smack_rule *rule;
307         int ret;
308         int fd;
309
310         fd = open(SMACKFS_MNT "/load", O_WRONLY);
311         if (fd < 0)
312                 return -1;
313
314         if (clear)
315                 strcpy(access_type, "-----");
316
317         for (rule = handle->first; rule != NULL; rule = rule->next) {
318                 if (!clear)
319                         int_to_access_type_k(rule->access_code, access_type);
320
321                 ret = snprintf(buf, LOAD_LEN + 1, KERNEL_FORMAT, rule->subject, rule->object, access_type);
322                 if (ret < 0) {
323                         close(fd);
324                         return -1;
325                 }
326
327                 ret = write(fd, buf, LOAD_LEN);
328                 if (ret < 0) {
329                         close(fd);
330                         return -1;
331                 }
332         }
333
334         close(fd);
335         return 0;
336 }
337
338 static inline int access_type_to_int(const char *access_type)
339 {
340         int i;
341         unsigned access;
342
343         access = 0;
344         for (i = 0; i < ACC_LEN && access_type[i] != '\0'; i++)
345                 switch (access_type[i]) {
346                 case 'r':
347                 case 'R':
348                         access |= ACC_R;
349                         break;
350                 case 'w':
351                 case 'W':
352                         access |= ACC_W;
353                         break;
354                 case 'x':
355                 case 'X':
356                         access |= ACC_X;
357                         break;
358                 case 'a':
359                 case 'A':
360                         access |= ACC_A;
361                         break;
362                 case 't':
363                 case 'T':
364                         access |= ACC_T;
365                         break;
366                 default:
367                         break;
368                 }
369
370         return access;
371 }
372
373 static inline void int_to_access_type_c(unsigned access, char *str)
374 {
375         int i;
376         i = 0;
377         if ((access & ACC_R) != 0)
378                 str[i++] = 'r';
379         if ((access & ACC_W) != 0)
380                 str[i++] = 'w';
381         if ((access & ACC_X) != 0)
382                 str[i++] = 'x';
383         if ((access & ACC_A) != 0)
384                 str[i++] = 'a';
385         if ((access & ACC_T) != 0)
386                 str[i++] = 't';
387         str[i] = '\0';
388 }
389
390 static inline void int_to_access_type_k(unsigned access, char *str)
391 {
392         str[0] = ((access & ACC_R) != 0) ? 'r' : '-';
393         str[1] = ((access & ACC_W) != 0) ? 'w' : '-';
394         str[2] = ((access & ACC_X) != 0) ? 'x' : '-';
395         str[3] = ((access & ACC_A) != 0) ? 'a' : '-';
396         str[4] = ((access & ACC_T) != 0) ? 't' : '-';
397         str[5] = '\0';
398 }
399