diff -up mcstrans-0.3.3/src/mcstrans.c.inotify mcstrans-0.3.3/src/mcstrans.c --- mcstrans-0.3.3/src/mcstrans.c.inotify 2011-12-06 08:45:02.000000000 -0500 +++ mcstrans-0.3.3/src/mcstrans.c 2013-02-08 08:48:08.343787003 -0500 @@ -1,6 +1,8 @@ /* Copyright (c) 2008-2009 Nall Design Works - Copyright 2006 Trusted Computer Solutions, Inc. */ + Copyright 2006 Trusted Computer Solutions, Inc. + Copyright 2013 Red Hat, Inc. +*/ /* Exported Interface @@ -12,6 +14,7 @@ */ +#include #include #include #include @@ -30,7 +33,7 @@ #include #include #include - +#include #include "mls_level.h" #include "mcstrans.h" @@ -166,6 +169,30 @@ err: } static int +remove_from_hashtable(context_map_node_t **table, char *key) { + unsigned int bucket = hash(key) % N_BUCKETS; + context_map_node_t **n; + context_map_node_t **p = NULL; + context_map_node_t *next = NULL; + for (n = &table[bucket]; *n; n = &(*n)->next) { + if (!strcmp((*n)->key, key)) + break; + p = n; + } + if (! *n) + return -1; + + next = (*n)->next; + free(*n); + if (p) + (*p)->next = next; + else + table[bucket] = next; + + return 0; +} + +static int numdigits(unsigned int n) { int count = 1; @@ -665,6 +692,26 @@ find_in_table(context_map_node_t **table return NULL; } +static void +remove_cache(domain_t *domain, char *raw) { + context_map_t *map=find_in_table(domain->raw_to_trans, raw); + if (!map) { + log_error("Failed to remove_cache (%s) does not exist\n", raw); + return; + } + log_debug(" remove_cache (%s,%s)\n", raw, map->trans); + if (remove_from_hashtable(domain->trans_to_raw, map->trans) < 0) { + log_error(" Failed to remove %s from trans_to_raw\n", map->trans); + } + + if (remove_from_hashtable(domain->raw_to_trans, raw) < 0) { + log_error(" Failed to remove %s from raw_to_trans\n", raw); + } + free(map->raw); + free(map->trans); + free(map); +} + char * trim(char *str, const char *whitespace) { char *p = str + strlen(str); @@ -1760,3 +1809,113 @@ finish_context_translations(void) { } } +#define INOTIFY_WATCHDIR "/run/setrans" + +/* size of the event structure, not counting name */ +#define EVENT_SIZE (sizeof (struct inotify_event)) +/* reasonable guess as to size of 1024 events */ +#define BUF_LEN (1024 * (EVENT_SIZE + 16)) +static domain_t *inotify_domain; + +int add_inotify_cache(char *raw) { + char trans[BUF_LEN+1]; + char path[PATH_MAX]; + FILE *f; + size_t len; + domain_t *domain = domains; + for (;domain; domain = domain->next) { + context_map_t *map=find_in_table(domain->raw_to_trans, raw); + if (map) { + log_error("Failed to add translation %s to cache (%s,%s) already exists\n", raw, raw, map->trans); + return -1; + } + } + memset(trans,0, sizeof(trans)); + memset(path,0, sizeof(path)); + len = snprintf(path, sizeof(path), "%s/%s", INOTIFY_WATCHDIR, raw); + if (len >= sizeof(path)) { + log_error("Failed to open %s/%s, too large for buffer\n", INOTIFY_WATCHDIR, raw); + } + f = fopen(path, "r"); + if(! f) { + log_error("Failed to open %s %s\n", path, strerror(errno)); + return -1; + } + fread(trans, 1, BUF_LEN, f); + fclose(f); + return add_cache(inotify_domain, raw, trans); +} + +int process_inotify(int inotifyfd) { + int i = 0; + char buf[BUF_LEN+1]; + int len; + memset(buf,0, BUF_LEN); + len = read(inotifyfd, buf, BUF_LEN); + if (len < 0) { + return -1; + } else if (!len) + /* BUF_LEN too small? */ + return -1; + while (i < len) { + struct inotify_event *event; + event = (struct inotify_event *)&buf[i]; + if (event->mask & IN_DELETE) { + if (event->len && event->name[0] != '.') { + remove_cache(inotify_domain, event->name); + } + } + if (event->mask & IN_CREATE) { + if (event->len && event->name[0] != '.') { + (void) add_inotify_cache(event->name); + } + } + + i += EVENT_SIZE + event->len; + } + return 0; +} + +/* Watch INOTIFY_WATCHDIR for file creaton and deletion, then attempt to + add/remove the contents of these files to the cache. The name of the + file is the raw MLS/MCS label, while the contents are the Translation name. +*/ +int init_inotify(void) { + DIR *dir; + struct dirent *entry; + int fd = inotify_init1(IN_CLOEXEC); + if (fd < 0) { + syslog(LOG_ERR, "socket() failed: %m"); + return -1; + } + + if (inotify_add_watch(fd, INOTIFY_WATCHDIR, IN_CREATE | IN_DELETE) < 0) + { + syslog(LOG_ERR, "inotify_add_watch( %s ) failed: %m", INOTIFY_WATCHDIR); + goto err; + } + inotify_domain = create_domain("inotify"); + if (!inotify_domain) { + syslog(LOG_ERR, "create_domain(inotify) failed: %m"); + goto err; + } + + /* read all existing files in the INOTIFY_WATCHDIR and add them to the + cache. + */ + if ((dir = opendir(INOTIFY_WATCHDIR)) == NULL) { + syslog(LOG_ERR, "opendirs(%s) failed: %m", INOTIFY_WATCHDIR); + goto err; + } + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] != '.') + (void) add_inotify_cache(entry->d_name); + } + closedir(dir); + + return fd; + +err: + close(fd); + return -1; +} diff -up mcstrans-0.3.3/src/mcstransd.c.inotify mcstrans-0.3.3/src/mcstransd.c --- mcstrans-0.3.3/src/mcstransd.c.inotify 2013-02-08 08:37:32.772422371 -0500 +++ mcstrans-0.3.3/src/mcstransd.c 2013-02-08 08:37:32.784422421 -0500 @@ -60,6 +60,7 @@ extern int raw_color(const security_cont #define SETRANSD_PROGNAME "mcstransd" static int sockfd = -1; /* socket we are listening on */ +static int inotifyfd = -1; /* inotify socket we are listening on */ static volatile int restart_daemon = 0; static void cleanup_exit(int ret) __attribute__ ((noreturn)); @@ -354,19 +355,23 @@ process_events(struct pollfd **ufds, int return -1; } } else { - ret = service_request(connfd); - if (ret) { - if (ret < 0) { - syslog(LOG_ERR, - "Servicing of request " - "failed for fd (%d)\n", - connfd); + if (connfd == inotifyfd) { + process_inotify(inotifyfd); + } else { + ret = service_request(connfd); + if (ret) { + if (ret < 0) { + syslog(LOG_ERR, + "Servicing of request " + "failed for fd (%d)\n", + connfd); + } + /* Setup pollfd for deletion later. */ + (*ufds)[ii].fd = -1; + close(connfd); + /* So we don't get bothered later */ + revents = revents & ~(POLLHUP); } - /* Setup pollfd for deletion later. */ - (*ufds)[ii].fd = -1; - close(connfd); - /* So we don't get bothered later */ - revents = revents & ~(POLLHUP); } } revents = revents & ~(POLLIN | POLLPRI); @@ -406,9 +411,9 @@ static void process_connections(void) { int ret = 0; - int nfds = 1; + int nfds = 2; - struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd)); + struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd)*nfds); if (!ufds) { syslog(LOG_ERR, "Failed to allocate a pollfd"); cleanup_exit(1); @@ -417,6 +422,10 @@ process_connections(void) ufds[0].events = POLLIN|POLLPRI; ufds[0].revents = 0; + ufds[1].fd = inotifyfd; + ufds[1].events = POLLIN|POLLPRI; + ufds[1].revents = 0; + while (1) { if (restart_daemon) { syslog(LOG_NOTICE, "Reload Translations"); @@ -516,6 +525,11 @@ initialize(void) cleanup_exit(1); } + inotifyfd = init_inotify(); + if (inotifyfd < 0) { + cleanup_exit(1); + } + memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SETRANS_UNIX_SOCKET, sizeof(addr.sun_path) - 1); diff -up mcstrans-0.3.3/src/mcstrans.h.inotify mcstrans-0.3.3/src/mcstrans.h --- mcstrans-0.3.3/src/mcstrans.h.inotify 2011-12-06 08:45:02.000000000 -0500 +++ mcstrans-0.3.3/src/mcstrans.h 2013-02-08 08:37:32.784422421 -0500 @@ -6,4 +6,5 @@ extern int init_translations(void); extern void finish_context_translations(void); extern int trans_context(const security_context_t, security_context_t *); extern int untrans_context(const security_context_t, security_context_t *); - +extern int init_inotify(void); +extern int process_inotify(int inotifyfd);