diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/audit2allow/audit2allow policycoreutils-2.0.71/audit2allow/audit2allow --- nsapolicycoreutils/audit2allow/audit2allow 2009-01-13 08:45:35.000000000 -0500 +++ policycoreutils-2.0.71/audit2allow/audit2allow 2009-08-20 12:53:16.000000000 -0400 @@ -42,6 +42,8 @@ from optparse import OptionParser parser = OptionParser(version=self.VERSION) + parser.add_option("-b", "--boot", action="store_true", dest="boot", default=False, + help="audit messages since last boot conflicts with -i") parser.add_option("-a", "--all", action="store_true", dest="audit", default=False, help="read input from audit log - conflicts with -i") parser.add_option("-d", "--dmesg", action="store_true", dest="dmesg", default=False, @@ -80,11 +82,11 @@ options, args = parser.parse_args() # Make -d, -a, and -i conflict - if options.audit is True: + if options.audit is True or options.boot: if options.input is not None: - sys.stderr.write("error: --all conflicts with --input\n") + sys.stderr.write("error: --all/--boot conflicts with --input\n") if options.dmesg is True: - sys.stderr.write("error: --all conflicts with --dmesg\n") + sys.stderr.write("error: --all/--boot conflicts with --dmesg\n") if options.input is not None and options.dmesg is True: sys.stderr.write("error: --input conflicts with --dmesg\n") @@ -129,6 +131,12 @@ except OSError, e: sys.stderr.write('could not run ausearch - "%s"\n' % str(e)) sys.exit(1) + elif self.__options.boot: + try: + messages = audit.get_audit_boot_msgs() + except OSError, e: + sys.stderr.write('could not run ausearch - "%s"\n' % str(e)) + sys.exit(1) else: # This is the default if no input is specified f = sys.stdin diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/Makefile policycoreutils-2.0.71/Makefile --- nsapolicycoreutils/Makefile 2008-08-28 09:34:24.000000000 -0400 +++ policycoreutils-2.0.71/Makefile 2009-08-20 12:53:16.000000000 -0400 @@ -1,4 +1,4 @@ -SUBDIRS = setfiles semanage load_policy newrole run_init secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps setsebool po +SUBDIRS = setfiles semanage load_policy newrole run_init secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps setsebool po gui INOTIFYH = $(shell ls /usr/include/sys/inotify.h 2>/dev/null) diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/restorecond/Makefile policycoreutils-2.0.71/restorecond/Makefile --- nsapolicycoreutils/restorecond/Makefile 2009-08-20 15:49:21.000000000 -0400 +++ policycoreutils-2.0.71/restorecond/Makefile 2009-08-20 15:30:42.000000000 -0400 @@ -1,17 +1,28 @@ # Installation directories. PREFIX ?= ${DESTDIR}/usr SBINDIR ?= $(PREFIX)/sbin +LIBDIR ?= $(PREFIX)/lib MANDIR = $(PREFIX)/share/man +AUTOSTARTDIR = $(DESTDIR)/etc/xdg/autostart +DBUSSERVICEDIR = $(DESTDIR)/usr/share/dbus-1/services + +autostart_DATA = sealertauto.desktop INITDIR = $(DESTDIR)/etc/rc.d/init.d SELINUXDIR = $(DESTDIR)/etc/selinux +DBUSFLAGS = -DHAVE_DBUS -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -I/usr/lib/dbus-1.0/include +DBUSLIB = -ldbus-glib-1 + CFLAGS ?= -g -Werror -Wall -W -override CFLAGS += -I$(PREFIX)/include -D_FILE_OFFSET_BITS=64 -LDLIBS += -lselinux -L$(PREFIX)/lib +override CFLAGS += -I$(PREFIX)/include $(DBUSFLAGS) -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/lib/glib-2.0/include + +LDLIBS += -lselinux $(DBUSLIB) -lglib-2.0 -L$(LIBDIR) all: restorecond -restorecond: restorecond.o utmpwatcher.o stringslist.o +restorecond.o utmpwatcher.o stringslist.o user.o watch.o: restorecond.h + +restorecond: ../setfiles/restore.o restorecond.o utmpwatcher.o stringslist.o user.o watch.o $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) install: all @@ -22,7 +33,12 @@ -mkdir -p $(INITDIR) install -m 755 restorecond.init $(INITDIR)/restorecond -mkdir -p $(SELINUXDIR) - install -m 600 restorecond.conf $(SELINUXDIR)/restorecond.conf + install -m 644 restorecond.conf $(SELINUXDIR)/restorecond.conf + install -m 644 restorecond_user.conf $(SELINUXDIR)/restorecond_user.conf + -mkdir -p $(AUTOSTARTDIR) + install -m 644 restorecond.desktop $(AUTOSTARTDIR)/restorecond.desktop + -mkdir -p $(DBUSSERVICEDIR) + install -m 600 org.selinux.Restorecond.service $(DBUSSERVICEDIR)/org.selinux.Restorecond.service relabel: install /sbin/restorecon $(SBINDIR)/restorecond diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/restorecond/org.selinux.Restorecond.service policycoreutils-2.0.71/restorecond/org.selinux.Restorecond.service --- nsapolicycoreutils/restorecond/org.selinux.Restorecond.service 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/restorecond/org.selinux.Restorecond.service 2009-08-20 12:53:16.000000000 -0400 @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.selinux.Restorecond +Exec=/usr/sbin/restorecond -u diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/restorecond/restorecond.c policycoreutils-2.0.71/restorecond/restorecond.c --- nsapolicycoreutils/restorecond/restorecond.c 2009-08-20 15:49:21.000000000 -0400 +++ policycoreutils-2.0.71/restorecond/restorecond.c 2009-08-20 15:30:44.000000000 -0400 @@ -48,294 +48,38 @@ #include #include #include -#include +#include "../setfiles/restore.h" #include -#include #include #include +#include +#include +#include +#include #include - #include "restorecond.h" -#include "stringslist.h" #include "utmpwatcher.h" -extern char *dirname(char *path); +const char *homedir; static int master_fd = -1; -static int master_wd = -1; -static int terminate = 0; - -#include -#include - -/* 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 int debug_mode = 0; -static int verbose_mode = 0; - -static void restore(const char *filename, int exact); - -struct watchList { - struct watchList *next; - int wd; - char *dir; - struct stringsList *files; -}; -struct watchList *firstDir = NULL; - -/* Compare two contexts to see if their differences are "significant", - * or whether the only difference is in the user. */ -static int only_changed_user(const char *a, const char *b) -{ - char *rest_a, *rest_b; /* Rest of the context after the user */ - if (!a || !b) - return 0; - rest_a = strchr(a, ':'); - rest_b = strchr(b, ':'); - if (!rest_a || !rest_b) - return 0; - return (strcmp(rest_a, rest_b) == 0); -} - -/* - A file was in a direcroty has been created. This function checks to - see if it is one that we are watching. -*/ - -static int watch_list_find(int wd, const char *file) -{ - struct watchList *ptr = NULL; - ptr = firstDir; - - if (debug_mode) - printf("%d: File=%s\n", wd, file); - while (ptr != NULL) { - if (ptr->wd == wd) { - int exact=0; - if (strings_list_find(ptr->files, file, &exact) == 0) { - char *path = NULL; - if (asprintf(&path, "%s/%s", ptr->dir, file) < - 0) - exitApp("Error allocating memory."); - restore(path, exact); - free(path); - return 0; - } - if (debug_mode) - strings_list_print(ptr->files); - - /* Not found in this directory */ - return -1; - } - ptr = ptr->next; - } - /* Did not find a directory */ - return -1; -} - -static void watch_list_free(int fd) -{ - struct watchList *ptr = NULL; - struct watchList *prev = NULL; - ptr = firstDir; - - while (ptr != NULL) { - inotify_rm_watch(fd, ptr->wd); - strings_list_free(ptr->files); - free(ptr->dir); - prev = ptr; - ptr = ptr->next; - free(prev); - } - firstDir = NULL; -} - -/* - Set the file context to the default file context for this system. - Same as restorecon. -*/ -static void restore(const char *filename, int exact) -{ - int retcontext = 0; - security_context_t scontext = NULL; - security_context_t prev_context = NULL; - struct stat st; - int fd = -1; - if (debug_mode) - printf("restore %s\n", filename); - - fd = open(filename, O_NOFOLLOW | O_RDONLY); - if (fd < 0) { - if (verbose_mode) - syslog(LOG_ERR, "Unable to open file (%s) %s\n", - filename, strerror(errno)); - return; - } - - if (fstat(fd, &st) != 0) { - syslog(LOG_ERR, "Unable to stat file (%s) %s\n", filename, - strerror(errno)); - close(fd); - return; - } - - if (!(st.st_mode & S_IFDIR) && st.st_nlink > 1) { - if (exact) { - syslog(LOG_ERR, - "Will not restore a file with more than one hard link (%s) %s\n", - filename, strerror(errno)); - } - close(fd); - return; - } - - if (matchpathcon(filename, st.st_mode, &scontext) < 0) { - if (errno == ENOENT) - return; - syslog(LOG_ERR, "matchpathcon(%s) failed %s\n", filename, - strerror(errno)); - return; - } - retcontext = fgetfilecon_raw(fd, &prev_context); - - if (retcontext >= 0 || errno == ENODATA) { - if (retcontext < 0) - prev_context = NULL; - if (retcontext < 0 || (strcmp(prev_context, scontext) != 0)) { - - if (only_changed_user(scontext, prev_context) != 0) { - free(scontext); - free(prev_context); - close(fd); - return; - } - - if (fsetfilecon(fd, scontext) < 0) { - if (errno != EOPNOTSUPP) - syslog(LOG_ERR, - "set context %s->%s failed:'%s'\n", - filename, scontext, strerror(errno)); - if (retcontext >= 0) - free(prev_context); - free(scontext); - close(fd); - return; - } - syslog(LOG_WARNING, "Reset file context %s: %s->%s\n", - filename, prev_context, scontext); - } - if (retcontext >= 0) - free(prev_context); - } else { - if (errno != EOPNOTSUPP) - syslog(LOG_ERR, "get context on %s failed: '%s'\n", - filename, strerror(errno)); - } - free(scontext); - close(fd); -} - -static void process_config(int fd, FILE * cfg) -{ - char *line_buf = NULL; - size_t len = 0; - - while (getline(&line_buf, &len, cfg) > 0) { - char *buffer = line_buf; - while (isspace(*buffer)) - buffer++; - if (buffer[0] == '#') - continue; - int l = strlen(buffer) - 1; - if (l <= 0) - continue; - buffer[l] = 0; - if (buffer[0] == '~') - utmpwatcher_add(fd, &buffer[1]); - else { - watch_list_add(fd, buffer); - } - } - free(line_buf); -} - -/* - Read config file ignoring Comment lines - Files specified one per line. Files with "~" will be expanded to the logged in users - homedirs. -*/ -static void read_config(int fd) -{ - char *watch_file_path = "/etc/selinux/restorecond.conf"; +static char *server_watch_file = "/etc/selinux/restorecond.conf"; +static char *user_watch_file = "/etc/selinux/restorecond_user.conf"; +static char *watch_file; +static struct restore_opts r_opts; - FILE *cfg = NULL; - if (debug_mode) - printf("Read Config\n"); - - watch_list_free(fd); - - cfg = fopen(watch_file_path, "r"); - if (!cfg) - exitApp("Error reading config file."); - process_config(fd, cfg); - fclose(cfg); - - inotify_rm_watch(fd, master_wd); - master_wd = - inotify_add_watch(fd, watch_file_path, IN_MOVED_FROM | IN_MODIFY); - if (master_wd == -1) - exitApp("Error watching config file."); -} +#include -/* - Inotify watch loop -*/ -static int watch(int fd) -{ - char buf[BUF_LEN]; - int len, i = 0; - len = read(fd, buf, BUF_LEN); - if (len < 0) { - if (terminate == 0) { - syslog(LOG_ERR, "Read error (%s)", strerror(errno)); - return 0; - } - syslog(LOG_ERR, "terminated"); - 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 (debug_mode) - printf("wd=%d mask=%u cookie=%u len=%u\n", - event->wd, event->mask, - event->cookie, event->len); - if (event->wd == master_wd) - read_config(fd); - else { - switch (utmpwatcher_handle(fd, event->wd)) { - case -1: /* Message was not for utmpwatcher */ - if (event->len) - watch_list_find(event->wd, event->name); - break; - - case 1: /* utmp has changed need to reload */ - read_config(fd); - break; - - default: /* No users logged in or out */ - break; - } - } +int debug_mode = 0; +int terminate = 0; +int master_wd = -1; +int run_as_user = 0; - i += EVENT_SIZE + event->len; - } - return 0; +static void done(void) { + watch_list_free(master_fd); + close(master_fd); + utmpwatcher_free(); + matchpathcon_fini(); } static const char *pidfile = "/var/run/restorecond.pid"; @@ -374,7 +118,7 @@ static void usage(char *program) { - printf("%s [-d] [-v] \n", program); + printf("%s [-d] [-s] [-f restorecond_file ] [-v] \n", program); exit(0); } @@ -390,74 +134,35 @@ to see if it is one that we are watching. */ -void watch_list_add(int fd, const char *path) -{ - struct watchList *ptr = NULL; - struct watchList *prev = NULL; - char *x = strdup(path); - if (!x) - exitApp("Out of Memory"); - char *dir = dirname(x); - char *file = basename(path); - ptr = firstDir; - - restore(path, 1); - - while (ptr != NULL) { - if (strcmp(dir, ptr->dir) == 0) { - strings_list_add(&ptr->files, file); - free(x); - return; - } - prev = ptr; - ptr = ptr->next; - } - ptr = calloc(1, sizeof(struct watchList)); - - if (!ptr) - exitApp("Out of Memory"); - - ptr->wd = inotify_add_watch(fd, dir, IN_CREATE | IN_MOVED_TO); - if (ptr->wd == -1) { - free(ptr); - syslog(LOG_ERR, "Unable to watch (%s) %s\n", - path, strerror(errno)); - return; - } - - ptr->dir = strdup(dir); - if (!ptr->dir) - exitApp("Out of Memory"); - - strings_list_add(&ptr->files, file); - if (prev) - prev->next = ptr; - else - firstDir = ptr; - - if (debug_mode) - printf("%d: Dir=%s, File=%s\n", ptr->wd, ptr->dir, file); - - free(x); -} - int main(int argc, char **argv) { int opt; struct sigaction sa; -#ifndef DEBUG - /* Make sure we are root */ - if (getuid() != 0) { - fprintf(stderr, "You must be root to run this program.\n"); - return 1; - } -#endif - /* Make sure we are root */ - if (is_selinux_enabled() != 1) { - fprintf(stderr, "Daemon requires SELinux be enabled to run.\n"); - return 1; - } + memset(&r_opts, 0, sizeof(r_opts)); + + r_opts.progress = 0; + r_opts.count = 0; + r_opts.debug = 0; + r_opts.change = 1; + r_opts.verbose = 0; + r_opts.logging = 0; + r_opts.rootpath = NULL; + r_opts.expand_realpath = 0; + r_opts.rootpathlen = 0; + r_opts.outfile = NULL; + r_opts.force = 0; + r_opts.hard_links = 0; + r_opts.expand_realpath = 1; + r_opts.abort_on_error = 0; + r_opts.add_assoc = 0; + r_opts.fts_flags = FTS_PHYSICAL; + r_opts.selabel_opt_validate = NULL; + r_opts.selabel_opt_path = NULL; + + restore_init(&r_opts); + /* If we are not running SELinux then just exit */ + if (is_selinux_enabled() != 1) return 0; /* Register sighandlers */ sa.sa_flags = 0; @@ -467,38 +172,59 @@ set_matchpathcon_flags(MATCHPATHCON_NOTRANS); - master_fd = inotify_init(); - if (master_fd < 0) - exitApp("inotify_init"); - - while ((opt = getopt(argc, argv, "dv")) > 0) { + atexit( done ); + while ((opt = getopt(argc, argv, "uf:dv")) > 0) { switch (opt) { case 'd': debug_mode = 1; break; + case 'f': + watch_file = optarg; + break; + case 'u': + run_as_user = 1; + break; case 'v': - verbose_mode = 1; + r_opts.verbose++; break; case '?': usage(argv[0]); } } - read_config(master_fd); + + master_fd = inotify_init(); + if (master_fd < 0) + exitApp("inotify_init"); + + uid_t uid = getuid(); + struct passwd *pwd = getpwuid(uid); + homedir = pwd->pw_dir; + if (uid != 0) { + if (run_as_user) + return server(master_fd, user_watch_file); + if (start() != 0) + return server(master_fd, user_watch_file); + return 0; + } + + watch_file = server_watch_file; + read_config(master_fd, watch_file); if (!debug_mode) daemon(0, 0); write_pid_file(); - while (watch(master_fd) == 0) { + while (watch(master_fd, watch_file) == 0) { }; watch_list_free(master_fd); close(master_fd); matchpathcon_fini(); - utmpwatcher_free(); if (pidfile) unlink(pidfile); return 0; } + + diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/restorecond/restorecond.conf policycoreutils-2.0.71/restorecond/restorecond.conf --- nsapolicycoreutils/restorecond/restorecond.conf 2009-08-20 15:49:21.000000000 -0400 +++ policycoreutils-2.0.71/restorecond/restorecond.conf 2009-08-20 15:30:45.000000000 -0400 @@ -4,8 +4,5 @@ /etc/mtab /var/run/utmp /var/log/wtmp -~/* -/root/.ssh +/root/* /root/.ssh/* - - diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/restorecond/restorecond.desktop policycoreutils-2.0.71/restorecond/restorecond.desktop --- nsapolicycoreutils/restorecond/restorecond.desktop 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/restorecond/restorecond.desktop 2009-08-20 12:53:16.000000000 -0400 @@ -0,0 +1,7 @@ +[Desktop Entry] +Name=File Context maintainer +Exec=/usr/sbin/restorecond -u +Comment=Fix file context in owned by the user +Encoding=UTF-8 +Type=Application +StartupNotify=false diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/restorecond/restorecond.h policycoreutils-2.0.71/restorecond/restorecond.h --- nsapolicycoreutils/restorecond/restorecond.h 2009-08-20 15:49:21.000000000 -0400 +++ policycoreutils-2.0.71/restorecond/restorecond.h 2009-08-20 15:30:47.000000000 -0400 @@ -24,7 +24,21 @@ #ifndef RESTORED_CONFIG_H #define RESTORED_CONFIG_H -void exitApp(const char *msg); -void watch_list_add(int inotify_fd, const char *path); +extern int debug_mode; +extern const char *homedir; +extern int terminate; +extern int master_wd; +extern int run_as_user; + +extern int start(void); +extern int server(int, const char *watch_file); + +extern void exitApp(const char *msg); +extern void read_config(int fd, const char *watch_file); + +extern int watch(int fd, const char *watch_file); +extern void watch_list_add(int inotify_fd, const char *path); +extern int watch_list_find(int wd, const char *file); +extern void watch_list_free(int fd); #endif diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/restorecond/restorecond_user.conf policycoreutils-2.0.71/restorecond/restorecond_user.conf --- nsapolicycoreutils/restorecond/restorecond_user.conf 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/restorecond/restorecond_user.conf 2009-08-20 12:53:16.000000000 -0400 @@ -0,0 +1,2 @@ +~/* +~/public_html/* diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/restorecond/user.c policycoreutils-2.0.71/restorecond/user.c --- nsapolicycoreutils/restorecond/user.c 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/restorecond/user.c 2009-08-20 13:08:42.000000000 -0400 @@ -0,0 +1,237 @@ +/* + * restorecond + * + * Copyright (C) 2006-2009 Red Hat + * see file 'COPYING' for use and warranty information + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. +.* + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * Authors: + * Dan Walsh + * +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "restorecond.h" +#include "stringslist.h" +#include +#ifdef HAVE_DBUS +#include +#include +#include + +static DBusHandlerResult signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data); + +static const char *PATH="/org/selinux/Restorecond"; +//static const char *BUSNAME="org.selinux.Restorecond"; +static const char *INTERFACE="org.selinux.RestorecondIface"; +static const char *RULE="type='signal',interface='org.selinux.RestorecondIface'"; + + +static DBusHandlerResult +signal_filter (DBusConnection *connection __attribute__ ((__unused__)), DBusMessage *message, void *user_data) +{ + /* User data is the event loop we are running in */ + GMainLoop *loop = user_data; + + /* A signal from the bus saying we are about to be disconnected */ + if (dbus_message_is_signal + (message, INTERFACE, "Stop")) { + + /* Tell the main loop to quit */ + g_main_loop_quit (loop); + /* We have handled this message, don't pass it on */ + return DBUS_HANDLER_RESULT_HANDLED; + } + /* A Ping signal on the com.burtonini.dbus.Signal interface */ + else if (dbus_message_is_signal (message, INTERFACE, "Start")) { + DBusError error; + dbus_error_init (&error); + g_print("Start received\n"); + return DBUS_HANDLER_RESULT_HANDLED; + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static int dbus_server(GMainLoop *loop) { + DBusConnection *bus; + DBusError error; + dbus_error_init (&error); + bus = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (bus) { + dbus_connection_setup_with_g_main (bus, NULL); + + /* listening to messages from all objects as no path is specified */ + dbus_bus_add_match (bus, RULE, &error); // see signals from the given interfacey + dbus_connection_add_filter (bus, signal_filter, loop, NULL); + return 0; + } + return -1; +} + +#endif +#include +#include + +/* 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 gboolean +io_channel_callback + (GIOChannel *source, + GIOCondition condition, + gpointer data __attribute__((__unused__))) +{ + + char buffer[BUF_LEN+1]; + gsize bytes_read; + unsigned int i = 0; + + if (condition & G_IO_IN) { + /* Data is available. */ + g_io_channel_read + (source, buffer, + sizeof (buffer), + &bytes_read); + + while (i < bytes_read) { + struct inotify_event *event; + event = (struct inotify_event *)&buffer[i]; + if (debug_mode) + printf("wd=%d mask=%u cookie=%u len=%u\n", + event->wd, event->mask, + event->cookie, event->len); + if (event->len) + watch_list_find(event->wd, event->name); + + i += EVENT_SIZE + event->len; + } + } + + /* An error happened while reading + the file. */ + + if (condition & G_IO_NVAL) + return FALSE; + + /* We have reached the end of the + file. */ + + if (condition & G_IO_HUP) { + g_io_channel_close (source); + return FALSE; + } + + /* Returning TRUE will make sure + the callback remains associated + to the channel. */ + + return TRUE; +} + +int start() { +#ifdef HAVE_DBUS + DBusConnection *bus; + DBusError error; + DBusMessage *message; + + /* Get a connection to the session bus */ + dbus_error_init (&error); + bus = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (!bus) { + if (debug_mode) + g_warning ("Failed to connect to the D-BUS daemon: %s", error.message); + dbus_error_free (&error); + return 1; + } + + + /* Create a new signal "Start" on the interface, + * from the object */ + message = dbus_message_new_signal (PATH, + INTERFACE, "Start"); + /* Send the signal */ + dbus_connection_send (bus, message, NULL); + /* Free the signal now we have finished with it */ + dbus_message_unref (message); +#endif /* HAVE_DBUS */ + return 0; +} + +static int local_server() { + // ! dbus, run as local service + char *ptr=NULL; + asprintf(&ptr, "%s/.restorecond", homedir); + int fd = open(ptr, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR); + if (debug_mode) + g_warning ("Lock file: %s", ptr); + + free(ptr); + if (fd < 0) { + if (debug_mode) + perror("open"); + return -1; + } + if (flock(fd, LOCK_EX | LOCK_NB) < 0) { + if (debug_mode) + perror("flock"); + return -1; + } + return 0; +} + +int server(int master_fd, const char *watch_file) { + GMainLoop *loop; + + loop = g_main_loop_new (NULL, FALSE); + +#ifdef HAVE_DBUS + if (dbus_server(loop) != 0) +#endif /* HAVE_DBUS */ + if (local_server(loop) != 0) + return 0; + + read_config(master_fd, watch_file); + + set_matchpathcon_flags(MATCHPATHCON_NOTRANS); + + GIOChannel *c = g_io_channel_unix_new(master_fd); + + g_io_add_watch_full( c, + G_PRIORITY_HIGH, + G_IO_IN|G_IO_ERR|G_IO_HUP, + io_channel_callback, NULL, NULL); + + g_main_loop_run (loop); + return 0; +} + diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/restorecond/watch.c policycoreutils-2.0.71/restorecond/watch.c --- nsapolicycoreutils/restorecond/watch.c 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/restorecond/watch.c 2009-08-20 13:08:19.000000000 -0400 @@ -0,0 +1,254 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../setfiles/restore.h" +#include +#include +#include +#include +#include +#include +#include +#include "restorecond.h" +#include "stringslist.h" +#include "utmpwatcher.h" + +/* 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)) + + +struct watchList { + struct watchList *next; + int wd; + char *dir; + struct stringsList *files; +}; +struct watchList *firstDir = NULL; + + +void watch_list_add(int fd, const char *path) +{ + struct watchList *ptr = NULL; + size_t i = 0; + struct watchList *prev = NULL; + glob_t globbuf; + char *x = strdup(path); + if (!x) + exitApp("Out of Memory"); + char *file = basename(x); + char *dir = dirname(x); + ptr = firstDir; + + globbuf.gl_offs = 1; + if (glob(path, + GLOB_TILDE | GLOB_PERIOD, + NULL, + &globbuf) >= 0) { + for (i=0; i < globbuf.gl_pathc; i++) { + int len = strlen(globbuf.gl_pathv[i]) -2; + if (len > 0 && strcmp(&globbuf.gl_pathv[i][len--], "/.") == 0) continue; + if (len > 0 && strcmp(&globbuf.gl_pathv[i][len], "/..") == 0) continue; + if (process_one(globbuf.gl_pathv[i], 0) > 0) + process_one(globbuf.gl_pathv[i], 1); + } + globfree(&globbuf); + } + + while (ptr != NULL) { + if (strcmp(dir, ptr->dir) == 0) { + strings_list_add(&ptr->files, file); + free(x); + return; + } + prev = ptr; + ptr = ptr->next; + } + ptr = calloc(1, sizeof(struct watchList)); + + if (!ptr) + exitApp("Out of Memory"); + + ptr->wd = inotify_add_watch(fd, dir, IN_CREATE | IN_MOVED_TO); + if (ptr->wd == -1) { + free(ptr); + syslog(LOG_ERR, "Unable to watch (%s) %s\n", + path, strerror(errno)); + return; + } + + ptr->dir = strdup(dir); + if (!ptr->dir) + exitApp("Out of Memory"); + + strings_list_add(&ptr->files, file); + if (prev) + prev->next = ptr; + else + firstDir = ptr; + + if (debug_mode) + printf("%d: Dir=%s, File=%s\n", ptr->wd, ptr->dir, file); + + free(x); +} + +/* + A file was in a direcroty has been created. This function checks to + see if it is one that we are watching. +*/ + +int watch_list_find(int wd, const char *file) +{ + struct watchList *ptr = NULL; + ptr = firstDir; + if (debug_mode) + printf("%d: File=%s\n", wd, file); + while (ptr != NULL) { + if (ptr->wd == wd) { + int exact=0; + if (strings_list_find(ptr->files, file, &exact) == 0) { + char *path = NULL; + if (asprintf(&path, "%s/%s", ptr->dir, file) < + 0) + exitApp("Error allocating memory."); + + process_one(path, 0); + free(path); + return 0; + } + if (debug_mode) + strings_list_print(ptr->files); + + /* Not found in this directory */ + return -1; + } + ptr = ptr->next; + } + /* Did not find a directory */ + return -1; +} + +void watch_list_free(int fd) +{ + struct watchList *ptr = NULL; + struct watchList *prev = NULL; + ptr = firstDir; + + while (ptr != NULL) { + inotify_rm_watch(fd, ptr->wd); + strings_list_free(ptr->files); + free(ptr->dir); + prev = ptr; + ptr = ptr->next; + free(prev); + } + firstDir = NULL; +} + +/* + Inotify watch loop +*/ +int watch(int fd, const char *watch_file) +{ + char buf[BUF_LEN]; + int len, i = 0; + len = read(fd, buf, BUF_LEN); + if (len < 0) { + if (terminate == 0) { + syslog(LOG_ERR, "Read error (%s)", strerror(errno)); + return 0; + } + syslog(LOG_ERR, "terminated"); + 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 (debug_mode) + printf("wd=%d mask=%u cookie=%u len=%u\n", + event->wd, event->mask, + event->cookie, event->len); + if (event->wd == master_wd) + read_config(fd, watch_file); + else { + if (event->len) + watch_list_find(event->wd, event->name); + } + + i += EVENT_SIZE + event->len; + } + return 0; +} + +static void process_config(int fd, FILE * cfg) +{ + char *line_buf = NULL; + size_t len = 0; + + while (getline(&line_buf, &len, cfg) > 0) { + char *buffer = line_buf; + while (isspace(*buffer)) + buffer++; + if (buffer[0] == '#') + continue; + int l = strlen(buffer) - 1; + if (l <= 0) + continue; + buffer[l] = 0; + if (buffer[0] == '~') { + if (run_as_user) { + char *ptr=NULL; + asprintf(&ptr, "%s%s", homedir, &buffer[1]); + watch_list_add(fd, ptr); + free(ptr); + } else { + utmpwatcher_add(fd, &buffer[1]); + } + } else { + watch_list_add(fd, buffer); + } + } + free(line_buf); +} + +/* + Read config file ignoring Comment lines + Files specified one per line. Files with "~" will be expanded to the logged in users + homedirs. +*/ + +void read_config(int fd, const char *watch_file_path) +{ + + FILE *cfg = NULL; + if (debug_mode) + printf("Read Config\n"); + + watch_list_free(fd); + + cfg = fopen(watch_file_path, "r"); + if (!cfg){ + perror(watch_file_path); + exitApp("Error reading config file"); + } + process_config(fd, cfg); + fclose(cfg); + + inotify_rm_watch(fd, master_wd); + master_wd = + inotify_add_watch(fd, watch_file_path, IN_MOVED_FROM | IN_MODIFY); + if (master_wd == -1) + exitApp("Error watching config file."); +} + diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/scripts/chcat policycoreutils-2.0.71/scripts/chcat --- nsapolicycoreutils/scripts/chcat 2009-06-23 15:36:07.000000000 -0400 +++ policycoreutils-2.0.71/scripts/chcat 2009-08-20 12:53:16.000000000 -0400 @@ -435,6 +435,8 @@ continue except ValueError, e: error(e) + except OSError, e: + error(e) sys.exit(errors) diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/scripts/Makefile policycoreutils-2.0.71/scripts/Makefile --- nsapolicycoreutils/scripts/Makefile 2008-08-28 09:34:24.000000000 -0400 +++ policycoreutils-2.0.71/scripts/Makefile 2009-08-20 12:53:16.000000000 -0400 @@ -5,11 +5,12 @@ MANDIR ?= $(PREFIX)/share/man LOCALEDIR ?= /usr/share/locale -all: fixfiles genhomedircon +all: fixfiles genhomedircon sandbox chcat install: all -mkdir -p $(BINDIR) install -m 755 chcat $(BINDIR) + install -m 755 sandbox $(BINDIR) install -m 755 fixfiles $(DESTDIR)/sbin install -m 755 genhomedircon $(SBINDIR) -mkdir -p $(MANDIR)/man8 diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/scripts/sandbox policycoreutils-2.0.71/scripts/sandbox --- nsapolicycoreutils/scripts/sandbox 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/scripts/sandbox 2009-08-20 12:53:16.000000000 -0400 @@ -0,0 +1,139 @@ +#!/usr/bin/python -E +import os, sys, getopt, socket, random, fcntl +import selinux + +PROGNAME = "policycoreutils" + +import gettext +gettext.bindtextdomain(PROGNAME, "/usr/share/locale") +gettext.textdomain(PROGNAME) + +try: + gettext.install(PROGNAME, + localedir = "/usr/share/locale", + unicode=False, + codeset = 'utf-8') +except IOError: + import __builtin__ + __builtin__.__dict__['_'] = unicode + + +random.seed(None) + +def error_exit(msg): + sys.stderr.write("%s: " % sys.argv[0]) + sys.stderr.write("%s\n" % msg) + sys.stderr.flush() + sys.exit(1) + +def mount(context): + if os.getuid() != 0: + usage(_("Mount options require root privileges")) + destdir = "/mnt/%s" % context + os.mkdir(destdir) + rc = os.system('/bin/mount -t tmpfs tmpfs %s' % (destdir)) + selinux.setfilecon(destdir, context) + if rc != 0: + sys.exit(rc) + os.chdir(destdir) + +def umount(dest): + os.chdir("/") + destdir = "/mnt/%s" % dest + os.system('/bin/umount %s' % (destdir)) + os.rmdir(destdir) + + +def reserve(mcs): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind("\0%s" % mcs) + fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) + +def gen_context(setype): + while True: + i1 = random.randrange(0, 1024) + i2 = random.randrange(0, 1024) + if i1 == i2: + continue + if i1 > i2: + tmp = i1 + i1 = i2 + i2 = tmp + mcs = "s0:c%d,c%d" % (i1, i2) + reserve(mcs) + try: + reserve(mcs) + except: + continue + break + con = selinux.getcon()[1].split(":") + + execcon = "%s:%s:%s:%s" % (con[0], con[1], setype, mcs) + + filecon = "%s:%s:%s:%s" % (con[0], + "object_r", + "%s_file_t" % setype[:-2], + mcs) + return execcon, filecon + + +if __name__ == '__main__': + if selinux.is_selinux_enabled() != 1: + error_exit("Requires an SELinux enabled system") + + def usage(message = ""): + text = _(""" +sandbox [ -m ] [ -t type ] command +""") + error_exit("%s\n%s" % (message, text)) + + setype = "sandbox_t" + mount_ind = False + try: + gopts, cmds = getopt.getopt(sys.argv[1:], "ht:m", + ["help", + "type=", + "mount"]) + for o, a in gopts: + if o == "-t" or o == "--type": + setype = a + + if o == "-m" or o == "--mount": + mount_ind = True + + if o == "-h" or o == "--help": + usage(_("Usage")); + + if len(cmds) == 0: + usage(_("Command required")) + + execcon, filecon = gen_context(setype) + rc = -1 + if mount_ind: + mount(filecon) + + if cmds[0][0] != "/" and cmds[0][:2] != "./" and cmds[0][:3] != "../": + for i in os.environ["PATH"].split(':'): + f = "%s/%s" % (i, cmds[0]) + if os.access(f, os.X_OK): + cmds[0] = f + break + + selinux.setexeccon(execcon) + rc = os.spawnvp(os.P_WAIT, cmds[0], cmds) + selinux.setexeccon(None) + + if mount_ind: + umount(filecon) + except getopt.GetoptError, error: + usage(_("Options Error %s ") % error.msg) + except ValueError, error: + error_exit(error.args[0]) + except KeyError, error: + error_exit(_("Invalid value %s") % error.args[0]) + except IOError, error: + error_exit(error.args[1]) + except OSError, error: + error_exit(error.args[1]) + + sys.exit(rc) diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/scripts/sandbox.8 policycoreutils-2.0.71/scripts/sandbox.8 --- nsapolicycoreutils/scripts/sandbox.8 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/scripts/sandbox.8 2009-08-20 12:53:16.000000000 -0400 @@ -0,0 +1,22 @@ +.TH SANDBOX "8" "May 2009" "chcat" "User Commands" +.SH NAME +sandbox \- Run cmd under an SELinux sandbox +.SH SYNOPSIS +.B sandbox +[ -M ] [ -t type ] cmd +.br +.SH DESCRIPTION +.PP +Run application within a tightly confined SELinux domain, This application can only read and write stdin and stdout along with files handled to it by the shell. +.PP +.TP +\fB\-m\fR +Mount a temporary file system and change working directory to it, files will be removed when job completes. +.TP +\fB\-t type\fR +Use alternate sandbox type, defaults to sandbox_t +.TP +.SH "SEE ALSO" +.TP +runcon(1) +.PP diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/scripts/sandbox.py policycoreutils-2.0.71/scripts/sandbox.py --- nsapolicycoreutils/scripts/sandbox.py 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/scripts/sandbox.py 2009-08-20 12:53:16.000000000 -0400 @@ -0,0 +1,67 @@ +#!/usr/bin/python +import os, sys, getopt, socket, random, fcntl +import selinux + +random.seed(None) + +def mount(src, context): + destdir="/mnt/%s" % context + os.mkdir(destdir) + print 'mount -n -o "context=%s" %s %s' % (context, src, destdir) + os.chdir(destdir) + +def umount(dest): + os.chdir("/") + destdir="/mnt/%s" % dest + print ('umount -n %s' % destdir) + os.rmdir(destdir) + + +def reserve(mcs): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind("\0%s" % mcs) + fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) + +def gen_context(type): + while True: + i1 = random.randrange(0,1024) + i2 = random.randrange(0,1024) + if i1 == i2: + continue + if i1 > i2: + tmp = i1 + i1 = i2 + i2 = tmp + mcs = "s0:c%d,c%d" % (i1, i2) + reserve(mcs) + try: + reserve(mcs) + except: + continue + break + con = selinux.getcon()[1].split(":") + + execcon="%s:%s:%s:%s" % (con[0], con[1], type, mcs) + + filecon="%s:%s:%s:%s" % (con[0], "object_r", "%s_file_t" % type[:-2], mcs) + return execcon, filecon + + +type = "sandbox_t" +mount_src = None +gopts, cmds = getopt.getopt(sys.argv[1:],"t:m:", + ["type", + "mount"]) +for o, a in gopts: + if o == "-t" or o == "--type": + type = a + if o == "-m" or o == "--mount": + mount_src = a + +execcon, filecon = gen_context(type) +selinux.setexeccon(execcon) + +if mount_src != None: + mount(mount_src, filecon) + umount(filecon) +os.execvp(cmds[0], cmds) diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/semanage/semanage policycoreutils-2.0.71/semanage/semanage --- nsapolicycoreutils/semanage/semanage 2009-08-19 16:35:03.000000000 -0400 +++ policycoreutils-2.0.71/semanage/semanage 2009-08-20 12:53:16.000000000 -0400 @@ -68,6 +68,7 @@ -h, --help Display this message -n, --noheading Do not print heading when listing OBJECTS -S, --store Select and alternate SELinux store to manage + --dontaudit Turn on or off dontaudit rules Object-specific Options (see above): @@ -84,6 +85,7 @@ -F, --file Treat target as an input file for command, change multiple settings -p, --proto Port protocol (tcp or udp) or internet protocol version of node (ipv4 or ipv6) -M, --mask Netmask + -e, --equal Make target equal to this paths labeling -P, --prefix Prefix for home directory labeling -L, --level Default SELinux Level (MLS/MCS Systems only) -R, --roles SELinux Roles (ex: "sysadm_r staff_r") @@ -192,6 +194,9 @@ locallist = False use_file = False store = "" + equal="" + + dontaudit = "" object = argv[0] option_dict=get_options() @@ -201,10 +206,12 @@ args = argv[1:] gopts, cmds = getopt.getopt(args, - '01adf:i:lhmnp:s:FCDR:L:r:t:T:P:S:M:', + '01ade:f:i:lhmnp:s:FCDR:L:r:t:T:P:S:M:', ['add', 'delete', 'deleteall', + 'dontaudit=', + 'equal=', 'ftype=', 'file', 'help', @@ -248,9 +255,15 @@ if o == "-f" or o == "--ftype": ftype=a + if o == "-e" or o == "--equal": + equal = a + if o == "-F" or o == "--file": use_file = True + if o == "--dontaudit": + dontaudit = not int(a) + if o == "-h" or o == "--help": raise ValueError(_("%s bad option") % o) @@ -324,6 +337,9 @@ if object == "boolean": OBJECT = seobject.booleanRecords(store) + if object == "module": + OBJECT = seobject.moduleRecords(store) + if object == "translation": OBJECT = seobject.setransRecords() @@ -362,11 +378,17 @@ if object == "interface": OBJECT.add(target, serange, setype) + if object == "module": + OBJECT.add(target) + if object == "node": OBJECT.add(target, mask, proto, serange, setype) if object == "fcontext": - OBJECT.add(target, setype, ftype, serange, seuser) + if equal == "": + OBJECT.add(target, setype, ftype, serange, seuser) + else: + OBJECT.add_equal(target, equal) if object == "permissive": OBJECT.add(target) @@ -386,6 +408,9 @@ rlist = roles.split() OBJECT.modify(target, rlist, selevel, serange, prefix) + if object == "module": + OBJECT.modify(target) + if object == "port": OBJECT.modify(target, proto, serange, setype) @@ -396,7 +421,10 @@ OBJECT.modify(target, mask, proto, serange, setype) if object == "fcontext": - OBJECT.modify(target, setype, ftype, serange, seuser) + if equal == "": + OBJECT.modify(target, setype, ftype, serange, seuser) + else: + OBJECT.modify_equal(target, equal) return diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/semanage/seobject.py policycoreutils-2.0.71/semanage/seobject.py --- nsapolicycoreutils/semanage/seobject.py 2009-08-19 16:35:03.000000000 -0400 +++ policycoreutils-2.0.71/semanage/seobject.py 2009-08-20 12:53:16.000000000 -0400 @@ -1,5 +1,5 @@ #! /usr/bin/python -E -# Copyright (C) 2005, 2006, 2007, 2008 Red Hat +# Copyright (C) 2005, 2006, 2007, 2008, 2009 Red Hat # see file 'COPYING' for use and warranty information # # semanage is a tool for managing SELinux configuration files @@ -21,7 +21,7 @@ # # -import pwd, grp, string, selinux, tempfile, os, re, sys +import pwd, grp, string, selinux, tempfile, os, re, sys, stat from semanage import *; PROGNAME="policycoreutils" import sepolgen.module as module @@ -273,6 +273,7 @@ (fd, newfilename) = tempfile.mkstemp('', self.filename) os.write(fd, self.out()) os.close(fd) + os.chmod(newfilename, os.stat(self.filename)[stat.ST_MODE]) os.rename(newfilename, self.filename) os.system("/sbin/service mcstrans reload > /dev/null") @@ -983,7 +984,7 @@ proto_str = semanage_port_get_proto_str(proto) low = semanage_port_get_low(port) high = semanage_port_get_high(port) - ddict[(low, high)] = (ctype, proto_str, level) + ddict[(low, high, proto_str)] = (ctype, level) return ddict def get_all_by_type(self, locallist = 0): @@ -1408,6 +1409,48 @@ class fcontextRecords(semanageRecords): def __init__(self, store = ""): semanageRecords.__init__(self, store) + self.equiv = {} + self.equal_ind = False + try: + fd = open(selinux.selinux_file_context_subs_path(), "r") + for i in fd.readlines(): + src, dst = i.split() + self.equiv[src] = dst + fd.close() + except IOError: + pass + + def commit(self): + if self.equal_ind: + subs_file = selinux.selinux_file_context_subs_path() + tmpfile = "%s.tmp" % subs_file + fd = open(tmpfile, "w") + for src in self.equiv.keys(): + fd.write("%s %s\n" % (src, self.equiv[src])) + fd.close() + try: + os.chmod(tmpfile, os.stat(subs_file)[stat.ST_MODE]) + except: + pass + os.rename(tmpfile,subs_file) + self.equal_ind = False + semanageRecords.commit(self) + + def add_equal(self, src, dst): + self.begin() + if src in self.equiv.keys(): + raise ValueError(_("Equivalence class for %s already exists") % src) + self.equiv[src] = dst + self.equal_ind = True + self.commit() + + def modify_equal(self, src, dst): + self.begin() + if src not in self.equiv.keys(): + raise ValueError(_("Equivalence class for %s does not exists") % src) + self.equiv[src] = dst + self.equal_ind = True + self.commit() def createcon(self, target, seuser = "system_u"): (rc, con) = semanage_context_create(self.sh) @@ -1574,9 +1617,16 @@ raise ValueError(_("Could not delete the file context %s") % target) semanage_fcontext_key_free(k) + self.equiv = {} + self.equal_ind = True self.commit() def __delete(self, target, ftype): + if target in self.equiv.keys(): + self.equiv.pop(target) + self.equal_ind = True + return + (rc,k) = semanage_fcontext_key_create(self.sh, target, file_types[ftype]) if rc < 0: raise ValueError(_("Could not create a key for %s") % target) @@ -1632,11 +1682,11 @@ return ddict def list(self, heading = 1, locallist = 0 ): - if heading: - print "%-50s %-18s %s\n" % (_("SELinux fcontext"), _("type"), _("Context")) fcon_dict = self.get_all(locallist) keys = fcon_dict.keys() keys.sort() + if len(keys) > 0 and heading: + print "%-50s %-18s %s\n" % (_("SELinux fcontext"), _("type"), _("Context")) for k in keys: if fcon_dict[k]: if is_mls_enabled: @@ -1645,6 +1695,12 @@ print "%-50s %-18s %s:%s:%s " % (k[0], k[1], fcon_dict[k][0], fcon_dict[k][1],fcon_dict[k][2]) else: print "%-50s %-18s <>" % (k[0], k[1]) + if len(self.equiv.keys()) > 0: + if heading: + print _("\nSELinux fcontext Equivalence \n") + + for src in self.equiv.keys(): + print "%s == %s" % (src, self.equiv[src]) class booleanRecords(semanageRecords): def __init__(self, store = ""): diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/setfiles/Makefile policycoreutils-2.0.71/setfiles/Makefile --- nsapolicycoreutils/setfiles/Makefile 2009-07-07 15:32:32.000000000 -0400 +++ policycoreutils-2.0.71/setfiles/Makefile 2009-08-20 12:53:16.000000000 -0400 @@ -5,7 +5,7 @@ LIBDIR ?= $(PREFIX)/lib AUDITH = $(shell ls /usr/include/libaudit.h 2>/dev/null) -CFLAGS = -Werror -Wall -W +CFLAGS = -g -Werror -Wall -W override CFLAGS += -I$(PREFIX)/include LDLIBS = -lselinux -lsepol -L$(LIBDIR) @@ -16,7 +16,7 @@ all: setfiles restorecon -setfiles: setfiles.o +setfiles: setfiles.o restore.o restorecon: setfiles ln -sf setfiles restorecon diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/setfiles/restore.c policycoreutils-2.0.71/setfiles/restore.c --- nsapolicycoreutils/setfiles/restore.c 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/setfiles/restore.c 2009-08-20 13:11:02.000000000 -0400 @@ -0,0 +1,530 @@ +#include "restore.h" + +#define SKIP -2 +#define ERR -1 +#define MAX_EXCLUDES 1000 + +/* + * The hash table of associations, hashed by inode number. + * Chaining is used for collisions, with elements ordered + * by inode number in each bucket. Each hash bucket has a dummy + * header. + */ +#define HASH_BITS 16 +#define HASH_BUCKETS (1 << HASH_BITS) +#define HASH_MASK (HASH_BUCKETS-1) + +/* + * An association between an inode and a context. + */ +typedef struct file_spec { + ino_t ino; /* inode number */ + char *con; /* matched context */ + char *file; /* full pathname */ + struct file_spec *next; /* next association in hash bucket chain */ +} file_spec_t; + +struct edir { + char *directory; + size_t size; +}; + + +static file_spec_t *fl_head; +static int exclude(const char *file); +static int filespec_add(ino_t ino, const security_context_t con, const char *file); +static int only_changed_user(const char *a, const char *b); +struct restore_opts *r_opts = NULL; +static void filespec_destroy(void); +static void filespec_eval(void); +static int excludeCtr = 0; +static struct edir excludeArray[MAX_EXCLUDES]; + +void remove_exclude(const char *directory) +{ + int i = 0; + for (i = 0; i < excludeCtr; i++) { + if (strcmp(directory, excludeArray[i].directory) == 0) { + if (i != excludeCtr-1) + excludeArray[i] = excludeArray[excludeCtr-1]; + excludeCtr--; + return; + } + } + return; + +} + +void restore_init(struct restore_opts *opts) +{ + r_opts = opts; + struct selinux_opt selinux_opts[] = { + { SELABEL_OPT_VALIDATE, r_opts->selabel_opt_validate }, + { SELABEL_OPT_PATH, r_opts->selabel_opt_path } + }; + r_opts->hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 2); + if (!r_opts->hnd) { + perror(r_opts->selabel_opt_path); + exit(1); + } +} + +void restore_finish() +{ + int i; + for (i = 0; i < excludeCtr; i++) { + free(excludeArray[i].directory); + } +} + +static int match(const char *name, struct stat *sb, char **con) +{ + if (!(r_opts->hard_links) && !S_ISDIR(sb->st_mode) && (sb->st_nlink > 1)) { + fprintf(stderr, "Warning! %s refers to a hard link, not fixing hard links.\n", + name); + return -1; + } + + if (NULL != r_opts->rootpath) { + if (0 != strncmp(r_opts->rootpath, name, r_opts->rootpathlen)) { + fprintf(stderr, "%s: %s is not located in %s\n", + r_opts->progname, name, r_opts->rootpath); + return -1; + } + name += r_opts->rootpathlen; + } + + if (r_opts->rootpath != NULL && name[0] == '\0') + /* this is actually the root dir of the alt root */ + return selabel_lookup_raw(r_opts->hnd, con, "/", sb->st_mode); + else + return selabel_lookup_raw(r_opts->hnd, con, name, sb->st_mode); +} +static int restore(FTSENT *ftsent) +{ + char *my_file = strdupa(ftsent->fts_path); + int ret; + char *context, *newcon; + int user_only_changed = 0; + if (match(my_file, ftsent->fts_statp, &newcon) < 0) + /* Check for no matching specification. */ + return (errno == ENOENT) ? 0 : -1; + + if (r_opts->progress) { + r_opts->count++; + if (r_opts->count % (80 * STAR_COUNT) == 0) { + fprintf(stdout, "\n"); + fflush(stdout); + } + if (r_opts->count % STAR_COUNT == 0) { + fprintf(stdout, "*"); + fflush(stdout); + } + } + + /* + * Try to add an association between this inode and + * this specification. If there is already an association + * for this inode and it conflicts with this specification, + * then use the last matching specification. + */ + if (r_opts->add_assoc) { + ret = filespec_add(ftsent->fts_statp->st_ino, newcon, my_file); + if (ret < 0) + goto err; + + if (ret > 0) + /* There was already an association and it took precedence. */ + goto out; + } + + if (r_opts->debug) { + printf("%s: %s matched by %s\n", r_opts->progname, my_file, newcon); + } + + /* Get the current context of the file. */ + ret = lgetfilecon_raw(ftsent->fts_accpath, &context); + if (ret < 0) { + if (errno == ENODATA) { + context = NULL; + } else { + fprintf(stderr, "%s get context on %s failed: '%s'\n", + r_opts->progname, my_file, strerror(errno)); + goto err; + } + user_only_changed = 0; + } else + user_only_changed = only_changed_user(context, newcon); + /* lgetfilecon returns number of characters and ret needs to be reset + * to 0. + */ + ret = 0; + + /* + * Do not relabel the file if the matching specification is + * <> or the file is already labeled according to the + * specification. + */ + if ((strcmp(newcon, "<>") == 0) || + (context && (strcmp(context, newcon) == 0))) { + freecon(context); + goto out; + } + + if (!r_opts->force && context && (is_context_customizable(context) > 0)) { + if (r_opts->verbose > 1) { + fprintf(stderr, + "%s: %s not reset customized by admin to %s\n", + r_opts->progname, my_file, context); + } + freecon(context); + goto out; + } + + if (r_opts->verbose) { + /* If we're just doing "-v", trim out any relabels where + * the user has r_opts->changed but the role and type are the + * same. For "-vv", emit everything. */ + if (r_opts->verbose > 1 || !user_only_changed) { + printf("%s reset %s context %s->%s\n", + r_opts->progname, my_file, context ?: "", newcon); + } + } + + if (r_opts->logging && !user_only_changed) { + if (context) + syslog(LOG_INFO, "relabeling %s from %s to %s\n", + my_file, context, newcon); + else + syslog(LOG_INFO, "labeling %s to %s\n", + my_file, newcon); + } + + if (r_opts->outfile && !user_only_changed) + fprintf(r_opts->outfile, "%s\n", my_file); + + if (context) + freecon(context); + + /* + * Do not relabel the file if -n was used. + */ + if (!r_opts->change || user_only_changed) + goto out; + + /* + * Relabel the file to the specified context. + */ + ret = lsetfilecon(ftsent->fts_accpath, newcon); + if (ret) { + fprintf(stderr, "%s set context %s->%s failed:'%s'\n", + r_opts->progname, my_file, newcon, strerror(errno)); + goto skip; + } + ret = 1; +out: + freecon(newcon); + return ret; +skip: + freecon(newcon); + return SKIP; +err: + freecon(newcon); + return ERR; +} +/* + * Apply the last matching specification to a file. + * This function is called by fts on each file during + * the directory traversal. + */ +static int apply_spec(FTSENT *ftsent) +{ + if (ftsent->fts_info == FTS_DNR) { + fprintf(stderr, "%s: unable to read directory %s\n", + r_opts->progname, ftsent->fts_path); + return SKIP; + } + + int rc = restore(ftsent); + if (rc == ERR) { + if (!r_opts->abort_on_error) + return SKIP; + } + return rc; +} + +int process_one(char *name, int recurse) +{ + int rc = 0; + const char *namelist[2] = {name, NULL}; + dev_t dev_num = 0; + FTS *fts_handle; + FTSENT *ftsent; + + if (r_opts->expand_realpath) { + char *p; + p = realpath(name, NULL); + if (!p) { + fprintf(stderr, "realpath(%s) failed %s\n", name, + strerror(errno)); + return -1; + } + name = p; + } + + if (r_opts == NULL){ + fprintf(stderr, + "Must call initialize first!"); + goto err; + } + + fts_handle = fts_open((char **)namelist, r_opts->fts_flags, NULL); + if (fts_handle == NULL) { + fprintf(stderr, + "%s: error while labeling %s: %s\n", + r_opts->progname, namelist[0], strerror(errno)); + goto err; + } + + + ftsent = fts_read(fts_handle); + if (ftsent != NULL) { + /* Keep the inode of the first one. */ + dev_num = ftsent->fts_statp->st_dev; + } + + do { + rc = 0; + /* Skip the post order nodes. */ + if (ftsent->fts_info == FTS_DP) + continue; + /* If the XDEV flag is set and the device is different */ + if (ftsent->fts_statp->st_dev != dev_num && + FTS_XDEV == (r_opts->fts_flags & FTS_XDEV)) + continue; + if (excludeCtr > 0) { + if (exclude(ftsent->fts_path)) { + fts_set(fts_handle, ftsent, FTS_SKIP); + continue; + } + } + rc = apply_spec(ftsent); + if (rc == SKIP) + fts_set(fts_handle, ftsent, FTS_SKIP); + if (rc == ERR) + goto err; + if (!recurse) + break; + } while ((ftsent = fts_read(fts_handle)) != NULL); + + +out: + if (r_opts->add_assoc) { + if (!r_opts->quiet) + filespec_eval(); + filespec_destroy(); + } + if (fts_handle) + fts_close(fts_handle); + return rc; + +err: + rc = -1; + goto out; +} + +static int exclude(const char *file) +{ + int i = 0; + for (i = 0; i < excludeCtr; i++) { + if (strncmp + (file, excludeArray[i].directory, + excludeArray[i].size) == 0) { + if (file[excludeArray[i].size] == 0 + || file[excludeArray[i].size] == '/') { + return 1; + } + } + } + return 0; +} + +int add_exclude(const char *directory) +{ + size_t len = 0; + + if (directory == NULL || directory[0] != '/') { + fprintf(stderr, "Full path required for exclude: %s.\n", + directory); + return 1; + } + if (excludeCtr == MAX_EXCLUDES) { + fprintf(stderr, "Maximum excludes %d exceeded.\n", + MAX_EXCLUDES); + return 1; + } + + len = strlen(directory); + while (len > 1 && directory[len - 1] == '/') { + len--; + } + excludeArray[excludeCtr].directory = strndup(directory, len); + + if (excludeArray[excludeCtr].directory == NULL) { + fprintf(stderr, "Out of memory.\n"); + return 1; + } + excludeArray[excludeCtr++].size = len; + + return 0; +} + +/* Compare two contexts to see if their differences are "significant", + * or whether the only difference is in the user. */ +static int only_changed_user(const char *a, const char *b) +{ + char *rest_a, *rest_b; /* Rest of the context after the user */ + if (r_opts->force) + return 0; + if (!a || !b) + return 0; + rest_a = strchr(a, ':'); + rest_b = strchr(b, ':'); + if (!rest_a || !rest_b) + return 0; + return (strcmp(rest_a, rest_b) == 0); +} + +/* + * Evaluate the association hash table distribution. + */ +static void filespec_eval(void) +{ + file_spec_t *fl; + int h, used, nel, len, longest; + + if (!fl_head) + return; + + used = 0; + longest = 0; + nel = 0; + for (h = 0; h < HASH_BUCKETS; h++) { + len = 0; + for (fl = fl_head[h].next; fl; fl = fl->next) { + len++; + } + if (len) + used++; + if (len > longest) + longest = len; + nel += len; + } + + if (r_opts->verbose > 1) + printf + ("%s: hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n", + __FUNCTION__, nel, used, HASH_BUCKETS, longest); +} + +/* + * Destroy the association hash table. + */ +static void filespec_destroy(void) +{ + file_spec_t *fl, *tmp; + int h; + + if (!fl_head) + return; + + for (h = 0; h < HASH_BUCKETS; h++) { + fl = fl_head[h].next; + while (fl) { + tmp = fl; + fl = fl->next; + freecon(tmp->con); + free(tmp->file); + free(tmp); + } + fl_head[h].next = NULL; + } + free(fl_head); + fl_head = NULL; +} +/* + * Try to add an association between an inode and a context. + * If there is a different context that matched the inode, + * then use the first context that matched. + */ +static int filespec_add(ino_t ino, const security_context_t con, const char *file) +{ + file_spec_t *prevfl, *fl; + int h, ret; + struct stat sb; + + if (!fl_head) { + fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); + if (!fl_head) + goto oom; + memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); + } + + h = (ino + (ino >> HASH_BITS)) & HASH_MASK; + for (prevfl = &fl_head[h], fl = fl_head[h].next; fl; + prevfl = fl, fl = fl->next) { + if (ino == fl->ino) { + ret = lstat(fl->file, &sb); + if (ret < 0 || sb.st_ino != ino) { + freecon(fl->con); + free(fl->file); + fl->file = strdup(file); + if (!fl->file) + goto oom; + fl->con = strdup(con); + if (!fl->con) + goto oom; + return 1; + } + + if (strcmp(fl->con, con) == 0) + return 1; + + fprintf(stderr, + "%s: conflicting specifications for %s and %s, using %s.\n", + __FUNCTION__, file, fl->file, fl->con); + free(fl->file); + fl->file = strdup(file); + if (!fl->file) + goto oom; + return 1; + } + + if (ino > fl->ino) + break; + } + + fl = malloc(sizeof(file_spec_t)); + if (!fl) + goto oom; + fl->ino = ino; + fl->con = strdup(con); + if (!fl->con) + goto oom_freefl; + fl->file = strdup(file); + if (!fl->file) + goto oom_freefl; + fl->next = prevfl->next; + prevfl->next = fl; + return 0; + oom_freefl: + free(fl); + oom: + fprintf(stderr, + "%s: insufficient memory for file label entry for %s\n", + __FUNCTION__, file); + return -1; +} + + + diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/setfiles/restore.h policycoreutils-2.0.71/setfiles/restore.h --- nsapolicycoreutils/setfiles/restore.h 1969-12-31 19:00:00.000000000 -0500 +++ policycoreutils-2.0.71/setfiles/restore.h 2009-08-20 12:53:16.000000000 -0400 @@ -0,0 +1,50 @@ +#ifndef RESTORE_H +#define RESTORE_H +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STAR_COUNT 1000 + +/* Things that need to be init'd */ +struct restore_opts { + int add_assoc; /* Track inode associations for conflict detection. */ + int progress; + unsigned long long count; + int debug; + int change; + int hard_links; + int verbose; + int logging; + char *rootpath; + int rootpathlen; + char *progname; + FILE *outfile; + int force; + struct selabel_handle *hnd; + int expand_realpath; /* Expand paths via realpath. */ + int abort_on_error; /* Abort the file tree walk upon an error. */ + int quiet; + int fts_flags; /* Flags to fts, e.g. follow links, follow mounts */ + const char *selabel_opt_validate; + const char *selabel_opt_path; +}; + +void restore_init(struct restore_opts *opts); +void restore_finish(); +int add_exclude(const char *directory); +void remove_exclude(const char *directory); +int process_one(char *name, int recurse); + +#endif diff --exclude-from=exclude --exclude=sepolgen-1.0.17 --exclude=gui --exclude=po -N -u -r nsapolicycoreutils/setfiles/setfiles.c policycoreutils-2.0.71/setfiles/setfiles.c --- nsapolicycoreutils/setfiles/setfiles.c 2009-08-12 12:08:15.000000000 -0400 +++ policycoreutils-2.0.71/setfiles/setfiles.c 2009-08-20 12:53:16.000000000 -0400 @@ -1,26 +1,12 @@ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif +#include "restore.h" #include -#include #include -#include #include -#include -#include #include #include #include #include #define __USE_XOPEN_EXTENDED 1 /* nftw */ -#define SKIP -2 -#define ERR -1 -#include -#include -#include -#include -#include -#include #include #ifdef USE_AUDIT #include @@ -32,287 +18,28 @@ static int mass_relabel; static int mass_relabel_errs; -#define STAR_COUNT 1000 - -static FILE *outfile = NULL; -static int force = 0; -#define STAT_BLOCK_SIZE 1 -static int progress = 0; -static unsigned long long count = 0; -#define MAX_EXCLUDES 1000 -static int excludeCtr = 0; -struct edir { - char *directory; - size_t size; -}; -static struct edir excludeArray[MAX_EXCLUDES]; +/* cmdline opts*/ -/* - * Command-line options. - */ static char *policyfile = NULL; -static int debug = 0; -static int change = 1; -static int quiet = 0; -static int ignore_enoent; -static int verbose = 0; -static int logging = 0; static int warn_no_match = 0; static int null_terminated = 0; -static char *rootpath = NULL; -static int rootpathlen = 0; -static int recurse; /* Recursive descent. */ static int errors; +static int ignore_enoent; +static struct restore_opts r_opts; + +#define STAT_BLOCK_SIZE 1 + -static char *progname; #define SETFILES "setfiles" #define RESTORECON "restorecon" static int iamrestorecon; /* Behavior flags determined based on setfiles vs. restorecon */ -static int expand_realpath; /* Expand paths via realpath. */ -static int abort_on_error; /* Abort the file tree walk upon an error. */ -static int add_assoc; /* Track inode associations for conflict detection. */ -static int fts_flags; /* Flags to fts, e.g. follow links, follow mounts */ static int ctx_validate; /* Validate contexts */ static const char *altpath; /* Alternate path to file_contexts */ -/* Label interface handle */ -static struct selabel_handle *hnd; - -/* - * An association between an inode and a context. - */ -typedef struct file_spec { - ino_t ino; /* inode number */ - char *con; /* matched context */ - char *file; /* full pathname */ - struct file_spec *next; /* next association in hash bucket chain */ -} file_spec_t; - -/* - * The hash table of associations, hashed by inode number. - * Chaining is used for collisions, with elements ordered - * by inode number in each bucket. Each hash bucket has a dummy - * header. - */ -#define HASH_BITS 16 -#define HASH_BUCKETS (1 << HASH_BITS) -#define HASH_MASK (HASH_BUCKETS-1) -static file_spec_t *fl_head; - -/* - * Try to add an association between an inode and a context. - * If there is a different context that matched the inode, - * then use the first context that matched. - */ -int filespec_add(ino_t ino, const security_context_t con, const char *file) -{ - file_spec_t *prevfl, *fl; - int h, ret; - struct stat sb; - - if (!fl_head) { - fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); - if (!fl_head) - goto oom; - memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); - } - - h = (ino + (ino >> HASH_BITS)) & HASH_MASK; - for (prevfl = &fl_head[h], fl = fl_head[h].next; fl; - prevfl = fl, fl = fl->next) { - if (ino == fl->ino) { - ret = lstat(fl->file, &sb); - if (ret < 0 || sb.st_ino != ino) { - freecon(fl->con); - free(fl->file); - fl->file = strdup(file); - if (!fl->file) - goto oom; - fl->con = strdup(con); - if (!fl->con) - goto oom; - return 1; - } - - if (strcmp(fl->con, con) == 0) - return 1; - - fprintf(stderr, - "%s: conflicting specifications for %s and %s, using %s.\n", - __FUNCTION__, file, fl->file, fl->con); - free(fl->file); - fl->file = strdup(file); - if (!fl->file) - goto oom; - return 1; - } - - if (ino > fl->ino) - break; - } - - fl = malloc(sizeof(file_spec_t)); - if (!fl) - goto oom; - fl->ino = ino; - fl->con = strdup(con); - if (!fl->con) - goto oom_freefl; - fl->file = strdup(file); - if (!fl->file) - goto oom_freefl; - fl->next = prevfl->next; - prevfl->next = fl; - return 0; - oom_freefl: - free(fl); - oom: - fprintf(stderr, - "%s: insufficient memory for file label entry for %s\n", - __FUNCTION__, file); - return -1; -} - -/* - * Evaluate the association hash table distribution. - */ -void filespec_eval(void) -{ - file_spec_t *fl; - int h, used, nel, len, longest; - - if (!fl_head) - return; - - used = 0; - longest = 0; - nel = 0; - for (h = 0; h < HASH_BUCKETS; h++) { - len = 0; - for (fl = fl_head[h].next; fl; fl = fl->next) { - len++; - } - if (len) - used++; - if (len > longest) - longest = len; - nel += len; - } - - printf - ("%s: hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n", - __FUNCTION__, nel, used, HASH_BUCKETS, longest); -} - -/* - * Destroy the association hash table. - */ -void filespec_destroy(void) -{ - file_spec_t *fl, *tmp; - int h; - - if (!fl_head) - return; - - for (h = 0; h < HASH_BUCKETS; h++) { - fl = fl_head[h].next; - while (fl) { - tmp = fl; - fl = fl->next; - freecon(tmp->con); - free(tmp->file); - free(tmp); - } - fl_head[h].next = NULL; - } - free(fl_head); - fl_head = NULL; -} - -static int add_exclude(const char *directory) -{ - size_t len = 0; - - if (directory == NULL || directory[0] != '/') { - fprintf(stderr, "Full path required for exclude: %s.\n", - directory); - return 1; - } - if (excludeCtr == MAX_EXCLUDES) { - fprintf(stderr, "Maximum excludes %d exceeded.\n", - MAX_EXCLUDES); - return 1; - } - - len = strlen(directory); - while (len > 1 && directory[len - 1] == '/') { - len--; - } - excludeArray[excludeCtr].directory = strndup(directory, len); - - if (excludeArray[excludeCtr].directory == NULL) { - fprintf(stderr, "Out of memory.\n"); - return 1; - } - excludeArray[excludeCtr++].size = len; - - return 0; -} - -static void remove_exclude(const char *directory) -{ - int i = 0; - for (i = 0; i < excludeCtr; i++) { - if (strcmp(directory, excludeArray[i].directory) == 0) { - free(excludeArray[i].directory); - if (i != excludeCtr-1) - excludeArray[i] = excludeArray[excludeCtr-1]; - excludeCtr--; - return; - } - } - return; -} - -static int exclude(const char *file) -{ - int i = 0; - for (i = 0; i < excludeCtr; i++) { - if (strncmp - (file, excludeArray[i].directory, - excludeArray[i].size) == 0) { - if (file[excludeArray[i].size] == 0 - || file[excludeArray[i].size] == '/') { - return 1; - } - } - } - return 0; -} - -int match(const char *name, struct stat *sb, char **con) -{ - if (NULL != rootpath) { - if (0 != strncmp(rootpath, name, rootpathlen)) { - fprintf(stderr, "%s: %s is not located in %s\n", - progname, name, rootpath); - return -1; - } - name += rootpathlen; - } - - if (rootpath != NULL && name[0] == '\0') - /* this is actually the root dir of the alt root */ - return selabel_lookup_raw(hnd, con, "/", sb->st_mode); - else - return selabel_lookup_raw(hnd, con, name, sb->st_mode); -} - void usage(const char *const name) { if (iamrestorecon) { @@ -334,194 +61,30 @@ void inc_err() { nerr++; - if (nerr > 9 && !debug) { + if (nerr > 9 && !r_opts.debug) { fprintf(stderr, "Exiting after 10 errors.\n"); exit(1); } } -/* Compare two contexts to see if their differences are "significant", - * or whether the only difference is in the user. */ -static int only_changed_user(const char *a, const char *b) -{ - char *rest_a, *rest_b; /* Rest of the context after the user */ - if (force) - return 0; - if (!a || !b) - return 0; - rest_a = strchr(a, ':'); - rest_b = strchr(b, ':'); - if (!rest_a || !rest_b) - return 0; - return (strcmp(rest_a, rest_b) == 0); -} - -static int restore(FTSENT *ftsent) -{ - char *my_file = strdupa(ftsent->fts_path); - int ret; - char *context, *newcon; - int user_only_changed = 0; - - if (match(my_file, ftsent->fts_statp, &newcon) < 0) - /* Check for no matching specification. */ - return (errno == ENOENT) ? 0 : -1; - - if (progress) { - count++; - if (count % (80 * STAR_COUNT) == 0) { - fprintf(stdout, "\n"); - fflush(stdout); - } - if (count % STAR_COUNT == 0) { - fprintf(stdout, "*"); - fflush(stdout); - } - } - - /* - * Try to add an association between this inode and - * this specification. If there is already an association - * for this inode and it conflicts with this specification, - * then use the last matching specification. - */ - if (add_assoc) { - ret = filespec_add(ftsent->fts_statp->st_ino, newcon, my_file); - if (ret < 0) - goto err; - - if (ret > 0) - /* There was already an association and it took precedence. */ - goto out; - } - - if (debug) { - printf("%s: %s matched by %s\n", progname, my_file, newcon); - } - - /* Get the current context of the file. */ - ret = lgetfilecon_raw(ftsent->fts_accpath, &context); - if (ret < 0) { - if (errno == ENODATA) { - context = NULL; - } else { - fprintf(stderr, "%s get context on %s failed: '%s'\n", - progname, my_file, strerror(errno)); - goto err; - } - user_only_changed = 0; - } else - user_only_changed = only_changed_user(context, newcon); - - /* - * Do not relabel the file if the matching specification is - * <> or the file is already labeled according to the - * specification. - */ - if ((strcmp(newcon, "<>") == 0) || - (context && (strcmp(context, newcon) == 0))) { - freecon(context); - goto out; - } - - if (!force && context && (is_context_customizable(context) > 0)) { - if (verbose > 1) { - fprintf(stderr, - "%s: %s not reset customized by admin to %s\n", - progname, my_file, context); - } - freecon(context); - goto out; - } - - if (verbose) { - /* If we're just doing "-v", trim out any relabels where - * the user has changed but the role and type are the - * same. For "-vv", emit everything. */ - if (verbose > 1 || !user_only_changed) { - printf("%s reset %s context %s->%s\n", - progname, my_file, context ?: "", newcon); - } - } - - if (logging && !user_only_changed) { - if (context) - syslog(LOG_INFO, "relabeling %s from %s to %s\n", - my_file, context, newcon); - else - syslog(LOG_INFO, "labeling %s to %s\n", - my_file, newcon); - } - - if (outfile && !user_only_changed) - fprintf(outfile, "%s\n", my_file); - - if (context) - freecon(context); - - /* - * Do not relabel the file if -n was used. - */ - if (!change || user_only_changed) - goto out; - - /* - * Relabel the file to the specified context. - */ - ret = lsetfilecon(ftsent->fts_accpath, newcon); - if (ret) { - fprintf(stderr, "%s set context %s->%s failed:'%s'\n", - progname, my_file, newcon, strerror(errno)); - goto skip; - } -out: - freecon(newcon); - return 0; -skip: - freecon(newcon); - return SKIP; -err: - freecon(newcon); - return ERR; -} - -/* - * Apply the last matching specification to a file. - * This function is called by fts on each file during - * the directory traversal. - */ -static int apply_spec(FTSENT *ftsent) -{ - if (ftsent->fts_info == FTS_DNR) { - fprintf(stderr, "%s: unable to read directory %s\n", - progname, ftsent->fts_path); - return SKIP; - } - int rc = restore(ftsent); - if (rc == ERR) { - if (!abort_on_error) - return SKIP; - } - return rc; -} void set_rootpath(const char *arg) { int len; - rootpath = strdup(arg); - if (NULL == rootpath) { - fprintf(stderr, "%s: insufficient memory for rootpath\n", - progname); + r_opts.rootpath = strdup(arg); + if (NULL == r_opts.rootpath) { + fprintf(stderr, "%s: insufficient memory for r_opts.rootpath\n", + r_opts.progname); exit(1); } /* trim trailing /, if present */ - len = strlen(rootpath); - while (len && ('/' == rootpath[len - 1])) - rootpath[--len] = 0; - rootpathlen = len; + len = strlen(r_opts.rootpath); + while (len && ('/' == r_opts.rootpath[len - 1])) + r_opts.rootpath[--len] = 0; + r_opts.rootpathlen = len; } int canoncon(char **contextp) @@ -545,90 +108,7 @@ return rc; } -static int process_one(char *name) -{ - int rc = 0; - const char *namelist[2]; - dev_t dev_num = 0; - FTS *fts_handle; - FTSENT *ftsent; - - if (expand_realpath) { - char *p; - p = realpath(name, NULL); - if (!p) { - fprintf(stderr, "realpath(%s) failed %s\n", name, - strerror(errno)); - return -1; - } - name = p; - } - - - if (!strcmp(name, "/")) - mass_relabel = 1; - - namelist[0] = name; - namelist[1] = NULL; - fts_handle = fts_open((char **)namelist, fts_flags, NULL); - if (fts_handle == NULL) { - fprintf(stderr, - "%s: error while labeling %s: %s\n", - progname, namelist[0], strerror(errno)); - goto err; - } - - ftsent = fts_read(fts_handle); - if (ftsent != NULL) { - /* Keep the inode of the first one. */ - dev_num = ftsent->fts_statp->st_dev; - } - - do { - /* Skip the post order nodes. */ - if (ftsent->fts_info == FTS_DP) - continue; - /* If the XDEV flag is set and the device is different */ - if (ftsent->fts_statp->st_dev != dev_num && - FTS_XDEV == (fts_flags & FTS_XDEV)) - continue; - if (excludeCtr > 0) { - if (exclude(ftsent->fts_path)) { - fts_set(fts_handle, ftsent, FTS_SKIP); - continue; - } - } - int rc = apply_spec(ftsent); - if (rc == SKIP) - fts_set(fts_handle, ftsent, FTS_SKIP); - if (rc == ERR) - goto err; - if (!recurse) - break; - } while ((ftsent = fts_read(fts_handle)) != NULL); - - if (!strcmp(name, "/")) - mass_relabel_errs = 0; - -out: - if (add_assoc) { - if (!quiet) - filespec_eval(); - filespec_destroy(); - } - if (fts_handle) - fts_close(fts_handle); - if (expand_realpath) - free(name); - return rc; - -err: - if (!strcmp(name, "/")) - mass_relabel_errs = 1; - rc = -1; - goto out; -} #ifndef USE_AUDIT static void maybe_audit_mass_relabel(void) @@ -729,21 +209,32 @@ int use_input_file = 0; char *buf = NULL; size_t buf_len; + int recurse; /* Recursive descent. */ char *base; - struct selinux_opt opts[] = { - { SELABEL_OPT_VALIDATE, NULL }, - { SELABEL_OPT_PATH, NULL } - }; + + memset(&r_opts, 0, sizeof(r_opts)); + + /* Initialize variables */ + r_opts.progress = 0; + r_opts.count = 0; + r_opts.debug = 0; + r_opts.change = 1; + r_opts.verbose = 0; + r_opts.logging = 0; + r_opts.rootpath = NULL; + r_opts.rootpathlen = 0; + r_opts.outfile = NULL; + r_opts.force = 0; + r_opts.hard_links = 1; - memset(excludeArray, 0, sizeof(excludeArray)); altpath = NULL; - progname = strdup(argv[0]); - if (!progname) { + r_opts.progname = strdup(argv[0]); + if (!r_opts.progname) { fprintf(stderr, "%s: Out of memory!\n", argv[0]); exit(1); } - base = basename(progname); + base = basename(r_opts.progname); if (!strcmp(base, SETFILES)) { /* @@ -757,10 +248,10 @@ */ iamrestorecon = 0; recurse = 1; - expand_realpath = 0; - abort_on_error = 1; - add_assoc = 1; - fts_flags = FTS_PHYSICAL | FTS_XDEV; + r_opts.expand_realpath = 0; + r_opts.abort_on_error = 1; + r_opts.add_assoc = 1; + r_opts.fts_flags = FTS_PHYSICAL | FTS_XDEV; ctx_validate = 1; } else { /* @@ -772,14 +263,14 @@ * Follows mounts, * Does lazy validation of contexts upon use. */ - if (strcmp(base, RESTORECON) && !quiet) + if (strcmp(base, RESTORECON) && !r_opts.quiet) printf("Executed with an unrecognized name (%s), defaulting to %s behavior.\n", base, RESTORECON); iamrestorecon = 1; recurse = 0; - expand_realpath = 1; - abort_on_error = 0; - add_assoc = 0; - fts_flags = FTS_PHYSICAL; + r_opts.expand_realpath = 1; + r_opts.abort_on_error = 0; + r_opts.add_assoc = 0; + r_opts.fts_flags = FTS_PHYSICAL; ctx_validate = 0; /* restorecon only: silent exit if no SELinux. @@ -828,11 +319,6 @@ } case 'e': remove_exclude(optarg); - if (lstat(optarg, &sb) < 0 && errno != EACCES) { - fprintf(stderr, "Can't stat exclude path \"%s\", %s - ignoring.\n", - optarg, strerror(errno)); - break; - } if (add_exclude(optarg)) exit(1); break; @@ -841,37 +327,37 @@ input_filename = optarg; break; case 'd': - debug = 1; + r_opts.debug = 1; break; case 'i': ignore_enoent = 1; break; case 'l': - logging = 1; + r_opts.logging = 1; break; case 'F': - force = 1; + r_opts.force = 1; break; case 'n': - change = 0; + r_opts.change = 0; break; case 'o': if (strcmp(optarg, "-") == 0) { - outfile = stdout; + r_opts.outfile = stdout; break; } - outfile = fopen(optarg, "w"); - if (!outfile) { + r_opts.outfile = fopen(optarg, "w"); + if (!r_opts.outfile) { fprintf(stderr, "Error opening %s: %s\n", optarg, strerror(errno)); usage(argv[0]); } - __fsetlocking(outfile, FSETLOCKING_BYCALLER); + __fsetlocking(r_opts.outfile, FSETLOCKING_BYCALLER); break; case 'q': - quiet = 1; + r_opts.quiet = 1; break; case 'R': case 'r': @@ -880,11 +366,11 @@ break; } if (optind + 1 >= argc) { - fprintf(stderr, "usage: %s -r rootpath\n", + fprintf(stderr, "usage: %s -r r_opts.rootpath\n", argv[0]); exit(1); } - if (NULL != rootpath) { + if (NULL != r_opts.rootpath) { fprintf(stderr, "%s: only one -r can be specified\n", argv[0]); @@ -895,23 +381,23 @@ case 's': use_input_file = 1; input_filename = "-"; - add_assoc = 0; + r_opts.add_assoc = 0; break; case 'v': - if (progress) { + if (r_opts.progress) { fprintf(stderr, "Progress and Verbose mutually exclusive\n"); exit(1); } - verbose++; + r_opts.verbose++; break; case 'p': - if (verbose) { + if (r_opts.verbose) { fprintf(stderr, "Progress and Verbose mutually exclusive\n"); usage(argv[0]); } - progress = 1; + r_opts.progress = 1; break; case 'W': warn_no_match = 1; @@ -959,18 +445,13 @@ } /* Load the file contexts configuration and check it. */ - opts[0].value = (ctx_validate ? (char*)1 : NULL); - opts[1].value = altpath; - - hnd = selabel_open(SELABEL_CTX_FILE, opts, 2); - if (!hnd) { - perror(altpath); - exit(1); - } + r_opts.selabel_opt_validate = (ctx_validate ? (char *)1 : NULL); + r_opts.selabel_opt_path = altpath; if (nerr) exit(1); + restore_init(&r_opts); if (use_input_file) { FILE *f = stdin; ssize_t len; @@ -987,31 +468,34 @@ delim = (null_terminated != 0) ? '\0' : '\n'; while ((len = getdelim(&buf, &buf_len, delim, f)) > 0) { buf[len - 1] = 0; - errors |= process_one(buf); + if (!strcmp(buf, "/")) + mass_relabel = 1; + errors |= process_one(buf, recurse) < 0; } if (strcmp(input_filename, "-") != 0) fclose(f); } else { for (i = optind; i < argc; i++) { - errors |= process_one(argv[i]); + if (!strcmp(argv[i], "/")) + mass_relabel = 1; + errors |= process_one(argv[i], recurse) < 0; } } - + + if (mass_relabel) + mass_relabel_errs = errors; maybe_audit_mass_relabel(); if (warn_no_match) - selabel_stats(hnd); - - selabel_close(hnd); + selabel_stats(r_opts.hnd); - if (outfile) - fclose(outfile); + selabel_close(r_opts.hnd); + restore_finish(); - for (i = 0; i < excludeCtr; i++) { - free(excludeArray[i].directory); - } + if (r_opts.outfile) + fclose(r_opts.outfile); - if (progress && count >= STAR_COUNT) + if (r_opts.progress && r_opts.count >= STAR_COUNT) printf("\n"); exit(errors); }