2 * This file is part of libsmack
4 * Copyright (C) 2010 Nokia Corporation
5 * Copyright (C) 2011 Intel Corporation
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.
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.
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
22 * Jarkko Sakkinen <jarkko.sakkinen@intel.com>
23 * Brian McGillion <brian.mcgillion@intel.com>
26 #include "sys/smack.h"
32 #include <sys/socket.h>
34 #include <sys/types.h>
39 #define LOAD_LEN (2 * (LABEL_LEN + 1) + ACC_LEN)
44 #define CAT_MAX_COUNT 240
45 #define CAT_MAX_VALUE 63
46 #define CIPSO_POS(i) (LABEL_LEN + 1 + NUM_LEN + NUM_LEN + i * NUM_LEN)
47 #define CIPSO_MAX_SIZE CIPSO_POS(CAT_MAX_COUNT)
48 #define CIPSO_NUM_LEN_STR "%-4d"
56 #define KERNEL_LONG_FORMAT "%s %s %s"
57 #define KERNEL_SHORT_FORMAT "%-23s %-23s %5s"
58 #define READ_BUF_SIZE LOAD_LEN + 1
59 #define SMACKFS_MNT "/smack"
60 #define SELF_LABEL_FILE "/proc/self/attr/current"
63 char subject[LABEL_LEN + 1];
64 char object[LABEL_LEN + 1];
66 struct smack_rule *next;
69 struct smack_accesses {
70 struct smack_rule *first;
71 struct smack_rule *last;
74 struct cipso_mapping {
75 char label[LABEL_LEN + 1];
76 int cats[CAT_MAX_VALUE];
79 struct cipso_mapping *next;
83 struct cipso_mapping *first;
84 struct cipso_mapping *last;
87 static int accesses_apply(struct smack_accesses *handle, int clear);
88 static inline int access_type_to_int(const char *access_type);
89 static inline void int_to_access_type_c(unsigned ac, char *str);
90 static inline void int_to_access_type_k(unsigned ac, char *str);
92 int smack_accesses_new(struct smack_accesses **accesses)
94 struct smack_accesses *result;
96 result = calloc(sizeof(struct smack_accesses), 1);
104 void smack_accesses_free(struct smack_accesses *handle)
109 struct smack_rule *rule = handle->first;
110 struct smack_rule *next_rule = NULL;
112 while (rule != NULL) {
113 next_rule = rule->next;
121 int smack_accesses_save(struct smack_accesses *handle, int fd)
123 struct smack_rule *rule = handle->first;
124 char access_type[ACC_LEN + 1];
133 file = fdopen(newfd, "w");
140 int_to_access_type_c(rule->access_code, access_type);
142 ret = fprintf(file, "%s %s %s\n",
143 rule->subject, rule->object, access_type);
156 int smack_accesses_apply(struct smack_accesses *handle)
158 return accesses_apply(handle, 0);
161 int smack_accesses_clear(struct smack_accesses *handle)
163 return accesses_apply(handle, 1);
166 int smack_accesses_add(struct smack_accesses *handle, const char *subject,
167 const char *object, const char *access_type)
169 struct smack_rule *rule = NULL;
171 rule = calloc(sizeof(struct smack_rule), 1);
175 strncpy(rule->subject, subject, LABEL_LEN + 1);
176 strncpy(rule->object, object, LABEL_LEN + 1);
177 rule->access_code = access_type_to_int(access_type);
179 if (handle->first == NULL) {
180 handle->first = handle->last = rule;
182 handle->last->next = rule;
189 int smack_accesses_add_from_file(struct smack_accesses *accesses, int fd)
192 char buf[READ_BUF_SIZE];
194 const char *subject, *object, *access;
201 file = fdopen(newfd, "r");
207 while (fgets(buf, READ_BUF_SIZE, file) != NULL) {
208 if (strcmp(buf, "\n") == 0)
210 subject = strtok_r(buf, " \t\n", &ptr);
211 object = strtok_r(NULL, " \t\n", &ptr);
212 access = strtok_r(NULL, " \t\n", &ptr);
214 if (subject == NULL || object == NULL || access == NULL ||
215 strtok_r(NULL, " \t\n", &ptr) != NULL) {
221 if (smack_accesses_add(accesses, subject, object, access)) {
236 int smack_have_access(const char *subject, const char *object,
237 const char *access_type)
239 char buf[LOAD_LEN + 1];
240 char access_type_k[ACC_LEN + 1];
241 unsigned access_code;
246 access_code = access_type_to_int(access_type);
247 int_to_access_type_k(access_code, access_type_k);
249 fd = open(SMACKFS_MNT "/access2", O_RDWR);
253 fd = open(SMACKFS_MNT "/access", O_RDWR);
260 ret = snprintf(buf, LOAD_LEN + 1, KERNEL_LONG_FORMAT,
261 subject, object, access_type_k);
263 ret = snprintf(buf, LOAD_LEN + 1, KERNEL_SHORT_FORMAT,
264 subject, object, access_type_k);
271 ret = write(fd, buf, strlen(buf));
277 ret = read(fd, buf, 1);
282 return buf[0] == '1';
284 void smack_cipso_free(struct smack_cipso *cipso)
289 struct cipso_mapping *mapping = cipso->first;
290 struct cipso_mapping *next_mapping = NULL;
292 while (mapping != NULL) {
293 next_mapping = mapping->next;
295 mapping = next_mapping;
299 struct smack_cipso *smack_cipso_new(int fd)
301 struct smack_cipso *cipso = NULL;
302 struct cipso_mapping *mapping = NULL;
305 char *label, *level, *cat, *ptr;
314 file = fdopen(newfd, "r");
320 cipso = calloc(sizeof(struct smack_cipso ), 1);
326 while (fgets(buf, BUF_SIZE, file) != NULL) {
327 mapping = calloc(sizeof(struct cipso_mapping), 1);
331 label = strtok_r(buf, " \t\n", &ptr);
332 level = strtok_r(NULL, " \t\n", &ptr);
333 cat = strtok_r(NULL, " \t\n", &ptr);
334 if (label == NULL || cat == NULL || level == NULL ||
335 strlen(label) > LABEL_LEN) {
340 strcpy(mapping->label, label);
343 val = strtol(level, NULL, 10);
347 if (val < 0 || val > LEVEL_MAX) {
352 mapping->level = val;
354 for (i = 0; i < CAT_MAX_COUNT && cat != NULL; i++) {
356 val = strtol(cat, NULL, 10);
360 if (val < 0 || val > CAT_MAX_VALUE) {
365 mapping->cats[i] = val;
367 cat = strtok_r(NULL, " \t\n", &ptr);
372 if (cipso->first == NULL) {
373 cipso->first = cipso->last = mapping;
375 cipso->last->next = mapping;
376 cipso->last = mapping;
387 smack_cipso_free(cipso);
392 int smack_cipso_apply(struct smack_cipso *cipso)
394 struct cipso_mapping *m = NULL;
395 char buf[CIPSO_MAX_SIZE];
399 fd = open(SMACKFS_MNT "/cipso2", O_WRONLY);
403 for (m = cipso->first; m != NULL; m = m->next) {
404 sprintf(buf, "%s ", m->label);
405 sprintf(&buf[LABEL_LEN + 1], CIPSO_NUM_LEN_STR, m->level);
406 sprintf(&buf[LABEL_LEN + 1 + NUM_LEN], CIPSO_NUM_LEN_STR, m->ncats);
408 for (i = 0; i < m->ncats; i++)
409 sprintf(&buf[CIPSO_POS(i)], CIPSO_NUM_LEN_STR, m->cats[i]);
411 if (write(fd, buf, strlen(buf)) < 0) {
420 int smack_new_label_from_self(char **label)
426 result = calloc(LABEL_LEN + 1, 1);
430 fd = open(SELF_LABEL_FILE, O_RDONLY);
436 ret = read(fd, result, LABEL_LEN);
447 int smack_new_label_from_socket(int fd, char **label)
451 socklen_t length = 1;
454 ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, &dummy, &length);
455 if (ret < 0 && errno != ERANGE)
458 result = calloc(length + 1, 1);
462 ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, result, &length);
472 static int accesses_apply(struct smack_accesses *handle, int clear)
474 char buf[LOAD_LEN + 1];
475 char access_type[ACC_LEN + 1];
476 struct smack_rule *rule;
481 fd = open(SMACKFS_MNT "/load2", O_WRONLY);
486 fd = open(SMACKFS_MNT "/load", O_WRONLY);
493 strcpy(access_type, "-----");
495 for (rule = handle->first; rule != NULL; rule = rule->next) {
497 int_to_access_type_k(rule->access_code, access_type);
500 ret = snprintf(buf, LOAD_LEN + 1, KERNEL_LONG_FORMAT,
501 rule->subject, rule->object,
504 ret = snprintf(buf, LOAD_LEN + 1, KERNEL_SHORT_FORMAT,
505 rule->subject, rule->object,
512 ret = write(fd, buf, strlen(buf));
523 static inline int access_type_to_int(const char *access_type)
529 for (i = 0; i < ACC_LEN && access_type[i] != '\0'; i++)
530 switch (access_type[i]) {
558 static inline void int_to_access_type_c(unsigned access, char *str)
562 if ((access & ACC_R) != 0)
564 if ((access & ACC_W) != 0)
566 if ((access & ACC_X) != 0)
568 if ((access & ACC_A) != 0)
570 if ((access & ACC_T) != 0)
575 static inline void int_to_access_type_k(unsigned access, char *str)
577 str[0] = ((access & ACC_R) != 0) ? 'r' : '-';
578 str[1] = ((access & ACC_W) != 0) ? 'w' : '-';
579 str[2] = ((access & ACC_X) != 0) ? 'x' : '-';
580 str[3] = ((access & ACC_A) != 0) ? 'a' : '-';
581 str[4] = ((access & ACC_T) != 0) ? 't' : '-';