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/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); }