From 399f260390d389be17a692c5291ba4095b51c6bf Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 4 Oct 2011 13:02:16 +0300 Subject: [PATCH] Migrated from uthash to glib. Changed API methods to take file descriptor instead of path. Removed check based test cases and created test application for printing rules in kernel form. --- configure.ac | 4 +- src/Makefile.am | 3 + src/smack.c | 321 +++++++++++++++++++++++----------------------------- src/smack.h | 72 +++++------- tests/Makefile.am | 10 +- tests/check_smack.c | 120 -------------------- tests/printload.c | 67 +++++++++++ 7 files changed, 244 insertions(+), 353 deletions(-) delete mode 100644 tests/check_smack.c create mode 100644 tests/printload.c diff --git a/configure.ac b/configure.ac index d18d458..96dcbff 100644 --- a/configure.ac +++ b/configure.ac @@ -24,9 +24,7 @@ fi AM_CONDITIONAL([HAVE_DOXYGEN],[test ! -z "$DOXYGEN"]) AC_SUBST([DOXYGEN], [$DOXYGEN]) -AC_CHECK_HEADERS([uthash.h],, - [AC_MSG_ERROR(Cannot find uthash headers)]) -PKG_CHECK_MODULES([CHECK], [check >= 0.9.4]) +PKG_CHECK_MODULES([GLIB], [glib-2.0]) AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile doc/Makefile libsmack.pc]) diff --git a/src/Makefile.am b/src/Makefile.am index 2001443..6be6a3c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,3 +3,6 @@ lib_LTLIBRARIES = libsmack.la libsmack_la_LDFLAGS = -version-info 1:0:0 libsmack_la_SOURCES = smack.c +libsmack_la_CFLAGS = @GLIB_CFLAGS@ +libsmack_la_LIBADD = @GLIB_LIBS@ + diff --git a/src/smack.c b/src/smack.c index 8ffa237..b8bfcd9 100644 --- a/src/smack.c +++ b/src/smack.c @@ -24,15 +24,15 @@ */ #include "smack.h" -#include #include +#include +#include #include #include -#include -#include -#include +#include #include -#include +#include +#include #define LABEL_LEN 23 @@ -49,54 +49,48 @@ #define READ_BUF_SIZE 512 -struct smack_object { - char *object; - unsigned ac; - char acstr[ACC_LEN + 1]; - UT_hash_handle hh; -}; - -struct smack_subject { - char *subject; - struct smack_object *objects; - UT_hash_handle hh; +struct smack_rule { + char subject[LABEL_LEN + 1]; + char object[LABEL_LEN + 1]; + unsigned access_code; }; struct _SmackRuleSet { - struct smack_subject *subjects; + GList *rules; }; -static int update_rule(struct smack_subject **subjects, - const char *subject_str, const char *object_str, - unsigned ac); inline unsigned str_to_ac(const char *str); inline void ac_to_config_str(unsigned ac, char *str); inline void ac_to_kernel_str(unsigned ac, char *str); -SmackRuleSet smack_rule_set_new(const char *path) +SmackRuleSet smack_rule_set_new(int fd) { SmackRuleSet rules; FILE *file; char buf[READ_BUF_SIZE]; const char *subject, *object, *access; - unsigned ac; - size_t size; - int err, ret; + int newfd; - rules = calloc(1, sizeof(struct _SmackRuleSet)); + rules = g_new(struct _SmackRuleSet, 1); if (rules == NULL) return NULL; + rules->rules = NULL; - if (path == NULL) + if (fd < 0) return rules; - file = fopen(path, "r"); - if (file == NULL) { + newfd = dup(fd); + if (newfd == -1) { free(rules); return NULL; } - ret = 0; + file = fdopen(newfd, "r"); + if (file == NULL) { + close(newfd); + free(rules); + return NULL; + } while (fgets(buf, READ_BUF_SIZE, file) != NULL) { subject = strtok(buf, " \t\n"); @@ -105,80 +99,64 @@ SmackRuleSet smack_rule_set_new(const char *path) if (subject == NULL || object == NULL || access == NULL || strtok(NULL, " \t\n") != NULL) { - ret = -1; - break; + errno = EINVAL; + goto err_out; } - ac = str_to_ac(access); - err = update_rule(&rules->subjects, subject, object, - ac); - if (err != 0) { - ret = -1; - break; - } + if (smack_rule_set_add(rules, subject, object, access)) + goto err_out; } - if (ret != 0 || ferror(file)) { - smack_rule_set_free(rules); - rules = NULL; - } + if (ferror(file)) + goto err_out; fclose(file); return rules; +err_out: + fclose(file); + smack_rule_set_free(rules); + return NULL; } void smack_rule_set_free(SmackRuleSet handle) { - struct smack_subject *s; - struct smack_object *o; - - if (handle == NULL) - return; - - while (handle->subjects != NULL) { - s = handle->subjects; - while (s->objects != NULL) { - o = s->objects; - HASH_DEL(s->objects, o); - free(o->object); - free(o); - } - HASH_DEL(handle->subjects, s); - free(s->subject); - free(s); - } - - free(handle); + g_list_free_full(handle->rules, g_free); } -int smack_rule_set_save(SmackRuleSet handle, const char *path) +int smack_rule_set_save(SmackRuleSet handle, int fd) { - struct smack_subject *s, *stmp; - struct smack_object *o, *otmp; - char astr[ACC_LEN + 1]; + GList *entry; + struct smack_rule *rule; + char access_type[ACC_LEN + 1]; FILE *file; - int err, ret; + int ret; + int newfd; - ret = 0; + newfd = dup(fd); + if (newfd == -1) { + return -1; + } - file = fopen(path, "w+"); - if (!file) + file = fdopen(newfd, "w"); + if (file == NULL) { + close(newfd); return -1; + } - HASH_ITER(hh, handle->subjects, s, stmp) { - HASH_ITER(hh, s->objects, o, otmp) { - if (o->ac == 0) - continue; + entry = g_list_first(handle->rules); + while (entry) { + rule = entry->data; - ac_to_config_str(o->ac, astr); + ac_to_config_str(rule->access_code, access_type); - err = fprintf(file, "%s %s %s\n", - s->subject, o->object, astr); - if (err < 0) { - ret = -1; - goto out; - } + ret = fprintf(file, "%s %s %s\n", + rule->subject, rule->object, access_type); + if (ret < 0) { + ret = -1; + goto out; } + + entry = g_list_next(entry); } out: @@ -186,95 +164,107 @@ out: return ret; } -int smack_rule_set_apply_kernel(SmackRuleSet handle, const char *path) +int smack_rule_set_apply_kernel(SmackRuleSet handle, int fd) { - struct smack_subject *s, *stmp; - struct smack_object *o, *otmp; + GList *entry; + struct smack_rule *rule; + char access_type[ACC_LEN + 1]; FILE *file; - char str[6]; - int err = 0; + int ret; + int newfd; - file = fopen(path, "w"); - if (!file) + newfd = dup(fd); + if (newfd == -1) { return -1; + } - HASH_ITER(hh, handle->subjects, s, stmp) { - HASH_ITER(hh, s->objects, o, otmp) { - ac_to_kernel_str(o->ac, str); + file = fdopen(newfd, "w"); + if (file == NULL) { + close(newfd); + return -1; + } + + entry = g_list_first(handle->rules); + while (entry) { + rule = entry->data; - err = fprintf(file, KERNEL_FORMAT "\n", - s->subject, o->object, str); + ac_to_kernel_str(rule->access_code, access_type); - if (err < 0) { - fclose(file); - return -1; - } + ret = fprintf(file, KERNEL_FORMAT "\n", + rule->subject, rule->object, access_type); + if (ret < 0) { + ret = -1; + goto out; } + + entry = g_list_next(entry); } +out: fclose(file); - return 0; + return ret; } -int smack_rule_set_clear_kernel(SmackRuleSet handle, const char *path) +int smack_rule_set_clear_kernel(SmackRuleSet handle, int fd) { - struct smack_subject *s, *stmp; - struct smack_object *o, *otmp; + GList *entry; + struct smack_rule *rule; + char access_type[ACC_LEN + 1]; FILE *file; - char str[6]; - int err = 0; + int ret; + int newfd; - file = fopen(path, "w"); - if (!file) + newfd = dup(fd); + if (newfd == -1) { return -1; + } - HASH_ITER(hh, handle->subjects, s, stmp) { - HASH_ITER(hh, s->objects, o, otmp) { - ac_to_kernel_str(0, str); + file = fdopen(newfd, "w"); + if (file == NULL) { + close(newfd); + return -1; + } - err = fprintf(file, "%-23s %-23s %4s\n", - s->subject, o->object, str); + entry = g_list_first(handle->rules); + while (entry) { + rule = entry->data; - if (err < 0) { - fclose(file); - return -1; - } + ret = fprintf(file, KERNEL_FORMAT "\n", + rule->subject, rule->object, "-----"); + if (ret < 0) { + ret = -1; + goto out; } + + entry = g_list_next(entry); } +out: fclose(file); - return 0; + return ret; } int smack_rule_set_add(SmackRuleSet handle, const char *subject, - const char *object, const char *access_str) + const char *object, const char *access_type) { - unsigned access; - int ret; + struct smack_rule *rule = NULL; - access = str_to_ac(access_str); - ret = update_rule(&handle->subjects, subject, object, access); - return ret == 0 ? 0 : -1; -} - -int smack_rule_set_have_access(SmackRuleSet handle, const char *subject, - const char *object, const char *access_str) -{ - struct smack_subject *s = NULL; - struct smack_object *o = NULL; - unsigned ac; + if (strlen(subject) > LABEL_LEN || strlen(object) > LABEL_LEN) { + errno = ERANGE; + return -1; + } - ac = str_to_ac(access_str); + rule = g_new(struct smack_rule, 1); + if (rule == NULL) + return -1; - HASH_FIND_STR(handle->subjects, subject, s); - if (s == NULL) - return 0; + strncpy(rule->subject, subject, LABEL_LEN + 1); + strncpy(rule->object, object, LABEL_LEN + 1); + rule->access_code = str_to_ac(access_type); - HASH_FIND_STR(s->objects, object, o); - if (o == NULL) - return 0; + handle->rules = g_list_append(handle->rules, rule); - return ((o->ac & ac) == ac); + return 0; } int smack_have_access(const char *path, const char *subject, @@ -310,59 +300,28 @@ int smack_have_access(const char *path, const char *subject, return buf[0] == '1'; } -int smack_get_peer_label(int sock_fd, char **label) +char *smack_get_peer_label(int fd) { char dummy; int ret; socklen_t length = 1; - char *value; + char *label; - ret = getsockopt(sock_fd, SOL_SOCKET, SO_PEERSEC, &dummy, &length); + ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, &dummy, &length); if (ret < 0 && errno != ERANGE) - return -1; + return NULL; - value = calloc(length, 1); - if (value == NULL) - return -1; + label = calloc(length, 1); + if (label == NULL) + return NULL; - ret = getsockopt(sock_fd, SOL_SOCKET, SO_PEERSEC, value, &length); + ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, label, &length); if (ret < 0) { - free(value); - return -1; - } - - *label = value; - return 0; -} - -static int update_rule(struct smack_subject **subjects, - const char *subject_str, - const char *object_str, unsigned ac) -{ - struct smack_subject *s = NULL; - struct smack_object *o = NULL; - - if (strlen(subject_str) > LABEL_LEN && - strlen(object_str) > LABEL_LEN) - return -ERANGE; - - HASH_FIND_STR(*subjects, subject_str, s); - if (s == NULL) { - s = calloc(1, sizeof(struct smack_subject)); - s->subject = strdup(subject_str); - HASH_ADD_KEYPTR(hh, *subjects, s->subject, strlen(s->subject), s); - } - - HASH_FIND_STR(s->objects, object_str, o); - if (o == NULL) { - o = calloc(1, sizeof(struct smack_object)); - o->object = strdup(object_str); - HASH_ADD_KEYPTR(hh, s->objects, o->object, strlen(o->object), o); + free(label); + return NULL; } - o->ac = ac; - ac_to_config_str(ac, o->acstr); - return 0; + return label; } inline unsigned str_to_ac(const char *str) @@ -425,7 +384,7 @@ inline void ac_to_kernel_str(unsigned access, char *str) str[1] = ((access & ACC_W) != 0) ? 'w' : '-'; str[2] = ((access & ACC_X) != 0) ? 'x' : '-'; str[3] = ((access & ACC_A) != 0) ? 'a' : '-'; - str[3] = ((access & ACC_T) != 0) ? 't' : '-'; - str[4] = '\0'; + str[4] = ((access & ACC_T) != 0) ? 't' : '-'; + str[5] = '\0'; } diff --git a/src/smack.h b/src/smack.h index 87b77a9..841e4ed 100644 --- a/src/smack.h +++ b/src/smack.h @@ -43,19 +43,18 @@ extern "C" { #endif /*! - * Read rules from a given file. Rules can be optionally filtered by a - * subject. + * Creates a new SmackRuleSet instance. If fd >= 0, rule set is read from the + * given file. Otherwise, empty rule set is created. * - * @param path path to the file containing rules. If NULL, empty set is - * created. + * @param fd file descriptor * @return SmackRuleSet instance on success */ -extern SmackRuleSet smack_rule_set_new(const char *path); +extern SmackRuleSet smack_rule_set_new(int fd); /*! - * Free resources allocated by rules. + * Destroy a SmackRuleSet instance. * - * @param handle handle to a rules + * @param handle handle to a SmackRuleSet instance */ extern void smack_rule_set_free(SmackRuleSet handle); @@ -63,53 +62,40 @@ extern void smack_rule_set_free(SmackRuleSet handle); * Write access rules to a given file. * * @param handle handle to a rules - * @param path path to the rules file - * @return Returns negative value on failure. + * @param fd file descriptor + * @return Returns 0 on success. */ -extern int smack_rule_set_save(SmackRuleSet handle, const char *path); +extern int smack_rule_set_save(SmackRuleSet handle, int fd); /*! - * Write rules in SmackFS format. + * Write rules in SmackFS format to a given file. * - * @param handle handle to a rule set - * @param path path to the load file - * @return Returns negative value on failure. + * @param handle handle to a rules + * @param fd file descriptor + * @return Returns 0 on success. */ -extern int smack_rule_set_apply_kernel(SmackRuleSet handle, const char *path); +extern int smack_rule_set_apply_kernel(SmackRuleSet handle, int fd); /*! - * Write rules in SmackFS format with access type set to -. + * Write rules in SmackFS format with access type set to '-' to a given file. * * @param handle handle to a rules - * @param path path to the load file - * @return Returns negative value on failure. + * @param fd file descriptor + * @return Returns 0 on success. */ -extern int smack_rule_set_clear_kernel(SmackRuleSet handle, const char *path); +extern int smack_rule_set_clear_kernel(SmackRuleSet handle, int fd); /*! - * Add new rule to a rule set. Updates existing rule if there is already rule - * for the given subject and object. + * Add new rule to a rule set. * * @param handle handle to a rule set * @param subject subject of the rule * @param object object of the rule - * @param access access string (rwxa) - * @return Returns negative value on failure. + * @param access_type access type + * @return Returns 0 on success. */ extern int smack_rule_set_add(SmackRuleSet handle, const char *subject, - const char *object, const char *access); - -/*! - * Check access to a give object from the give rule set. - * - * @param handle handle to a rule set - * @param subject subject of the rule - * @param object object of the rule - * @param access string defining access type - * @return 1 if access, 0 if no access. - */ -extern int smack_rule_set_have_access(SmackRuleSet handle, const char *subject, - const char *object, const char *access); + const char *object, const char *access_type); /*! * Check access from SmackFS access file. @@ -118,21 +104,19 @@ extern int smack_rule_set_have_access(SmackRuleSet handle, const char *subject, * @param subject subject of the rule * @param object object of the rule * @param access_type access type - * @return 1 if access, 0 if no access. + * @return 1 if access, 0 if no access and -1 on error. */ extern int smack_have_access(const char *path, const char *subject, const char *object, const char *access_type); /*! - * Get the label that is associated with a peer on the other - * end of a socket. + * Get the label that is associated with a peer on the other end of a socket. + * Caller is responsible of freeing the returned label. * - * @param sock_fd The file descriptor of the socket - * @param label The NULL terminated label of the socket if it exists, - * the caller is responsible to call free on the label. - * @return 0 on success, -1 otherwise. + * @param fd socket file descriptor + * @return label on success and NULL of failure. */ -extern int smack_get_peer_label(int sock_fd, char **label); +extern char *smack_get_peer_label(int fd); #ifdef __cplusplus } diff --git a/tests/Makefile.am b/tests/Makefile.am index 3f2dcb0..d33b05f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ -TESTS = check_smack -check_PROGRAMS = check_smack +AM_CPPFLAGS = -I../src -check_smack_SOURCES = check_smack.c $(top_builddir)/src/smack.h -check_smack_CFLAGS = @CHECK_CFLAGS@ -check_smack_LDADD = -L$(top_builddir)/src/.libs -lsmack @CHECK_LIBS@ +bin_PROGRAMS = printload + +printload_SOURCES = printload.c +printload_LDADD = -L$(top_builddir)/src/.libs -lsmack diff --git a/tests/check_smack.c b/tests/check_smack.c deleted file mode 100644 index 190e4a8..0000000 --- a/tests/check_smack.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * This file is part of libsmack - * - * Copyright (C) 2010 Nokia Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * Author: Jarkko Sakkinen - */ - -#include -#include -#include -#include "../src/smack.h" - -START_TEST(test_save_to_kernel) -{ - int rc; - SmackRuleSet rules; - - rules = smack_rule_set_new(NULL); - fail_unless(rules != NULL, "Rule set creation failed"); - if (rules == NULL) - return; - - smack_rule_set_add(rules, "Apple", "Orange", "rwx"); - smack_rule_set_add(rules, "Plum", "Peach", "rx"); - smack_rule_set_add(rules, "Banana", "Peach", "xa"); - - rc = smack_rule_set_apply_kernel( - rules, - "save_to_kernel.rules"); - fail_unless(rc == 0, "Failed to write the rule set"); - - rules = smack_rule_set_new("save_to_kernel.rules"); - fail_unless(rules != NULL, "Opening rule set failed"); - if (rules == NULL) - return; - - rc = smack_rule_set_have_access(rules, "Banana", "Peach", "x"); - fail_unless(rc == 1, "Access not granted"); - rc = smack_rule_set_have_access(rules, "Banana", "Peach", "r"); - fail_unless(rc == 0, "Access granted"); - rc = smack_rule_set_have_access(rules, "Apple", "Orange", "a"); - fail_unless(rc == 0, "Access granted"); - - smack_rule_set_free(rules); -} -END_TEST - -START_TEST(test_save_to_file) -{ - int rc; - const char *sn; - SmackRuleSet rules; - - rules = smack_rule_set_new(NULL); - fail_unless(rules != NULL, "Creating rule set failed"); - if (rules == NULL) - return; - - smack_rule_set_add(rules, "Apple", "Orange", "rwx"); - smack_rule_set_add(rules, "Plum", "Peach", "rx"); - smack_rule_set_add(rules, "Banana", "Peach", "xa"); - - rc = smack_rule_set_save( - rules, - "save_to_file-rules"); - fail_unless(rc == 0, "Failed to write the rule set"); - - rc = smack_rule_set_have_access(rules, "Banana", "Peach", "x"); - fail_unless(rc == 1, "Access not granted"); - rc = smack_rule_set_have_access(rules, "Banana", "Peach", "r"); - fail_unless(rc == 0, "Access granted"); - rc = smack_rule_set_have_access(rules, "Apple", "Orange", "a"); - fail_unless(rc == 0, "Access granted"); - - smack_rule_set_free(rules); -} -END_TEST - -Suite *ruleset_suite (void) -{ - Suite *s; - TCase *tc_core; - - s = suite_create("Rules"); - - tc_core = tcase_create("Rules"); - tcase_add_test(tc_core, test_save_to_kernel); - tcase_add_test(tc_core, test_save_to_file); - suite_add_tcase(s, tc_core); - - return s; -} - -int main(void) -{ - int nfailed; - Suite *s = ruleset_suite(); - SRunner *sr = srunner_create(s); - srunner_set_log(sr, "check_rules.log"); - srunner_run_all(sr, CK_ENV); - nfailed = srunner_ntests_failed(sr); - srunner_free(sr); - return (nfailed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - diff --git a/tests/printload.c b/tests/printload.c new file mode 100644 index 0000000..46b7fc9 --- /dev/null +++ b/tests/printload.c @@ -0,0 +1,67 @@ +/* + * This file is part of libsmack + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * Authors: + * Jarkko Sakkinen + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct option opts[] = { + {"clear", no_argument, NULL, 'c'}, + {NULL, 0, NULL, 0} +}; + +int main(int argc, char **argv) +{ + SmackRuleSet rules; + int clear_flag = 0; + int o = 1; + + while ((o = getopt_long(argc, argv, "c", opts, NULL)) != -1) { + switch (o) { + case 'c': + clear_flag = 1; + break; + default: + exit(EXIT_FAILURE); + } + + rules = smack_rule_set_new(STDIN_FILENO); + + if (rules == NULL) { + perror("smack_rule_set_new"); + exit(EXIT_FAILURE); + } + + if (clear_flag) + smack_rule_set_clear_kernel(rules, STDOUT_FILENO); + else + smack_rule_set_apply_kernel(rules, STDOUT_FILENO); + + return EXIT_SUCCESS; +} + -- 2.7.4