Blob Blame History Raw
diff --git a/policycoreutils/Makefile b/policycoreutils/Makefile
index 86ed03f..3e95698 100644
--- a/policycoreutils/Makefile
+++ b/policycoreutils/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS = setfiles semanage load_policy newrole run_init sandbox secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps setsebool po
+SUBDIRS = setfiles semanage semanage/default_encoding load_policy newrole run_init sandbox secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps sepolgen-ifgen setsebool po
 
 INOTIFYH = $(shell ls /usr/include/sys/inotify.h 2>/dev/null)
 
diff --git a/policycoreutils/audit2allow/audit2allow b/policycoreutils/audit2allow/audit2allow
index 5435e9d..c60490b 100644
--- a/policycoreutils/audit2allow/audit2allow
+++ b/policycoreutils/audit2allow/audit2allow
@@ -1,4 +1,4 @@
-#! /usr/bin/python -E
+#! /usr/bin/python -Es
 # Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
 #
 # Copyright (C) 2006-2007  Red Hat
@@ -28,6 +28,7 @@ import sepolgen.objectmodel as objectmodel
 import sepolgen.defaults as defaults
 import sepolgen.module as module
 from sepolgen.sepolgeni18n import _
+import selinux.audit2why as audit2why
 
 class AuditToPolicy:
     VERSION = "%prog .1"
@@ -46,6 +47,7 @@ class AuditToPolicy:
                           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("-p", "--policy", dest="policy", default=None, help="Policy file to use for analysis")
         parser.add_option("-d", "--dmesg", action="store_true", dest="dmesg", default=False,
                           help="read input from dmesg - conflicts with --all and --input")
         parser.add_option("-i", "--input", dest="input",
@@ -231,29 +233,12 @@ class AuditToPolicy:
 
     def __output_audit2why(self):
             import selinux
-            import selinux.audit2why as audit2why
             import seobject
-            audit2why.init()
             for i in self.__parser.avc_msgs:
-                rc, bools = audit2why.analyze(i.scontext.to_string(), i.tcontext.to_string(), i.tclass, i.accesses)
+                rc = i.type
+                bools = i.bools
                 if rc >= 0:
                     print "%s\n\tWas caused by:" % i.message
-                if rc == audit2why.NOPOLICY:
-                    raise RuntimeError("Must call policy_init first")
-                if rc == audit2why.BADTCON:
-                    print "Invalid Target Context %s\n" % i.tcontext
-                    continue
-                if rc == audit2why.BADSCON:
-                    print "Invalid Source Context %s\n" % i.scontext
-                    continue
-                if rc == audit2why.BADSCON:
-                    print "Invalid Type Class %s\n" % i.tclass
-                    continue
-                if rc == audit2why.BADPERM:
-                    print "Invalid permission %s\n" % i.accesses
-                    continue
-                if rc == audit2why. BADCOMPUTE:
-                    raise RuntimeError("Error during access vector computation")
                 if rc == audit2why.ALLOW:
                     print "\t\tUnknown - would be allowed by active policy\n",
                     print "\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n"
@@ -350,11 +335,19 @@ class AuditToPolicy:
     def main(self):
         try:
             self.__parse_options()
+            if self.__options.policy:
+                audit2why.init(self.__options.policy)
+            else:
+                audit2why.init()
+
             self.__read_input()
             self.__process_input()
             self.__output()
         except KeyboardInterrupt:
             sys.exit(0)
+        except ValueError, e:
+            print e
+            sys.exit(1)
 
 if __name__ == "__main__":
     app = AuditToPolicy()
diff --git a/policycoreutils/audit2allow/audit2allow.1 b/policycoreutils/audit2allow/audit2allow.1
index fd9eb88..a854a45 100644
--- a/policycoreutils/audit2allow/audit2allow.1
+++ b/policycoreutils/audit2allow/audit2allow.1
@@ -67,6 +67,9 @@ Generate module/require output <modulename>
 .B "\-M <modulename>" 
 Generate loadable module package, conflicts with -o
 .TP
+.B "\-p <policyfile>"  | "\-\-policy <policyfile>"
+Policy file to use for analysis
+.TP
 .B "\-o <outputfile>"  | "\-\-output <outputfile>"
 append output to 
 .I <outputfile>
diff --git a/policycoreutils/audit2allow/sepolgen-ifgen b/policycoreutils/audit2allow/sepolgen-ifgen
index 0acbf7e..ef4bec3 100644
--- a/policycoreutils/audit2allow/sepolgen-ifgen
+++ b/policycoreutils/audit2allow/sepolgen-ifgen
@@ -28,6 +28,10 @@
 
 import sys
 import os
+import tempfile
+import subprocess
+
+import selinux
 
 import sepolgen.refparser as refparser
 import sepolgen.defaults as defaults
@@ -35,6 +39,7 @@ import sepolgen.interfaces as interfaces
 
 
 VERSION = "%prog .1"
+ATTR_HELPER = "/usr/bin/sepolgen-ifgen-attr-helper"
 
 def parse_options():
     from optparse import OptionParser
@@ -44,14 +49,58 @@ def parse_options():
                       help="filename to store output")
     parser.add_option("-i", "--interfaces", dest="headers", default=defaults.headers(),
                       help="location of the interface header files")
+    parser.add_option("-a", "--attribute_info", dest="attribute_info")
+    parser.add_option("-p", "--policy", dest="policy_path")
     parser.add_option("-v", "--verbose", action="store_true", default=False,
                       help="print debuging output")
     parser.add_option("-d", "--debug", action="store_true", default=False,
                      help="extra debugging output")
+    parser.add_option("--no_attrs", action="store_true", default=False,
+                      help="do not retrieve attribute access from kernel policy")
     options, args = parser.parse_args()
     
     return options
 
+def get_policy():
+    i = selinux.security_policyvers()
+    p = selinux.selinux_binary_policy_path() + "." + str(i)
+    while i > 0 and not os.path.exists(p):
+        i = i - 1
+        p = selinux.selinux_binary_policy_path() + "." + str(i)
+    if i > 0:
+        return p
+    return None
+
+def get_attrs(policy_path):
+    try:
+        if not policy_path:
+            policy_path = get_policy()
+        if not policy_path:
+            sys.stderr.write("No installed policy to check\n")
+            return None
+        outfile = tempfile.NamedTemporaryFile()
+    except IOError, e:
+        sys.stderr.write("could not open attribute output file\n")
+        return None
+    except OSError:
+        # SELinux Disabled Machine
+        return None
+
+    fd = open("/dev/null","w")
+    ret = subprocess.Popen([ATTR_HELPER, policy_path, outfile.name], stdout=fd).wait()
+    fd.close()
+    if ret != 0:
+        sys.stderr.write("could not run attribute helper")
+        return None
+
+    attrs = interfaces.AttributeSet()
+    try:
+        attrs.from_file(outfile)
+    except:
+        print "error parsing attribute info"
+        return None
+
+    return attrs
 
 def main():
     options = parse_options()
@@ -68,6 +117,14 @@ def main():
     else:
         log = None
 
+    # Get the attibutes from the binary
+    attrs = None
+    if not options.no_attrs:
+        attrs = get_attrs(options.policy_path)
+        if attrs is None:
+            return 1
+
+    # Parse the headers
     try:
         headers = refparser.parse_headers(options.headers, output=log, debug=options.debug)
     except ValueError, e:
@@ -76,7 +133,7 @@ def main():
         return 1
 
     if_set = interfaces.InterfaceSet(output=log)
-    if_set.add_headers(headers)
+    if_set.add_headers(headers, attributes=attrs)
     if_set.to_file(f)
     f.close()
 
diff --git a/policycoreutils/newrole/newrole.c b/policycoreutils/newrole/newrole.c
index 99d0ed7..3f08d37 100644
--- a/policycoreutils/newrole/newrole.c
+++ b/policycoreutils/newrole/newrole.c
@@ -1030,10 +1030,11 @@ int main(int argc, char *argv[])
 	 * if it makes sense to continue to run newrole, and setting up
 	 * a scrubbed environment.
 	 */
-	if (drop_capabilities(FALSE)) {
+/*	if (drop_capabilities(FALSE)) {
 		perror(_("Sorry, newrole failed to drop capabilities\n"));
 		return -1;
 	}
+*/
 	if (set_signal_handles())
 		return -1;
 
diff --git a/policycoreutils/restorecond/Makefile b/policycoreutils/restorecond/Makefile
index 3f235e6..03a4544 100644
--- a/policycoreutils/restorecond/Makefile
+++ b/policycoreutils/restorecond/Makefile
@@ -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 -ldbus-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 @@ install: all
 	-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 --git a/policycoreutils/restorecond/org.selinux.Restorecond.service b/policycoreutils/restorecond/org.selinux.Restorecond.service
new file mode 100644
index 0000000..0ef5f0b
--- /dev/null
+++ b/policycoreutils/restorecond/org.selinux.Restorecond.service
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.selinux.Restorecond
+Exec=/usr/sbin/restorecond -u
diff --git a/policycoreutils/restorecond/restorecond.8 b/policycoreutils/restorecond/restorecond.8
index b149dcb..4622d2b 100644
--- a/policycoreutils/restorecond/restorecond.8
+++ b/policycoreutils/restorecond/restorecond.8
@@ -3,7 +3,7 @@
 restorecond \- daemon that watches for file creation and then sets the default SELinux file context
 
 .SH "SYNOPSIS"
-.B restorecond  [\-d]
+.B restorecond  [\-d] [\-f restorecond_file ] [\-u] [\-v]
 .P
 
 .SH "DESCRIPTION"
@@ -19,13 +19,22 @@ the correct file context associated with the policy.
 .B \-d
 Turns on debugging mode.   Application will stay in the foreground and lots of
 debugs messages start printing.
+.TP
+.B \-f restorecond_file
+Use alternative restorecond.conf file.
+.TP
+.B \-u
+Turns on user mode.  Runs restorecond in the user session and reads /etc/selinux/restorecond_user.conf.  Uses dbus to make sure only one restorecond is running per user session.
+.TP
+.B \-v
+Turns on verbose debugging.  (Report missing files)
 
 .SH "AUTHOR"
-This man page was written by Dan Walsh <dwalsh@redhat.com>.
-The program was written by Dan Walsh <dwalsh@redhat.com>.
+This man page and program was written by Dan Walsh <dwalsh@redhat.com>.
 
 .SH "FILES"
 /etc/selinux/restorecond.conf
+/etc/selinux/restorecond_user.conf
 
 .SH "SEE ALSO"
 .BR restorecon (8),
diff --git a/policycoreutils/restorecond/restorecond.c b/policycoreutils/restorecond/restorecond.c
index 4952632..89f5d97 100644
--- a/policycoreutils/restorecond/restorecond.c
+++ b/policycoreutils/restorecond/restorecond.c
@@ -30,9 +30,11 @@
  * and makes sure that there security context matches the systems defaults
  *
  * USAGE:
- * restorecond [-d] [-v]
+ * restorecond [-d] [-u] [-v] [-f restorecond_file ]
  * 
  * -d   Run in debug mode
+ * -f   Use alternative restorecond_file
+ * -u   Run in user mode
  * -v   Run in verbose mode (Report missing files)
  *
  * EXAMPLE USAGE:
@@ -48,297 +50,38 @@
 #include <signal.h>
 #include <string.h>
 #include <unistd.h>
-#include <ctype.h>
+#include "../setfiles/restore.h"
 #include <sys/types.h>
-#include <sys/stat.h>
 #include <syslog.h>
 #include <limits.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
 #include <fcntl.h>
-
 #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 <selinux/selinux.h>
-#include <utmp.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))
 
-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);
-}
+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;
 
-/* 
-   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";
-
-	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.");
-}
-
-/* 
-   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->mask & ~IN_IGNORED) {
-			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;
+#include <selinux/selinux.h>
 
-				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";
@@ -377,7 +120,7 @@ static void term_handler()
 
 static void usage(char *program)
 {
-	printf("%s [-d] [-v] \n", program);
+	printf("%s [-d] [-f restorecond_file ] [-u] [-v] \n", program);
 	exit(0);
 }
 
@@ -393,74 +136,35 @@ void exitApp(const char *msg)
    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.rootpathlen = 0;
+	r_opts.outfile = NULL;
+	r_opts.force = 0;
+	r_opts.hard_links = 0;
+	r_opts.abort_on_error = 0;
+	r_opts.add_assoc = 0;
+	r_opts.expand_realpath = 0;
+	r_opts.fts_flags = FTS_PHYSICAL;
+	r_opts.selabel_opt_validate = NULL;
+	r_opts.selabel_opt_path = NULL;
+	r_opts.ignore_enoent = 1;
+
+	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;
@@ -470,36 +174,59 @@ int main(int argc, char **argv)
 
 	set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
 
-	master_fd = inotify_init();
-	if (master_fd < 0)
-		exitApp("inotify_init");
-
-	while ((opt = getopt(argc, argv, "dv")) > 0) {
+	exclude_non_seclabel_mounts();
+	atexit( done );
+	while ((opt = getopt(argc, argv, "df:uv")) > 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);
+	if (!pwd)
+		exitApp("getpwuid");
+
+	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);
 
diff --git a/policycoreutils/restorecond/restorecond.conf b/policycoreutils/restorecond/restorecond.conf
index 3fc9376..58b723a 100644
--- a/policycoreutils/restorecond/restorecond.conf
+++ b/policycoreutils/restorecond/restorecond.conf
@@ -4,8 +4,5 @@
 /etc/mtab
 /var/run/utmp
 /var/log/wtmp
-~/*
-/root/.ssh
+/root/*
 /root/.ssh/*
-
-
diff --git a/policycoreutils/restorecond/restorecond.desktop b/policycoreutils/restorecond/restorecond.desktop
new file mode 100644
index 0000000..23ff89d
--- /dev/null
+++ b/policycoreutils/restorecond/restorecond.desktop
@@ -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 --git a/policycoreutils/restorecond/restorecond.h b/policycoreutils/restorecond/restorecond.h
index e1666bf..8c85ef0 100644
--- a/policycoreutils/restorecond/restorecond.h
+++ b/policycoreutils/restorecond/restorecond.h
@@ -24,7 +24,22 @@
 #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);
+extern int watch_list_isempty();
 
 #endif
diff --git a/policycoreutils/restorecond/restorecond.init b/policycoreutils/restorecond/restorecond.init
index b966db6..775c52b 100644
--- a/policycoreutils/restorecond/restorecond.init
+++ b/policycoreutils/restorecond/restorecond.init
@@ -26,7 +26,7 @@ PATH=/sbin:/bin:/usr/bin:/usr/sbin
 # Source function library.
 . /etc/rc.d/init.d/functions
 
-[ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled || exit 0
+[ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled || exit 7
 
 # Check that we are root ... so non-root users stop here
 test $EUID = 0  || exit 4
@@ -75,16 +75,15 @@ case "$1" in
 	status restorecond
 	RETVAL=$?
 	;;
-  restart|reload)
+  force-reload|restart|reload)
 	restart
 	;;
   condrestart)
 	[ -e /var/lock/subsys/restorecond ] && restart || :
 	;;
   *)
-        echo $"Usage: $0 {start|stop|restart|reload|condrestart}"
+        echo $"Usage: $0 {start|stop|restart|force-reload|status|condrestart}"
         RETVAL=3
 esac
 
 exit $RETVAL
-
diff --git a/policycoreutils/restorecond/restorecond_user.conf b/policycoreutils/restorecond/restorecond_user.conf
new file mode 100644
index 0000000..e0c2871
--- /dev/null
+++ b/policycoreutils/restorecond/restorecond_user.conf
@@ -0,0 +1,7 @@
+~/*
+~/public_html/*
+~/.gnome2/*
+~/local/*
+~/.fonts/*
+~/.cache/*
+~/.config/*
diff --git a/policycoreutils/restorecond/user.c b/policycoreutils/restorecond/user.c
new file mode 100644
index 0000000..ade3fb8
--- /dev/null
+++ b/policycoreutils/restorecond/user.c
@@ -0,0 +1,246 @@
+/*
+ * 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 <dwalsh@redhat.com>
+ *
+*/
+
+#define _GNU_SOURCE
+#include <sys/inotify.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include "restorecond.h"
+#include "stringslist.h"
+#include <glib.h>
+#ifdef HAVE_DBUS
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+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 <selinux/selinux.h>
+#include <sys/file.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))
+
+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;
+	if (asprintf(&ptr, "%s/.restorecond", homedir) < 0) {
+		if (debug_mode)
+			perror("asprintf");
+		return -1;
+	}
+	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))
+		    goto end;
+
+    read_config(master_fd, watch_file);
+
+    if (watch_list_isempty()) goto end;
+
+    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);
+
+end:
+    g_main_loop_unref (loop);
+    return 0;
+}
+
diff --git a/policycoreutils/restorecond/watch.c b/policycoreutils/restorecond/watch.c
new file mode 100644
index 0000000..6a833c3
--- /dev/null
+++ b/policycoreutils/restorecond/watch.c
@@ -0,0 +1,272 @@
+#define _GNU_SOURCE
+#include <sys/inotify.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include "../setfiles/restore.h"
+#include <glob.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <selinux/selinux.h>
+#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;
+
+int watch_list_isempty() {
+	return 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;
+
+	if (exclude(path)) goto end;
+
+	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_realpath(globbuf.gl_pathv[i], 0) > 0)
+			  process_one_realpath(globbuf.gl_pathv[i], 1);
+		}
+		globfree(&globbuf);
+	}
+
+	while (ptr != NULL) {
+		if (strcmp(dir, ptr->dir) == 0) {
+			strings_list_add(&ptr->files, file);
+			goto end;
+		}
+		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);
+		if (! run_as_user)
+			syslog(LOG_ERR, "Unable to watch (%s) %s\n",
+			       path, strerror(errno));
+		goto end;
+	}
+
+	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);
+
+end:
+	free(x);
+	return;
+}
+
+/*
+   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_realpath(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;
+	if (firstDir == NULL) return 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 {
+			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, watch_file);
+				break;
+
+			default:	/* No users logged in or out */
+				break;
+			}
+		}
+
+		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;
+				if (asprintf(&ptr, "%s%s", homedir, &buffer[1]) < 0)
+					exitApp("Error allocating memory.");
+
+				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 --git a/policycoreutils/run_init/run_init.c b/policycoreutils/run_init/run_init.c
index 9db766c..068e24c 100644
--- a/policycoreutils/run_init/run_init.c
+++ b/policycoreutils/run_init/run_init.c
@@ -414,10 +414,17 @@ int main(int argc, char *argv[])
 	 * execvp or using a exec(1) recycles pty's, and does not open a new
 	 * one. 
 	 */
+#ifdef USE_OPEN_INIT_PTY
 	if (execvp("/usr/sbin/open_init_pty", argv)) {
 		perror("execvp");
 		exit(-1);
 	}
+#else
+	if (execvp(argv[1], argv + 1)) {
+		perror("execvp");
+		exit(-1);
+	}
+#endif
 	return 0;
 
 }				/* main() */
diff --git a/policycoreutils/sandbox/Makefile b/policycoreutils/sandbox/Makefile
index ff0ee7c..924999d 100644
--- a/policycoreutils/sandbox/Makefile
+++ b/policycoreutils/sandbox/Makefile
@@ -7,10 +7,10 @@ SBINDIR ?= $(PREFIX)/sbin
 MANDIR ?= $(PREFIX)/share/man
 LOCALEDIR ?= /usr/share/locale
 SHAREDIR ?= $(PREFIX)/share/sandbox
-override CFLAGS += $(LDFLAGS) -I$(PREFIX)/include -DPACKAGE="\"policycoreutils\""
-LDLIBS += -lselinux -lcap-ng 
+override CFLAGS += $(LDFLAGS) -I$(PREFIX)/include -DPACKAGE="\"policycoreutils\"" -Wall -Werror -Wextra
+LDLIBS += -lcgroup -lselinux -lcap-ng
 
-all: sandbox seunshare sandboxX.sh 
+all: sandbox seunshare sandboxX.sh start
 
 seunshare: seunshare.o $(EXTRA_OBJS)
 	$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
@@ -20,14 +20,18 @@ install: all
 	install -m 755 sandbox $(BINDIR)
 	-mkdir -p $(MANDIR)/man8
 	install -m 644 sandbox.8 $(MANDIR)/man8/
+	install -m 644 seunshare.8 $(MANDIR)/man8/
+	-mkdir -p $(MANDIR)/man5
+	install -m 644 sandbox.conf.5 $(MANDIR)/man5/sandbox.5
 	-mkdir -p $(SBINDIR)
 	install -m 4755 seunshare $(SBINDIR)/
 	-mkdir -p $(SHAREDIR)
 	install -m 755 sandboxX.sh $(SHAREDIR)
+	install -m 755 start $(SHAREDIR)
 	-mkdir -p $(INITDIR)
 	install -m 755 sandbox.init $(INITDIR)/sandbox
 	-mkdir -p $(SYSCONFDIR)
-	install -m 644 sandbox.config $(SYSCONFDIR)/sandbox
+	install -m 644 sandbox.conf $(SYSCONFDIR)/sandbox
 
 test:
 	@python test_sandbox.py -v
diff --git a/policycoreutils/sandbox/sandbox b/policycoreutils/sandbox/sandbox
index 0b89e9a..481034c 100644
--- a/policycoreutils/sandbox/sandbox
+++ b/policycoreutils/sandbox/sandbox
@@ -1,5 +1,6 @@
 #! /usr/bin/python -Es
 # Authors: Dan Walsh <dwalsh@redhat.com>
+# Authors: Thomas Liu <tliu@fedoraproject.org>
 # Authors: Josh Cogliati
 #
 # Copyright (C) 2009,2010  Red Hat
@@ -19,15 +20,17 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 #
 
-import os, sys, socket, random, fcntl, shutil, re, subprocess
+import os, stat, sys, socket, random, fcntl, shutil, re, subprocess
 import selinux
 import signal
 from tempfile import mkdtemp
 import pwd
+import commands
+import setools
 
 PROGNAME = "policycoreutils"
-HOMEDIR=pwd.getpwuid(os.getuid()).pw_dir
-
+SEUNSHARE = "/usr/sbin/seunshare"
+SANDBOXSH = "/usr/share/sandbox/sandboxX.sh"
 import gettext
 gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
 gettext.textdomain(PROGNAME)
@@ -41,6 +44,7 @@ except IOError:
        import __builtin__
        __builtin__.__dict__['_'] = unicode
 
+DEFAULT_WINDOWSIZE = "1000x700"
 DEFAULT_TYPE = "sandbox_t"
 DEFAULT_X_TYPE = "sandbox_x_t"
 SAVE_FILES = {}
@@ -63,15 +67,15 @@ def error_exit(msg):
     sys.stderr.flush()
     sys.exit(1)
 
-def copyfile(file, dir, dest):
+def copyfile(file, srcdir, dest):
        import re
-       if file.startswith(dir):
+       if file.startswith(srcdir):
               dname = os.path.dirname(file)
               bname = os.path.basename(file)
-              if dname == dir:
+              if dname == srcdir:
                      dest = dest + "/" + bname
               else:
-                     newdir = re.sub(dir, dest, dname)
+                     newdir = re.sub(srcdir, dest, dname)
                      if not os.path.exists(newdir):
                             os.makedirs(newdir)
                      dest = newdir + "/" + bname
@@ -81,9 +85,10 @@ def copyfile(file, dir, dest):
                             shutil.copytree(file, dest)
                      else:
                             shutil.copy2(file, dest)
+
               except shutil.Error, elist:
-                     for e in elist:
-                            sys.stderr.write(e[1])
+                     for e in elist.message:
+                            sys.stderr.write(e[2])
                      
               SAVE_FILES[file] = (dest, os.path.getmtime(dest))
 
@@ -161,10 +166,10 @@ class Sandbox:
                   if not self.__options.homedir or not self.__options.tmpdir:
                          self.usage(_("Homedir and tempdir required for level mounts"))
 
-           if not os.path.exists("/usr/sbin/seunshare"):
+           if not os.path.exists(SEUNSHARE):
                   raise ValueError(_("""
-/usr/sbin/seunshare is required for the action you want to perform.  
-"""))
+%s is required for the action you want to perform.
+""") % SEUNSHARE)
 
     def __mount_callback(self, option, opt, value, parser):
            self.__mount = True
@@ -172,6 +177,15 @@ class Sandbox:
     def __x_callback(self, option, opt, value, parser):
            self.__mount = True
            setattr(parser.values, option.dest, True)
+           if not os.path.exists(SEUNSHARE):
+                  raise ValueError(_("""
+%s is required for the action you want to perform.
+""") % SEUNSHARE)
+
+           if not os.path.exists(SANDBOXSH):
+                  raise ValueError(_("""
+%s is required for the action you want to perform.
+""") % SANDBOXSH)
 
     def __validdir(self, option, opt, value, parser):
            if not os.path.isdir(value):
@@ -194,6 +208,8 @@ class Sandbox:
                          self.__include(option, opt, i[:-1], parser)
                   except IOError, e:
                          sys.stderr.write(str(e))
+                  except TypeError, e:
+                         sys.stderr.write(str(e))
            fd.close()
 
     def __copyfiles(self):
@@ -212,13 +228,15 @@ class Sandbox:
 /etc/gdm/Xsession
 """)
            else:
-                  command = " ".join(self.__paths)
+                  command = self.__paths[0] + " "
+                  for p in self.__paths[1:]:
+                         command += "'%s' " % p
                   fd.write("""#! /bin/sh
 #TITLE: %s
 /usr/bin/test -r ~/.xmodmap && /usr/bin/xmodmap ~/.xmodmap
 %s &
 WM_PID=$!
-%s
+dbus-launch --exit-with-session %s
 kill -TERM $WM_PID  2> /dev/null
 """ % (command, wm, command))
            fd.close()
@@ -229,11 +247,22 @@ kill -TERM $WM_PID  2> /dev/null
 
     def __parse_options(self):
         from optparse import OptionParser
+        types = ""
+        try:
+               types = _("""
+Policy defines the following types for use with the -t:
+\t%s
+""") % "\n\t".join(setools.seinfo(setools.ATTRIBUTE, "sandbox_type")[0]['types'])
+        except RuntimeError:
+               pass
+
         usage = _("""
-sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [[-i file ] ...] [ -t type ] command
+sandbox [-h] [-c] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] command
+
+sandbox [-h] [-c] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] -S
+%s
+""") % types
 
-sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [[-i file ] ...] [ -t type ] -S
-""")
         
         parser = OptionParser(version=self.VERSION, usage=usage)
         parser.disable_interspersed_args()
@@ -260,14 +289,18 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [-
         parser.add_option("-H", "--homedir", 
                           action="callback", callback=self.__validdir,
                           type="string",
-                          dest="homedir",  
+                          dest="homedir",
                           help=_("alternate home directory to use for mounting"))
 
-        parser.add_option("-T", "--tmpdir", dest="tmpdir",  
+        parser.add_option("-T", "--tmpdir", dest="tmpdir",
                           type="string",
                           action="callback", callback=self.__validdir,
                           help=_("alternate /tmp directory to use for mounting"))
 
+        parser.add_option("-w", "--windowsize", dest="windowsize",
+                          type="string", default=DEFAULT_WINDOWSIZE,
+                          help="size of the sandbox window")
+
         parser.add_option("-W", "--windowmanager", dest="wm",  
                           type="string",
                           default="/usr/bin/matchbox-window-manager -use_titlebar no",
@@ -276,13 +309,21 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [-
         parser.add_option("-l", "--level", dest="level", 
                           help=_("MCS/MLS level for the sandbox"))
 
+        parser.add_option("-c", "--cgroups",
+                          action="store_true", dest="usecgroup", default=False,
+                          help=_("Use cgroups to limit this sandbox."))
+
+        parser.add_option("-C", "--capabilities",
+                         action="store_true", dest="usecaps", default=False,
+                         help="Allow apps requiring capabilities to run within the sandbox.")
+
         self.__parser=parser
 
         self.__options, cmds = parser.parse_args()
 
         if self.__options.X_ind:
                self.setype = DEFAULT_X_TYPE
-        
+               self.dpi=commands.getoutput("xrdb -query | grep dpi  | /bin/cut -f 2")
         if self.__options.setype:
                self.setype = self.__options.setype
 
@@ -300,6 +341,10 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [-
                self.__homedir = self.__options.homedir
                self.__tmpdir = self.__options.tmpdir
         else:
+               if self.__options.level:
+                      self.__homedir = self.__options.homedir
+                      self.__tmpdir = self.__options.tmpdir
+
                if len(cmds) == 0:
                       self.usage(_("Command required"))
                cmds[0] = fullpath(cmds[0])
@@ -323,50 +368,51 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [-
 
            con = selinux.getcon()[1].split(":")
            self.__execcon = "%s:%s:%s:%s" % (con[0], con[1], self.setype, level)
-           self.__filecon = "%s:%s:%s:%s" % (con[0], "object_r", 
-                                             "%s_file_t" % self.setype[:-2], 
+           self.__filecon = "%s:%s:%s:%s" % (con[0], "object_r",
+                                             "%s_file_t" % self.setype[:-2],
                                              level)
     def __setup_dir(self):
            if self.__options.level or self.__options.session:
                   return
-           sandboxdir = HOMEDIR + "/.sandbox"
-           if not os.path.exists(sandboxdir):
-                  os.mkdir(sandboxdir)
 
            if self.__options.homedir:
                   selinux.chcon(self.__options.homedir, self.__filecon, recursive=True)
                   self.__homedir = self.__options.homedir
            else:
                   selinux.setfscreatecon(self.__filecon)
-                  self.__homedir = mkdtemp(dir=sandboxdir, prefix=".sandbox")
+                  self.__homedir = mkdtemp(dir="/tmp", prefix=".sandbox_home_")
 
            if self.__options.tmpdir:
                   selinux.chcon(self.__options.tmpdir, self.__filecon, recursive=True)
                   self.__tmpdir = self.__options.tmpdir
            else:
                   selinux.setfscreatecon(self.__filecon)
-                  self.__tmpdir = mkdtemp(dir="/tmp", prefix=".sandbox")
+                  self.__tmpdir = mkdtemp(dir="/tmp", prefix=".sandbox_tmp_")
            selinux.setfscreatecon(None)
            self.__copyfiles()
 
     def __execute(self):
            try:
-                  if self.__options.X_ind:
-                         xmodmapfile = self.__homedir + "/.xmodmap"
-                         xd = open(xmodmapfile,"w")
-                         subprocess.Popen(["/usr/bin/xmodmap","-pke"],stdout=xd).wait()
-                         xd.close()
-
-                         self.__setup_sandboxrc(self.__options.wm)
-                         
-                         cmds = [ '/usr/sbin/seunshare', "-t", self.__tmpdir, "-h", self.__homedir, "--", self.__execcon, "/usr/share/sandbox/sandboxX.sh" ]
-                         rc = subprocess.Popen(cmds).wait()
-                         return rc
-
+                  cmds = [ SEUNSHARE,  "-Z", self.__execcon ]
+                  if self.__options.usecgroup:
+                         cmds.append('-c')
+                  if self.__options.usecaps:
+                         cmds.append('-C')
                   if self.__mount:
-                         cmds =  [ '/usr/sbin/seunshare', "-t", self.__tmpdir, "-h", self.__homedir, "--", self.__execcon ] + self.__paths
-                         rc = subprocess.Popen(cmds).wait()
-                         return rc
+                         cmds +=  [ "-t", self.__tmpdir, "-h", self.__homedir ]
+
+                         if self.__options.X_ind:
+                                xmodmapfile = self.__homedir + "/.xmodmap"
+                                xd = open(xmodmapfile,"w")
+                                subprocess.Popen(["/usr/bin/xmodmap","-pke"],stdout=xd).wait()
+                                xd.close()
+
+                                self.__setup_sandboxrc(self.__options.wm)
+
+                                cmds += [ "--", SANDBOXSH, self.__options.windowsize, self.dpi ]
+                         else:
+                                cmds += [ "--" ] + self.__paths
+                         return subprocess.Popen(cmds).wait()
 
                   selinux.setexeccon(self.__execcon)
                   rc = subprocess.Popen(self.__cmds).wait()
@@ -404,7 +450,7 @@ if __name__ == '__main__':
            sandbox = Sandbox()
            rc = sandbox.main()
     except OSError, error:
-           error_exit(error.args[1])
+           error_exit(error)
     except ValueError, error:
            error_exit(error.args[0])
     except KeyError, error:
diff --git a/policycoreutils/sandbox/sandbox.8 b/policycoreutils/sandbox/sandbox.8
index 1479364..2b37e63 100644
--- a/policycoreutils/sandbox/sandbox.8
+++ b/policycoreutils/sandbox/sandbox.8
@@ -1,10 +1,13 @@
-.TH SANDBOX "8" "May 2009" "chcat" "User Commands"
+.TH SANDBOX "8" "May 2010" "sandbox" "User Commands"
 .SH NAME
 sandbox \- Run cmd under an SELinux sandbox
 .SH SYNOPSIS
 .B sandbox
-[-l level ] [[-M | -X]  -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [[-i file ]...] [ -t type ] cmd
-[-l level ] [[-M | -X]  -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [[-i file ]...] [ -t type ] -S
+[-C] [-c] [-l level ] [[-M | -X]  -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] cmd
+
+.br
+.B sandbox
+[-C] [-c] [-l level ] [[-M | -X]  -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] -S
 .br
 .SH DESCRIPTION
 .PP
@@ -42,6 +45,12 @@ Use alternate sandbox type, defaults to sandbox_t or sandbox_x_t for -X.
 \fB\-T\ tmpdir
 Use alternate tempory directory to mount on /tmp.  Defaults to tmpfs. Requires -X or -M.
 .TP
+\fB\-S
+Run a full desktop session, Requires level, and home and tmpdir.
+.TP
+\fB\-w windowsize\fR
+Specifies the windowsize when creating an X based Sandbox. The default windowsize is 1000x700.
+.TP
 \fB\-W windowmanager\fR
 Select alternative window manager to run within 
 .B sandbox -X.
@@ -50,8 +59,20 @@ Default to /usr/bin/matchbox-window-manager.
 \fB\-X\fR 
 Create an X based Sandbox for gui apps, temporary files for
 $HOME and /tmp, secondary Xserver, defaults to sandbox_x_t
+.TP
+\fB\-c\fR
+Use control groups to control this copy of sandbox.  Specify parameters in /etc/sysconfig/sandbox.  Max memory usage and cpu usage are to be specified in percent.  You can specify which CPUs to use by numbering them 0,1,2... etc.
+.TP
+\fB\-C\fR
+Use capabilities within the sandbox.  By default applications executed within the sandbox will not be allowed to use capabilities (setuid apps), with the -C flag, you can use programs requiring capabilities.
 .PP
 .SH "SEE ALSO"
 .TP
-runcon(1)
+runcon(1), seunshare(8), selinux(8)
 .PP
+
+.SH AUTHOR
+This manual page was written by
+.I Dan Walsh <dwalsh@redhat.com>
+and
+.I Thomas Liu <tliu@fedoraproject.org>
diff --git a/policycoreutils/sandbox/sandbox.conf b/policycoreutils/sandbox/sandbox.conf
new file mode 100644
index 0000000..7c35808
--- /dev/null
+++ b/policycoreutils/sandbox/sandbox.conf
@@ -0,0 +1,7 @@
+# Space separate list of homedirs
+HOMEDIRS="/home"
+# Control group configuration
+NAME=sandbox
+CPUAFFINITY=ALL
+MEMUSAGE=80%
+CPUUSAGE=80%
diff --git a/policycoreutils/sandbox/sandbox.conf.5 b/policycoreutils/sandbox/sandbox.conf.5
new file mode 100644
index 0000000..b3ee67d
--- /dev/null
+++ b/policycoreutils/sandbox/sandbox.conf.5
@@ -0,0 +1,40 @@
+.TH sandbox.conf "5" "June 2010" "sandbox.conf" "Linux System Administration"
+.SH NAME
+sandbox.conf \- user config file for the SELinux sandbox
+.SH DESCRIPTION
+.PP
+When running sandbox with the -C argument, it will be confined using control groups and a system administrator can specify how the sandbox is confined.
+
+.PP
+Everything after "#" is ignored, as are empty lines.  All arguments should be separated by and equals sign ("=").
+
+.PP
+These keywords are allowed.
+
+.RS
+.TP
+.B NAME
+The name of the sandbox control group.  Default is "sandbox".
+
+.TP
+.B CPUAFFINITY
+Which cpus to assign sandbox to.  The default is ALL, but users can specify a comma-separated list with dashes ("-") to represent ranges.  Ex: 0-2,5
+
+.TP
+.B MEMUSAGE
+How much memory to allow sandbox to use.  The default is 80%.  Users can specify either a percentage or a value in the form of a number followed by one of the suffixes K, M, G to denote kilobytes, megabytes or gigabytes respectively.  Ex: 50% or 100M
+
+.TP
+.B CPUUSAGE
+Percentage of cpu sandbox should be allowed to use.  The default is 80%.  Specify a value followed by a percent sign ("%"). Ex: 50%
+
+
+
+.SH "SEE ALSO"
+.TP
+sandbox(8)
+.PP
+
+.SH AUTHOR
+This manual page was written by
+.I Thomas Liu <tliu@fedoraproject.org>
diff --git a/policycoreutils/sandbox/sandbox.init b/policycoreutils/sandbox/sandbox.init
index ff8b3ef..66aadfd 100644
--- a/policycoreutils/sandbox/sandbox.init
+++ b/policycoreutils/sandbox/sandbox.init
@@ -10,17 +10,12 @@
 #
 # chkconfig: 345 1 99
 #
-# Description: sandbox and other apps that want to use pam_namespace 
-#              on /var/tmp, /tmp and home directories, requires this script
-#              to be run at boot time.
-#              This script sets up the / mount point and all of its 
-#              subdirectories as shared. The script sets up
-#              /tmp, /var/tmp, /home and any homedirs listed in 
-#              /etc/sysconfig/sandbox and all of their subdirectories 
-#              as unshared.
-#              All processes that use pam_namespace will see 
-#              modifications to the global mountspace, except for the
-#              unshared directories.
+# description: sandbox, xguest and other apps that want to use pam_namespace \
+#              require this script be run at boot.  This service script does \
+#              not actually run any service but sets up: \
+#              /var/tmp, /tmp and home directories to be used by these tools.\
+#              If you do not use sandbox, xguest or pam_namespace you can turn \
+#              this service off.\
 #
 
 # Source function library.
@@ -41,15 +36,6 @@ start() {
 
 	touch $LOCKFILE
 	mount --make-rshared / || return $? 
-	mount --rbind /tmp /tmp || return $?
-	mount --rbind /var/tmp /var/tmp || return $?
-	mount --make-private /tmp || return $?
-	mount --make-private /var/tmp || return $?
-	for h in $HOMEDIRS; do
-	    mount --rbind $h $h || return $?
-	    mount --make-private $h || return $?
-	done
-
 	return 0
 }
 
diff --git a/policycoreutils/sandbox/sandboxX.sh b/policycoreutils/sandbox/sandboxX.sh
index 8338203..88ebfee 100644
--- a/policycoreutils/sandbox/sandboxX.sh
+++ b/policycoreutils/sandbox/sandboxX.sh
@@ -1,15 +1,21 @@
-#!/bin/bash 
+#!/bin/bash
+trap "" TERM
 context=`id -Z | secon -t -l -P`
 export TITLE="Sandbox $context -- `grep ^#TITLE: ~/.sandboxrc | /usr/bin/cut -b8-80`"
-export SCREENSIZE="1000x700"
-#export SCREENSIZE=`xdpyinfo | awk  '/dimensions/ {  print $2 }'`
+[ -z $1 ] && export SCREENSIZE="1000x700" || export SCREENSIZE="$1"
+[ -z $2 ] && export DPI="96" || export DPI="$2"
 trap "exit 0" HUP
 
-(/usr/bin/Xephyr -title "$TITLE" -terminate -screen $SCREENSIZE -displayfd 5 5>&1 2>/dev/null) | while read D; do 
+(/usr/bin/Xephyr -title "$TITLE" -terminate -screen $SCREENSIZE -dpi $DPI -displayfd 5 5>&1 2>/dev/null) | while read D; do
     export DISPLAY=:$D
-    python -c 'import gtk, os, commands; commands.getstatusoutput("%s/.sandboxrc" % os.environ["HOME"])'
+    cat > ~/seremote << __EOF
+#!/bin/sh
+DISPLAY=$DISPLAY "\$@"
+__EOF
+    chmod +x ~/seremote
+    /usr/share/sandbox/start $HOME/.sandboxrc
     export EXITCODE=$?
-    kill -HUP 0
+    kill -TERM 0
     break
 done
 exit 0
diff --git a/policycoreutils/sandbox/seunshare.8 b/policycoreutils/sandbox/seunshare.8
new file mode 100644
index 0000000..06610c0
--- /dev/null
+++ b/policycoreutils/sandbox/seunshare.8
@@ -0,0 +1,43 @@
+.TH SEUNSHARE "8" "May 2010" "seunshare" "User Commands"
+.SH NAME
+seunshare \- Run cmd with alternate homedir, tmpdir and/or SELinux context
+.SH SYNOPSIS
+.B seunshare
+[ -v ] [ -c ] [ -C ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z context ] -- executable [args]
+.br
+.SH DESCRIPTION
+.PP
+Run the
+.I executable
+within the specified context, using the alternate home directory and /tmp directory.  The seunshare command unshares from the default namespace, then mounts the specified homedir and tmpdir over the default homedir and /tmp. Finally it tells the kernel to execute the application under the specified SELinux context.
+
+.TP
+\fB\-h homedir\fR
+Alternate homedir to be used by the application.  Homedir must be owned by the user.
+.TP
+\fB\-t\ tmpdir
+Use alternate tempory directory to mount on /tmp.  tmpdir must be owned by the user.
+.TP
+\fB\-c --cgroups\fR
+Use cgroups to control this copy of seunshare.  Specify parameters in /etc/sysconfig/sandbox.  Max memory usage and cpu usage are to be specified in percent.  You can specify which CPUs to use by numbering them 0,1,2... etc.
+.TP
+\fB\-C --capabilities\fR
+Allow apps executed within the namespace to use capabilities.  Default is no capabilities.
+.TP
+\fB\-k --kill\fR
+Kill all processes with matching MCS level.
+.TP
+\fB\-Z\ context
+Use alternate SELinux context while runing the executable.
+.TP
+\fB\-v\fR
+Verbose output
+.SH "SEE ALSO"
+.TP
+runcon(1), sandbox(8), selinux(8)
+.PP
+.SH AUTHOR
+This manual page was written by
+.I Dan Walsh <dwalsh@redhat.com>
+and
+.I Thomas Liu <tliu@fedoraproject.org>
diff --git a/policycoreutils/sandbox/seunshare.c b/policycoreutils/sandbox/seunshare.c
index e713b74..1a0a488 100644
--- a/policycoreutils/sandbox/seunshare.c
+++ b/policycoreutils/sandbox/seunshare.c
@@ -1,27 +1,35 @@
+/*
+ * Authors: Dan Walsh <dwalsh@redhat.com>
+ * Authors: Thomas Liu <tliu@fedoraproject.org>
+ */
+
 #define _GNU_SOURCE
 #include <signal.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 #include <syslog.h>
 #include <sys/mount.h>
+#include <glob.h>
 #include <pwd.h>
 #include <sched.h>
+#include <libcgroup.h>
 #include <string.h>
 #include <stdio.h>
+#include <regex.h>
 #include <unistd.h>
+#include <sys/fsuid.h>
 #include <stdlib.h>
 #include <cap-ng.h>
 #include <getopt.h>		/* for getopt_long() form of getopt() */
 #include <limits.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #include <selinux/selinux.h>
 #include <selinux/context.h>	/* for context-mangling functions */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include <dirent.h>
 
 #ifdef USE_NLS
 #include <locale.h>		/* for setlocale() */
@@ -39,29 +47,55 @@
 #define MS_PRIVATE 1<<18
 #endif
 
+#ifndef PACKAGE
+#define PACKAGE "policycoreutils"	/* the name of this package lang translation */
+#endif
+
+#define BUF_SIZE 1024
+#define DEFAULT_PATH "/usr/bin:/bin"
+#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -c ] [ -k ] [ -C ] [ -t tmpdir] [ -h  homedir ] [ -Z context ] -- executable [args]")
+
+static int verbose = 0;
+static int child = 0;
+
+static capng_select_t cap_set = CAPNG_SELECT_BOTH;
+
 /**
- * This function will drop all capabilities 
- * Returns zero on success, non-zero otherwise
+ * This function will drop all capabilities.
  */
-static int drop_capabilities(uid_t uid)
+static int drop_caps()
 {
-	capng_clear(CAPNG_SELECT_BOTH);
-
-	if (capng_lock() < 0) 
+	if (capng_have_capabilities(cap_set) == CAPNG_NONE)
+		return 0;
+	capng_clear(cap_set);
+	if (capng_lock() == -1 || capng_apply(cap_set) == -1) {
+		fprintf(stderr, _("Failed to drop all capabilities\n"));
 		return -1;
-	/* Change uid */
-	if (setresuid(uid, uid, uid)) {
-		fprintf(stderr, _("Error changing uid, aborting.\n"));
+	}
+	return 0;
+}
+
+/**
+ * This function will drop all privileges.
+ */
+static int drop_privs(uid_t uid)
+{
+	if (drop_caps() == -1 || setresuid(uid, uid, uid) == -1) {
+		fprintf(stderr, _("Failed to drop privileges\n"));
 		return -1;
 	}
-	return capng_apply(CAPNG_SELECT_BOTH);
+	return 0;
 }
 
-#define DEFAULT_PATH "/usr/bin:/bin"
-static	int verbose = 0;
+/**
+ * If the user sends a siginto to seunshare, kill the child's session
+ */
+void handler(int sig) {
+	if (child > 0) kill(-child,sig);
+}
 
 /**
- * Take care of any signal setup
+ * Take care of any signal setup.
  */
 static int set_signal_handles(void)
 {
@@ -75,32 +109,117 @@ static int set_signal_handles(void)
 
 	(void)sigprocmask(SIG_SETMASK, &empty, NULL);
 
-	/* Terminate on SIGHUP. */
+	/* Terminate on SIGHUP */
 	if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
 		perror("Unable to set SIGHUP handler");
 		return -1;
 	}
 
+	if (signal(SIGINT, handler) == SIG_ERR) {
+		perror("Unable to set SIGINT handler");
+		return -1;
+	}
+
+	return 0;
+}
+
+#define status_to_retval(status,retval) do { \
+	if ((status) == -1) \
+		retval = -1; \
+	else if (WIFEXITED((status))) \
+		retval = WEXITSTATUS((status)); \
+	else if (WIFSIGNALED((status))) \
+		retval = 128 + WTERMSIG((status)); \
+	else \
+		retval = -1; \
+	} while(0)
+
+/**
+ * Spawn external command using system() with dropped privileges.
+ * TODO: avoid system() and use exec*() instead
+ */
+static int spawn_command(const char *cmd, uid_t uid){
+	int child;
+	int status = -1;
+
+	if (verbose > 1)
+		printf("spawn_command: %s\n", cmd);
+
+	child = fork();
+	if (child == -1) {
+		perror(_("Unable to fork"));
+		return status;
+	}
+
+	if (child == 0) {
+		if (drop_privs(uid) != 0) exit(-1);
+
+		status = system(cmd);
+		status_to_retval(status, status);
+		exit(status);
+	}
+
+	waitpid(child, &status, 0);
+	status_to_retval(status, status);
+	return status;
+}
+
+/**
+ * Check file/directory ownership, struct stat * must be passed to the
+ * functions.
+ */
+static int check_owner_uid(uid_t uid, const char *file, struct stat *st) {
+	if (S_ISLNK(st->st_mode)) {
+		fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
+		return -1;
+	}
+	if (st->st_uid != uid) {
+		fprintf(stderr, _("Error: %s not owned by UID %d\n"), file, uid);
+		return -1;
+	}
+	return 0;
+}
+
+static int check_owner_gid(gid_t gid, const char *file, struct stat *st) {
+	if (S_ISLNK(st->st_mode)) {
+		fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
+		return -1;
+	}
+	if (st->st_gid != gid) {
+		fprintf(stderr, _("Error: %s not owned by GID %d\n"), file, gid);
+		return -1;
+	}
 	return 0;
 }
 
+#define equal_stats(one,two) \
+	((one)->st_dev == (two)->st_dev && (one)->st_ino == (two)->st_ino && \
+	 (one)->st_uid == (two)->st_uid && (one)->st_gid == (two)->st_gid && \
+	 (one)->st_mode == (two)->st_mode)
+
 /**
- * This function makes sure the mounted directory is owned by the user executing
- * seunshare.
- * If so, it returns 0. If it can not figure this out or they are different, it returns -1.
+ * Sanity check specified directory.  Store stat info for future comparison, or
+ * compare with previously saved info to detect replaced directories.
+ * Note: This function does not perform owner checks.
  */
-static int verify_mount(const char *mntdir, struct passwd *pwd) {
+static int verify_directory(const char *dir, struct stat *st_in, struct stat *st_out) {
 	struct stat sb;
-	if (stat(mntdir, &sb) == -1) {
-		fprintf(stderr, _("Invalid mount point %s: %s\n"), mntdir, strerror(errno));
+
+	if (st_out == NULL) st_out = &sb;
+
+	if (lstat(dir, st_out) == -1) {
+		fprintf(stderr, _("Failed to stat %s: %s\n"), dir, strerror(errno));
+		return -1;
+	}
+	if (! S_ISDIR(st_out->st_mode)) {
+		fprintf(stderr, _("Error: %s is not a directory: %s\n"), dir, strerror(errno));
 		return -1;
 	}
-	if (sb.st_uid != pwd->pw_uid) {
-		errno = EPERM;
-		syslog(LOG_AUTHPRIV | LOG_ALERT, "%s attempted to mount an invalid directory, %s", pwd->pw_name, mntdir);
-		perror(_("Invalid mount point, reporting to administrator"));
+	if (st_in && !equal_stats(st_in, st_out)) {
+		fprintf(stderr, _("Error: %s was replaced by a different directory\n"), dir);
 		return -1;
 	}
+
 	return 0;
 }
 
@@ -123,7 +242,7 @@ static int verify_shell(const char *shell_name)
 
 		/* check the shell skipping newline char */
 		if (!strcmp(shell_name, buf)) {
-			rc = 1;
+			rc = 0;
 			break;
 		}
 	}
@@ -131,54 +250,618 @@ static int verify_shell(const char *shell_name)
 	return rc;
 }
 
-static int seunshare_mount(const char *src, const char *dst, struct passwd *pwd) {
+/**
+ * Mount directory and check that we mounted the right directory.
+ */
+static int seunshare_mount(const char *src, const char *dst, struct stat *src_st)
+{
+	int flags = MS_REC;
+	int is_tmp = 0;
+
 	if (verbose)
-		printf("Mount %s on %s\n", src, dst);
-	if (mount(dst, dst,  NULL, MS_BIND | MS_REC, NULL) < 0) {
+		printf(_("Mounting %s on %s\n"), src, dst);
+
+	if (strcmp("/tmp", dst) == 0) {
+		flags = flags | MS_NODEV | MS_NOSUID | MS_NOEXEC;
+		is_tmp = 1;
+	}
+
+	/* mount directory */
+	if (mount(dst, dst,  NULL, MS_BIND | flags, NULL) < 0) {
 		fprintf(stderr, _("Failed to mount %s on %s: %s\n"), dst, dst, strerror(errno));
 		return -1;
 	}
-
-	if (mount(dst, dst, NULL, MS_PRIVATE | MS_REC, NULL) < 0) {
+	if (mount(dst, dst, NULL, MS_PRIVATE | flags, NULL) < 0) {
 		fprintf(stderr, _("Failed to make %s private: %s\n"), dst, strerror(errno));
 		return -1;
 	}
-
-	if (mount(src, dst, NULL, MS_BIND | MS_REC, NULL) < 0) {
+	if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) {
 		fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno));
 		return -1;
 	}
 
-	if (verify_mount(dst, pwd) < 0) 
+	/* verify whether we mounted what we expected to mount */
+	if (verify_directory(dst, src_st, NULL) < 0) return -1;
+
+	/* bind mount /tmp on /var/tmp too */
+	if (is_tmp) {
+		if (verbose)
+			printf(_("Mounting /tmp on /var/tmp\n"));
+
+		if (mount("/var/tmp", "/var/tmp",  NULL, MS_BIND | flags, NULL) < 0) {
+			fprintf(stderr, _("Failed to mount /var/tmp on /var/tmp: %s\n"), strerror(errno));
+			return -1;
+		}
+		if (mount("/var/tmp", "/var/tmp", NULL, MS_PRIVATE | flags, NULL) < 0) {
+			fprintf(stderr, _("Failed to make /var/tmp private: %s\n"), strerror(errno));
+			return -1;
+		}
+		if (mount("/tmp", "/var/tmp",  NULL, MS_BIND | flags, NULL) < 0) {
+			fprintf(stderr, _("Failed to mount /tmp on /var/tmp: %s\n"), strerror(errno));
+			return -1;
+		}
+	}
+
+	return 0;
+
+}
+
+/**
+ * Error logging used by cgroups code.
+ */
+static int sandbox_error(const char *string)
+{
+	fprintf(stderr, string);
+	syslog(LOG_AUTHPRIV | LOG_ALERT, string);
+	exit(-1);
+}
+
+/**
+ * Regular expression match.
+ */
+static int match(const char *string, char *pattern)
+{
+	int status;
+	regex_t re;
+	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
+		return 0;
+	}
+	status = regexec(&re, string, (size_t)0, NULL, 0);
+	regfree(&re);
+	if (status != 0) {
+		return 0;
+	}
+	return 1;
+}
+
+/**
+ * Apply cgroups settings from the /etc/sysconfig/sandbox config file.
+ */
+static int setup_cgroups()
+{
+	char *cpus = NULL;	/* which CPUs to use */
+	char *cgroupname = NULL;/* name for the cgroup */
+	char *mem = NULL;	/* string for memory amount to pass to cgroup */
+	int64_t memusage = 0;	/* amount of memory to use max (percent) */
+	int cpupercentage = 0;  /* what percentage of cpu to allow usage */
+	FILE* fp;
+	char buf[BUF_SIZE];
+	char *tok = NULL;
+	int rc = -1;
+	char *str = NULL;
+	const char* fname = "/etc/sysconfig/sandbox";
+
+	if ((fp = fopen(fname, "rt")) == NULL) {
+		fprintf(stderr, "Error opening sandbox config file.");
+		return rc;
+	}
+	while(fgets(buf, BUF_SIZE, fp) != NULL) {
+		/* Skip comments */
+		if (buf[0] == '#') continue;
+
+		/* Copy the string, ignoring whitespace */
+		int len = strlen(buf);
+		free(str);
+		str = malloc((len + 1) * sizeof(char));
+		if (!str)
+			goto err;
+
+		int ind = 0;
+		int i;
+		for (i = 0; i < len; i++) {
+			char cur = buf[i];
+			if (cur != ' ' && cur != '\t') {
+				str[ind] = cur;
+				ind++;
+			}
+		}
+		str[ind] = '\0';
+
+		tok = strtok(str, "=\n");
+		if (tok != NULL) {
+			if (!strcmp(tok, "CPUAFFINITY")) {
+				tok = strtok(NULL, "=\n");
+				cpus = strdup(tok);
+				if (!strcmp(cpus, "ALL")) {
+					free(cpus);
+					cpus = NULL;
+				}
+			} else if (!strcmp(tok, "MEMUSAGE")) {
+				tok = strtok(NULL, "=\n");
+				if (match(tok, "^[0-9]+[kKmMgG%]")) {
+					char *ind = strchr(tok, '%');
+					if (ind != NULL) {
+						*ind = '\0';;
+						memusage = atoi(tok);
+					} else {
+						mem = strdup(tok);
+					}
+				} else {
+					fprintf(stderr, "Error parsing config file.");
+					goto err;
+				}
+
+			} else if (!strcmp(tok, "CPUUSAGE")) {
+				tok = strtok(NULL, "=\n");
+				if (match(tok, "^[0-9]+\%")) {
+					char* ind = strchr(tok, '%');
+					*ind = '\0';
+					cpupercentage = atoi(tok);
+				} else {
+					fprintf(stderr, "Error parsing config file.");
+					goto err;
+				}
+			} else if (!strcmp(tok, "NAME")) {
+				tok = strtok(NULL, "=\n");
+				cgroupname = strdup(tok);
+			} else {
+				continue;
+			}
+		}
+
+	}
+	if (mem == NULL) {
+		long phypz = sysconf(_SC_PHYS_PAGES);
+		long psize = sysconf(_SC_PAGE_SIZE);
+		memusage = phypz * psize * (float) memusage / 100.0;
+	}
+
+	cgroup_init();
+
+	int64_t current_runtime = 0;
+	int64_t current_period = 0 ;
+	int64_t current_mem = 0;
+	char *curr_cpu_path = NULL;
+	char *curr_mem_path = NULL;
+	int ret  = cgroup_get_current_controller_path(getpid(), "cpu", &curr_cpu_path);
+	if (ret) {
+		sandbox_error("Error while trying to get current controller path.\n");
+	} else {
+		struct cgroup *curr = cgroup_new_cgroup(curr_cpu_path);
+		cgroup_get_cgroup(curr);
+		cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_runtime_us", &current_runtime);
+		cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_period_us", &current_period);
+	}
+
+	ret  = cgroup_get_current_controller_path(getpid(), "memory", &curr_mem_path);
+	if (ret) {
+		sandbox_error("Error while trying to get current controller path.\n");
+	} else {
+		struct cgroup *curr = cgroup_new_cgroup(curr_mem_path);
+		cgroup_get_cgroup(curr);
+		cgroup_get_value_int64(cgroup_get_controller(curr, "memory"), "memory.limit_in_bytes", &current_mem);
+	}
+
+	if (((float) cpupercentage)  / 100.0> (float)current_runtime / (float) current_period) {
+		sandbox_error("CPU usage restricted!\n");
+		goto err;
+	}
+
+	if (mem == NULL) {
+		if (memusage > current_mem) {
+			sandbox_error("Attempting to use more memory than allowed!");
+			goto err;
+		}
+	}
+
+	long nprocs = sysconf(_SC_NPROCESSORS_ONLN);
+
+	struct sched_param sp;
+	sp.sched_priority = sched_get_priority_min(SCHED_FIFO);
+	sched_setscheduler(getpid(), SCHED_FIFO, &sp);
+	struct cgroup *sandbox_group = cgroup_new_cgroup(cgroupname);
+	cgroup_add_controller(sandbox_group, "memory");
+	cgroup_add_controller(sandbox_group, "cpu");
+
+	if (mem == NULL) {
+		if (memusage > 0) {
+			cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", memusage);
+		}
+	} else {
+		cgroup_set_value_string(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", mem);
+	}
+	if (cpupercentage > 0) {
+		cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_runtime_us",
+					(float) cpupercentage / 100.0 * 60000);
+		cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_period_us",60000 * nprocs);
+	}
+	if (cpus != NULL) {
+		cgroup_set_value_string(cgroup_get_controller(sandbox_group, "cpu"), "cgroup.procs",cpus);
+	}
+
+	uint64_t allocated_mem;
+	if (cgroup_get_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", &allocated_mem) > current_mem) {
+		sandbox_error("Attempting to use more memory than allowed!\n");
+		goto err;
+	}
+
+	rc = cgroup_create_cgroup(sandbox_group, 1);
+	if (rc != 0) {
+		sandbox_error("Failed to create group.  Ensure that cgconfig service is running. \n");
+		goto err;
+	}
+
+	cgroup_attach_task(sandbox_group);
+
+	rc = 0;
+err:
+	fclose(fp);
+	free(str);
+	free(mem);
+	free(cgroupname);
+	free(cpus);
+	return rc;
+}
+
+/*
+   If path is empy or ends with  "/." or "/.. return -1 else return 0;
+ */
+static int bad_path(const char *path) {
+	const char *ptr;
+	ptr = path;
+	while (*ptr) ptr++;
+	if (ptr == path) return -1; // ptr null
+	ptr--;
+	if (ptr != path && *ptr  == '.') {
+		ptr--;
+		if (*ptr  == '/') return -1; // path ends in /.
+		if (*ptr  == '.') {
+			if (ptr != path) {
+				ptr--;
+				if (*ptr  == '/') return -1; // path ends in /..
+			}
+		}
+	}
+	return 0;
+}
+
+static int rsynccmd(const char * src, const char *dst, char **cmdbuf)
+{
+	char *buf = NULL;
+	char *newbuf = NULL;
+	glob_t fglob;
+	fglob.gl_offs = 0;
+	int flags = GLOB_PERIOD;
+	unsigned int i = 0;
+	int rc = -1;
+
+	/* match glob for all files in src dir */
+	if (asprintf(&buf, "%s/*", src) == -1) {
+		fprintf(stderr, "Out of memory\n");
+		return -1;
+	}
+
+	if (glob(buf, flags, NULL, &fglob) != 0) {
+		free(buf); buf = NULL;
 		return -1;
+	}
+
+	free(buf); buf = NULL;
+
+	for ( i=0; i < fglob.gl_pathc; i++) {
+		const char *path = fglob.gl_pathv[i];
+
+		if (bad_path(path)) continue;
+
+		if (!buf) {
+			if (asprintf(&newbuf, "\'%s\'", path) == -1) {
+				fprintf(stderr, "Out of memory\n");
+				goto err;
+			}
+		} else {
+			if (asprintf(&newbuf, "%s  \'%s\'", buf, path) == -1) {
+				fprintf(stderr, "Out of memory\n");
+				goto err;
+			}
+		}
+
+		free(buf); buf = newbuf;
+		newbuf = NULL;
+	}
+
+	if (buf) {
+		if (asprintf(&newbuf, "/usr/bin/rsync -trlHDq %s '%s'", buf, dst) == -1) {
+			fprintf(stderr, "Out of memory\n");
+			goto err;
+		}
+		*cmdbuf=newbuf;
+	}
+	else {
+		*cmdbuf=NULL;
+	}
+	rc = 0;
+
+err:
+	free(buf); buf = NULL;
+	globfree(&fglob);
+	return rc;
+}
+
+/**
+ * Clean up runtime temporary directory.  Returns 0 if no problem was detected,
+ * >0 if some error was detected, but errors here are treated as non-fatal and
+ * left to tmpwatch to finish incomplete cleanup.
+ */
+static int cleanup_tmpdir(const char *tmpdir, const char *src,
+	struct passwd *pwd, int copy_content)
+{
+	char *cmdbuf = NULL;
+	int rc = 0;
+
+	/* rsync files back */
+	if (copy_content) {
+		if (asprintf(&cmdbuf, "/usr/bin/rsync --exclude=.X11-unix -utrlHDq --delete '%s/' '%s/'", tmpdir, src) == -1) {
+			fprintf(stderr, _("Out of memory\n"));
+			cmdbuf = NULL;
+			rc++;
+		}
+		if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
+			fprintf(stderr, _("Failed to copy files from the runtime temporary directory\n"));
+			rc++;
+		}
+		free(cmdbuf); cmdbuf = NULL;
+	}
+
+	/* remove files from the runtime temporary directory */
+	if (asprintf(&cmdbuf, "/bin/rm -r '%s/' 2>/dev/null", tmpdir) == -1) {
+		fprintf(stderr, _("Out of memory\n"));
+		cmdbuf = NULL;
+		rc++;
+	}
+	/* this may fail if there's root-owned file left in the runtime tmpdir */
+	if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) rc++;
+	free(cmdbuf); cmdbuf = NULL;
+
+	/* remove runtime temporary directory */
+	setfsuid(0);
+	if (rmdir(tmpdir) == -1)
+		fprintf(stderr, _("Failed to remove directory %s: %s\n"), tmpdir, strerror(errno));
+	setfsuid(pwd->pw_uid);
+
+	return 0;
+}
+
+/**
+ * seunshare will create a tmpdir in /tmp, with root ownership.  The parent
+ * process waits for it child to exit to attempt to remove the directory.  If
+ * it fails to remove the directory, we will need to rely on tmpreaper/tmpwatch
+ * to clean it up.
+ */
+static char *create_tmpdir(const char *src, struct stat *src_st,
+	struct stat *out_st, struct passwd *pwd, security_context_t execcon)
+{
+	char *tmpdir = NULL;
+	char *cmdbuf = NULL;
+	int fd_t = -1, fd_s = -1;
+	struct stat tmp_st;
+	security_context_t con = NULL;
+
+	/* get selinux context */
+	if (execcon) {
+		setfsuid(pwd->pw_uid);
+		if ((fd_s = open(src, O_RDONLY)) < 0) {
+			fprintf(stderr, _("Failed to open directory %s: %s\n"), src, strerror(errno));
+			goto err;
+		}
+		if (fstat(fd_s, &tmp_st) == -1) {
+			fprintf(stderr, _("Failed to stat directory %s: %s\n"), src, strerror(errno));
+			goto err;
+		}
+		if (!equal_stats(src_st, &tmp_st)) {
+			fprintf(stderr, _("Error: %s was replaced by a different directory\n"), src);
+			goto err;
+		}
+		if (fgetfilecon(fd_s, &con) == -1) {
+			fprintf(stderr, _("Failed to get context of the directory %s: %s\n"), src, strerror(errno));
+			goto err;
+		}
+
+		/* ok to not reach this if there is an error */
+		setfsuid(0);
+	}
+
+	if (asprintf(&tmpdir, "/tmp/.sandbox-%s-XXXXXX", pwd->pw_name) == -1) {
+		fprintf(stderr, _("Out of memory\n"));
+		tmpdir = NULL;
+		goto err;
+	}
+	if (mkdtemp(tmpdir) == NULL) {
+		fprintf(stderr, _("Failed to create temporary directory: %s\n"), strerror(errno));
+		goto err;
+	}
+
+	/* temporary directory must be owned by root:user */
+	if (verify_directory(tmpdir, NULL, out_st) < 0) {
+		goto err;
+	}
+
+	if (check_owner_uid(0, tmpdir, out_st) < 0)
+		goto err;
+
+	if (check_owner_gid(getgid(), tmpdir, out_st) < 0)
+		goto err;
+
+	/* change permissions of the temporary directory */
+	if ((fd_t = open(tmpdir, O_RDONLY)) < 0) {
+		fprintf(stderr, _("Failed to open directory %s: %s\n"), tmpdir, strerror(errno));
+		goto err;
+	}
+	if (fstat(fd_t, &tmp_st) == -1) {
+		fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
+		goto err;
+	}
+	if (!equal_stats(out_st, &tmp_st)) {
+		fprintf(stderr, _("Error: %s was replaced by a different directory\n"), tmpdir);
+		goto err;
+	}
+	if (fchmod(fd_t, 01770) == -1) {
+		fprintf(stderr, _("Unable to change mode on %s: %s\n"), tmpdir, strerror(errno));
+		goto err;
+	}
+	/* re-stat again to pick change mode */
+	if (fstat(fd_t, out_st) == -1) {
+		fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
+		goto err;
+	}
+
+	/* copy selinux context */
+	if (execcon) {
+		if (fsetfilecon(fd_t, con) == -1) {
+			fprintf(stderr, _("Failed to set context of the directory %s: %s\n"), tmpdir, strerror(errno));
+			goto err;
+		}
+	}
+
+	setfsuid(pwd->pw_uid);
+
+	if (rsynccmd(src, tmpdir, &cmdbuf) < 0) {
+		goto err;
+	}
+
+	/* ok to not reach this if there is an error */
+	setfsuid(0);
+
+	if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
+		fprintf(stderr, _("Failed to populate runtime temporary directory\n"));
+		cleanup_tmpdir(tmpdir, src, pwd, 0);
+		goto err;
+	}
+
+	goto good;
+err:
+	free(tmpdir); tmpdir = NULL;
+good:
+	free(cmdbuf); cmdbuf = NULL;
+	freecon(con); con = NULL;
+	if (fd_t >= 0) close(fd_t);
+	if (fd_s >= 0) close(fd_s);
+	return tmpdir;
 }
 
-#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -t tmpdir ] [ -h homedir ] -- CONTEXT executable [args] ")
+#define PROC_BASE "/proc"
+
+static int
+killall (security_context_t execcon)
+{
+	DIR *dir;
+	security_context_t scon;
+	struct dirent *de;
+	pid_t *pid_table, pid, self;
+	int i;
+	int pids, max_pids;
+	int running = 0;
+	self = getpid();
+	if (!(dir = opendir(PROC_BASE))) {
+		return -1;
+	}
+	max_pids = 256;
+	pid_table = malloc(max_pids * sizeof (pid_t));
+	if (!pid_table) {
+		(void)closedir(dir);
+		return -1;
+	}
+	pids = 0;
+	context_t con;
+	con = context_new(execcon);
+	const char *mcs = context_range_get(con);
+	printf("mcs=%s\n", mcs);
+	while ((de = readdir (dir)) != NULL) {
+		if (!(pid = (pid_t)atoi(de->d_name)) || pid == self)
+			continue;
+
+		if (pids == max_pids) {
+			if (!(pid_table = realloc(pid_table, 2*pids*sizeof(pid_t)))) {
+				(void)closedir(dir);
+				return -1;
+			}
+			max_pids *= 2;
+		}
+		pid_table[pids++] = pid;
+	}
+
+	(void)closedir(dir);
+
+	for (i = 0; i < pids; i++) {
+		pid_t id = pid_table[i];
+
+		if (getpidcon(id, &scon) == 0) {
+
+			context_t pidcon = context_new(scon);
+			/* Attempt to kill remaining processes */
+			if (strcmp(context_range_get(pidcon), mcs) == 0)
+				kill(id, SIGKILL);
+
+			context_free(pidcon);
+			freecon(scon);
+		}
+		running++;
+	}
+
+	context_free(con);
+	free(pid_table);
+	return running;
+}
 
 int main(int argc, char **argv) {
-	int rc;
 	int status = -1;
+	security_context_t execcon = NULL;
 
-	security_context_t scontext;
-
-	int flag_index;		/* flag index in argv[] */
 	int clflag;		/* holds codes for command line flags */
-	char *tmpdir_s = NULL;	/* tmpdir spec'd by user in argv[] */
+	int usecgroups = 0;
+	int kill_all = 0;
+
 	char *homedir_s = NULL;	/* homedir spec'd by user in argv[] */
+	char *tmpdir_s = NULL;	/* tmpdir spec'd by user in argv[] */
+	char *tmpdir_r = NULL;	/* tmpdir created by seunshare */
+
+	struct stat st_homedir;
+	struct stat st_tmpdir_s;
+	struct stat st_tmpdir_r;
 
 	const struct option long_options[] = {
 		{"homedir", 1, 0, 'h'},
 		{"tmpdir", 1, 0, 't'},
+		{"kill", 1, 0, 'k'},
 		{"verbose", 1, 0, 'v'},
+		{"cgroups", 1, 0, 'c'},
+		{"context", 1, 0, 'Z'},
+		{"capabilities", 1, 0, 'C'},
 		{NULL, 0, 0, 0}
 	};
 
 	uid_t uid = getuid();
-
+/*
 	if (!uid) {
 		fprintf(stderr, _("Must not be root"));
 		return -1;
 	}
+*/
+
+#ifdef USE_NLS
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+#endif
 
 	struct passwd *pwd=getpwuid(uid);
 	if (!pwd) {
@@ -187,34 +870,36 @@ int main(int argc, char **argv) {
 	}
 
 	if (verify_shell(pwd->pw_shell) < 0) {
-		fprintf(stderr, _("Error!  Shell is not valid.\n"));
+		fprintf(stderr, _("Error: User shell is not valid\n"));
 		return -1;
 	}
 
 	while (1) {
-		clflag = getopt_long(argc, argv, "h:t:", long_options,
-				     &flag_index);
+		clflag = getopt_long(argc, argv, "Ccvh:t:Z:", long_options, NULL);
 		if (clflag == -1)
 			break;
 
 		switch (clflag) {
 		case 't':
-			if (!(tmpdir_s = realpath(optarg, NULL))) {
-				fprintf(stderr, _("Invalid mount point %s: %s\n"), optarg, strerror(errno));
-				return -1;
-			}
-			if (verify_mount(tmpdir_s, pwd) < 0) return -1;
+			tmpdir_s = optarg;
+			break;
+		case 'k':
+			kill_all = 1;
 			break;
 		case 'h':
-			if (!(homedir_s = realpath(optarg, NULL))) {
-				fprintf(stderr, _("Invalid mount point %s: %s\n"), optarg, strerror(errno));
-				return -1;
-			}
-			if (verify_mount(homedir_s, pwd) < 0) return -1;
-			if (verify_mount(pwd->pw_dir, pwd) < 0) return -1;
+			homedir_s = optarg;
 			break;
 		case 'v':
-			verbose = 1;
+			verbose++;
+			break;
+		case 'c':
+			usecgroups = 1;
+			break;
+		case 'C':
+			cap_set = CAPNG_SELECT_CAPS;
+			break;
+		case 'Z':
+			execcon = optarg;
 			break;
 		default:
 			fprintf(stderr, "%s\n", USAGE_STRING);
@@ -223,99 +908,131 @@ int main(int argc, char **argv) {
 	}
 
 	if (! homedir_s && ! tmpdir_s) {
-		fprintf(stderr, _("Error: tmpdir and/or homedir required \n"),
-			"%s\n", USAGE_STRING);
+		fprintf(stderr, _("Error: tmpdir and/or homedir required\n %s\n"), USAGE_STRING);
 		return -1;
 	}
 
-	if (argc - optind < 2) {
-		fprintf(stderr, _("Error: context and executable required \n"),
-			"%s\n", USAGE_STRING);
+	if (argc - optind < 1) {
+		fprintf(stderr, _("Error: executable required\n %s\n"), USAGE_STRING);
 		return -1;
 	}
 
-	scontext = argv[optind++];
-	
-	if (set_signal_handles())
+	if (execcon && is_selinux_enabled() != 1) {
+		fprintf(stderr, _("Error: execution context specified, but SELinux is not enabled\n"));
 		return -1;
+	}
 
-        if (unshare(CLONE_NEWNS) < 0) {
-		perror(_("Failed to unshare"));
+	if (set_signal_handles())
 		return -1;
-	}
 
-	if (homedir_s && tmpdir_s && (strncmp(pwd->pw_dir, tmpdir_s, strlen(pwd->pw_dir)) == 0)) {
-	    if (seunshare_mount(tmpdir_s, "/tmp", pwd) < 0)
-		    return -1;
-	    if (seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0)
-		    return -1;
-	} else {			
-		if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0)
-				return -1;
-				
-		if (tmpdir_s && seunshare_mount(tmpdir_s, "/tmp", pwd) < 0)
-				return -1;
-	}
+	if (usecgroups && setup_cgroups() < 0)
+		return  -1;
+
+	/* set fsuid to ruid */
+	/* Changing fsuid is usually required when user-specified directory is
+	 * on an NFS mount.  It's also desired to avoid leaking info about
+	 * existence of the files not accessible to the user. */
+	setfsuid(uid);
 
-	if (drop_capabilities(uid)) {
-		perror(_("Failed to drop all capabilities"));
+	/* verify homedir and tmpdir */
+	if (homedir_s && (
+		verify_directory(homedir_s, NULL, &st_homedir) < 0 ||
+		check_owner_uid(uid, homedir_s, &st_homedir))) return -1;
+	if (tmpdir_s && (
+		verify_directory(tmpdir_s, NULL, &st_tmpdir_s) < 0 ||
+		check_owner_uid(uid, tmpdir_s, &st_tmpdir_s))) return -1;
+	setfsuid(0);
+
+	/* create runtime tmpdir */
+	if (tmpdir_s && (tmpdir_r = create_tmpdir(tmpdir_s, &st_tmpdir_s,
+						  &st_tmpdir_r, pwd, execcon)) == NULL) {
+		fprintf(stderr, _("Failed to create runtime temporary directory\n"));
 		return -1;
 	}
 
-	int child = fork();
+	/* spawn child process */
+	child = fork();
 	if (child == -1) {
 		perror(_("Unable to fork"));
-		return -1;
+		goto err;
 	}
 
-	if (!child) {
-		char *display=NULL;
-		/* Construct a new environment */
-		char *d = getenv("DISPLAY");
-		if (d) {
-			display =  strdup(d);
-			if (!display) {
-				perror(_("Out of memory"));
-				exit(-1);
-			}
+	if (child == 0) {
+		char *display = NULL;
+		int rc = -1;
+
+		if (unshare(CLONE_NEWNS) < 0) {
+			perror(_("Failed to unshare"));
+			goto childerr;
 		}
 
-		if ((rc = clearenv())) {
-			perror(_("Unable to clear environment"));
-			free(display);
-			exit(-1);
+		/* assume fsuid==ruid after this point */
+		setfsuid(uid);
+
+		/* mount homedir and tmpdir, in this order */
+		if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir,
+			&st_homedir) != 0) goto childerr;
+		if (tmpdir_s &&	seunshare_mount(tmpdir_r, "/tmp",
+			&st_tmpdir_r) != 0) goto childerr;
+
+		if (drop_privs(uid) != 0) goto childerr;
+
+		/* construct a new environment */
+		if ((display = getenv("DISPLAY")) != NULL) {
+			if ((display = strdup(display)) == NULL) {
+				perror(_("Out of memory"));
+				goto childerr;
+			}
 		}
-		
-		if (setexeccon(scontext)) {
-			fprintf(stderr, _("Could not set exec context to %s.\n"),
-				scontext);
-			free(display);
-			exit(-1);
+		if ((rc = clearenv()) != 0) {
+			perror(_("Failed to clear environment"));
+			goto childerr;
 		}
-
-		if (display) 
+		if (display)
 			rc |= setenv("DISPLAY", display, 1);
 		rc |= setenv("HOME", pwd->pw_dir, 1);
 		rc |= setenv("SHELL", pwd->pw_shell, 1);
 		rc |= setenv("USER", pwd->pw_name, 1);
 		rc |= setenv("LOGNAME", pwd->pw_name, 1);
 		rc |= setenv("PATH", DEFAULT_PATH, 1);
-		
+		if (rc != 0) {
+			fprintf(stderr, _("Failed to construct environment\n"));
+			goto childerr;
+		}
+
+		/* selinux context */
+		if (execcon && setexeccon(execcon) != 0) {
+			fprintf(stderr, _("Could not set exec context to %s.\n"), execcon);
+			goto childerr;
+		}
+
 		if (chdir(pwd->pw_dir)) {
 			perror(_("Failed to change dir to homedir"));
-			exit(-1);
+			goto childerr;
 		}
 		setsid();
 		execv(argv[optind], argv + optind);
+		fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno));
+childerr:
 		free(display);
-		perror("execv");
 		exit(-1);
-	} else {
-		waitpid(child, &status, 0);
 	}
 
-	free(tmpdir_s);
-	free(homedir_s);
+	drop_caps();
+
+	/* parent waits for child exit to do the cleanup */
+	waitpid(child, &status, 0);
+	status_to_retval(status, status);
+
+	/* Make sure all child processes exit */
+	kill(-child,SIGTERM);
+
+	if (execcon && kill_all)
+		killall(execcon);
+
+	if (tmpdir_r) cleanup_tmpdir(tmpdir_r, tmpdir_s, pwd, 1);
 
+err:
+	free(tmpdir_r);
 	return status;
 }
diff --git a/policycoreutils/sandbox/start b/policycoreutils/sandbox/start
new file mode 100644
index 0000000..52950d7
--- /dev/null
+++ b/policycoreutils/sandbox/start
@@ -0,0 +1,9 @@
+#! /usr/bin/python -Es
+import gtk, commands, sys
+rc = [-1,'']
+try:
+    rc=commands.getstatusoutput(sys.argv[1])
+except:
+    pass
+if rc[0] == 0:
+    print rc[1]
diff --git a/policycoreutils/scripts/fixfiles b/policycoreutils/scripts/fixfiles
index e4e5f0d..27dcccf 100755
--- a/policycoreutils/scripts/fixfiles
+++ b/policycoreutils/scripts/fixfiles
@@ -103,7 +103,7 @@ exclude_dirs_from_relabelling() {
 
 exclude_dirs() {
     exclude=
-    for i in /home /root /tmp /dev; do
+    for i in /var/lib/BackupPC /home /tmp /dev; do
         [ -e $i ]  && exclude="$exclude -e $i";
     done
     exclude="$exclude `exclude_dirs_from_relabelling`"
diff --git a/policycoreutils/semanage/default_encoding/Makefile b/policycoreutils/semanage/default_encoding/Makefile
new file mode 100644
index 0000000..e15a877
--- /dev/null
+++ b/policycoreutils/semanage/default_encoding/Makefile
@@ -0,0 +1,8 @@
+all:
+	LDFLAGS="" python setup.py build
+
+install: all
+	LDFLAGS="" python setup.py install --root=$(DESTDIR)/
+
+clean:
+	rm -rf build *~
diff --git a/policycoreutils/semanage/default_encoding/default_encoding.c b/policycoreutils/semanage/default_encoding/default_encoding.c
new file mode 100644
index 0000000..2ba4870
--- /dev/null
+++ b/policycoreutils/semanage/default_encoding/default_encoding.c
@@ -0,0 +1,59 @@
+/*
+ * Authors:
+ *   John Dennis <jdennis@redhat.com>
+ *
+ * Copyright (C) 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.
+ *
+ * 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
+ */
+
+#include <Python.h>
+
+PyDoc_STRVAR(setdefaultencoding_doc,
+"setdefaultencoding(encoding='utf-8')\n\
+\n\
+Set the current default string encoding used by the Unicode implementation.\n\
+Defaults to utf-8."
+);
+
+static PyObject *
+setdefaultencoding(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = {"utf-8", NULL};
+    char *encoding;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:setdefaultencoding", kwlist, &encoding))
+        return NULL;
+
+    if (PyUnicode_SetDefaultEncoding(encoding))
+        return NULL;
+
+    Py_RETURN_NONE;
+}
+
+static PyMethodDef methods[] = {
+    {"setdefaultencoding", (PyCFunction)setdefaultencoding, METH_VARARGS|METH_KEYWORDS, setdefaultencoding_doc},
+	{NULL,		NULL}		/* sentinel */
+};
+
+
+PyMODINIT_FUNC
+initdefault_encoding_utf8(void)
+{
+    PyObject* m;
+
+    PyUnicode_SetDefaultEncoding("utf-8");
+    m = Py_InitModule3("default_encoding_utf8", methods, "Forces the default encoding to utf-8");
+}
diff --git a/policycoreutils/semanage/default_encoding/policycoreutils/__init__.py b/policycoreutils/semanage/default_encoding/policycoreutils/__init__.py
new file mode 100644
index 0000000..ccb6b8b
--- /dev/null
+++ b/policycoreutils/semanage/default_encoding/policycoreutils/__init__.py
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2006,2007,2008, 2009 Red Hat, Inc.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
diff --git a/policycoreutils/semanage/default_encoding/setup.py b/policycoreutils/semanage/default_encoding/setup.py
new file mode 100644
index 0000000..e2befdb
--- /dev/null
+++ b/policycoreutils/semanage/default_encoding/setup.py
@@ -0,0 +1,38 @@
+# Authors:
+#   John Dennis <jdennis@redhat.com>
+#
+# Copyright (C) 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.
+#
+# 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
+
+from distutils.core import setup, Extension
+
+default_encoding_utf8 = Extension('policycoreutils.default_encoding_utf8', ['default_encoding.c'])
+
+setup(name             = 'policycoreutils-default-encoding',
+      version          = '0.1',
+      description      = 'Forces the default encoding in Python to be utf-8',
+      long_description = 'Forces the default encoding in Python to be utf-8',
+      author           = 'John Dennis',
+      author_email     = 'jdennis@redhat.com',
+      maintainer       = 'John Dennis',
+      maintainer_email = 'jdennis@redhat.com',
+      license          = 'GPLv3+',
+      platforms        = 'posix',
+      url              = '',
+      download_url     = '',
+      ext_modules      = [default_encoding_utf8],
+      packages=["policycoreutils"],
+)
diff --git a/policycoreutils/semanage/semanage b/policycoreutils/semanage/semanage
index 0140cd2..656a028 100644
--- a/policycoreutils/semanage/semanage
+++ b/policycoreutils/semanage/semanage
@@ -20,6 +20,7 @@
 #                                        02111-1307  USA
 #
 #  
+import policycoreutils.default_encoding_utf8
 import sys, getopt, re
 import seobject
 import selinux
@@ -32,7 +33,7 @@ gettext.textdomain(PROGNAME)
 try:
        gettext.install(PROGNAME,
                        localedir="/usr/share/locale",
-                       unicode=False,
+                       unicode=True,
                        codeset = 'utf-8')
 except IOError:
        import __builtin__
@@ -283,11 +284,14 @@ Object-specific Options (see above):
 				equal = a
 
 			if o == "--enable":
-				set_action(o)
+				if disable:
+					raise ValueError(_("You can't disable and enable at the same time"))
+
 				enable = True
 
 			if o == "--disable":
-				set_action(o)
+				if enable:
+					raise ValueError(_("You can't disable and enable at the same time"))
 				disable = True
 
 			if o == "-F"  or o == "--file":
@@ -338,9 +342,11 @@ Object-specific Options (see above):
 
 			if o == "--on" or o == "-1":
 				value = "on"
+				modify = True
 
 			if o == "--off" or o == "-0":
 				value = "off"
+				modify = True
 
 		if object == "login":
 			OBJECT = seobject.loginRecords(store)
@@ -362,6 +368,8 @@ Object-specific Options (see above):
 		
 		if object == "boolean":
 			OBJECT = seobject.booleanRecords(store)
+			if use_file:
+				modify = True
 
 		if object == "module":
 			OBJECT = seobject.moduleRecords(store)
@@ -500,31 +508,36 @@ Object-specific Options (see above):
                if len(sys.argv) < 3:
                       usage(_("Requires 2 or more arguments"))
                 
-               gopts, cmds = getopt.getopt(sys.argv[1:],
-                                           '01adf:i:lhmno:p:s:FCDR:L:r:t:T:P:S:',
-                                           ['add',
-                                            'delete',
-                                            'deleteall',
-                                            'ftype=',
-                                            'file',
-                                            'help',
-                                            'input=',
-                                            'list', 
-                                            'modify',
-                                            'noheading',
-                                            'localist',
-                                            'off', 
-                                            'on', 
-                                            'output=',
-                                            'proto=',
-                                            'seuser=',
-                                            'store=',
-                                            'range=',
-                                            'level=',
-                                            'roles=',
-                                            'type=',
-                                            'prefix='
-                                            ])
+               try:
+                      gopts, cmds = getopt.getopt(sys.argv[1:],
+                                                  '01adf:i:lhmno:p:s:FCDR:L:r:t:T:P:S:',
+                                                  ['add',
+                                                   'delete',
+                                                   'deleteall',
+                                                   'ftype=',
+                                                   'file',
+                                                   'help',
+                                                   'input=',
+                                                   'list',
+                                                   'modify',
+                                                   'noheading',
+                                                   'localist',
+                                                   'off',
+                                                   'on',
+                                                   'output=',
+                                                   'proto=',
+                                                   'seuser=',
+                                                   'store=',
+                                                   'range=',
+                                                   'level=',
+                                                   'roles=',
+                                                   'type=',
+                                                   'trans=',
+                                                   'prefix='
+                                                   ])
+               except getopt.error, error:
+                      usage(_("Options Error %s ") % error.msg)
+
                for o, a in gopts:
                       if o == "-S" or o == '--store':
                              store = a
@@ -554,8 +567,6 @@ Object-specific Options (see above):
                else:
                       process_args(sys.argv[1:])
 			
-	except getopt.error, error:
-		usage(_("Options Error %s ") % error.msg)
 	except ValueError, error:
 		errorExit(error.args[0])
 	except KeyError, error:
diff --git a/policycoreutils/semanage/seobject.py b/policycoreutils/semanage/seobject.py
index 6842b07..6742fe9 100644
--- a/policycoreutils/semanage/seobject.py
+++ b/policycoreutils/semanage/seobject.py
@@ -30,11 +30,10 @@ from IPy import IP
 import gettext
 gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
 gettext.textdomain(PROGNAME)
-try:
-       gettext.install(PROGNAME, localedir = "/usr/share/locale", unicode = 1)
-except IOError:
-       import __builtin__
-       __builtin__.__dict__['_'] = unicode
+
+import gettext
+translation=gettext.translation(PROGNAME, localedir = "/usr/share/locale", fallback=True)
+_=translation.ugettext
 
 import syslog
 
@@ -161,10 +160,12 @@ def untranslate(trans, prepend = 1):
 		return trans
 	else:
 		return raw
-	
+
 class semanageRecords:
         transaction = False
         handle = None
+        store = None
+
         def __init__(self, store):
                global handle
                       
@@ -182,7 +183,7 @@ class semanageRecords:
 
                if not semanageRecords.transaction and store != "":
                       semanage_select_store(handle, store, SEMANAGE_CON_DIRECT);
-                     semanageRecords.store = store
+                      semanageRecords.store = store
 
                if not semanage_is_managed(handle):
                       semanage_handle_destroy(handle)
@@ -328,6 +329,7 @@ class permissiveRecords(semanageRecords):
                       name = semanage_module_get_name(mod)
                       if name and name.startswith("permissive_"):
                              l.append(name.split("permissive_")[1])
+
                return l
 
 	def list(self, heading = 1, locallist = 0):
@@ -420,7 +422,9 @@ class loginRecords(semanageRecords):
 		if rc < 0:
 			raise ValueError(_("Could not check if login mapping for %s is defined") % name)
 		if exists:
-			raise ValueError(_("Login mapping for %s is already defined") % name)
+                       semanage_seuser_key_free(k)
+                       return self.__modify(name, sename, serange)
+
                 if name[0] == '%':
                        try:
                               grp.getgrnam(name[1:])
@@ -627,7 +631,8 @@ class seluserRecords(semanageRecords):
                 if rc < 0:
                        raise ValueError(_("Could not check if SELinux user %s is defined") % name)
                 if exists:
-                       raise ValueError(_("SELinux user %s is already defined") % name)
+                       semanage_user_key_free(k)
+                       return self.__modify(name, roles, selevel, serange, prefix)
 
                 (rc, u) = semanage_user_create(self.sh)
                 if rc < 0:
@@ -864,6 +869,7 @@ class portRecords(semanageRecords):
 		return ( k, proto_d, low, high )
 
 	def __add(self, port, proto, serange, type):
+
 		if is_mls_enabled == 1:
 			if serange == "":
 				serange = "s0"
@@ -926,6 +932,7 @@ class portRecords(semanageRecords):
                 self.commit()
 
 	def __modify(self, port, proto, serange, setype):
+
 		if serange == "" and setype == "":
 			if is_mls_enabled == 1:
 				raise ValueError(_("Requires setype or serange"))
@@ -1136,7 +1143,8 @@ class nodeRecords(semanageRecords):
 
                (rc, exists) = semanage_node_exists(self.sh, k)
                if exists:
-                       raise ValueError(_("Addr %s already defined") % addr)
+                       semanage_node_key_free(k)
+                       return self.__modify(addr, mask, self.protocol[proto], serange, ctype)
 
                (rc, node) = semanage_node_create(self.sh)
                if rc < 0:
@@ -1152,7 +1160,6 @@ class nodeRecords(semanageRecords):
                if rc < 0:
                        raise ValueError(_("Could not set mask for %s") % addr)
 
-
                rc = semanage_context_set_user(self.sh, con, "system_u")
                if rc < 0:
                        raise ValueError(_("Could not set user in addr context for %s") % addr)
@@ -1204,12 +1211,11 @@ class nodeRecords(semanageRecords):
                if not exists:
                        raise ValueError(_("Addr %s is not defined") % addr)
 
-               (rc, node) = semanage_node_query(self.sh, k)
+               (rc, node) = semanage_node_query_local(self.sh, k)
                if rc < 0:
                        raise ValueError(_("Could not query addr %s") % addr)
 
                con = semanage_node_get_con(node)
-
                if serange != "":
                        semanage_context_set_mls(self.sh, con, untranslate(serange))
                if setype != "":
@@ -1334,7 +1340,8 @@ class interfaceRecords(semanageRecords):
 		if rc < 0:
 			raise ValueError(_("Could not check if interface %s is defined") % interface)
 		if exists:
-			raise ValueError(_("Interface %s already defined") % interface)
+                        semanage_iface_key_free(k)
+                        return self.__modify(interface, serange, ctype)
 
 		(rc, iface) = semanage_iface_create(self.sh)
 		if rc < 0:
@@ -1592,7 +1599,8 @@ class fcontextRecords(semanageRecords):
                               raise ValueError(_("Could not check if file context for %s is defined") % target)
 
                 if exists:
-                       raise ValueError(_("File context for %s already defined") % target)
+                       semanage_fcontext_key_free(k)
+                       return self.__modify(target, type, ftype, serange, seuser)
 
 		(rc, fcontext) = semanage_fcontext_create(self.sh)
 		if rc < 0:
@@ -1783,11 +1791,11 @@ class fcontextRecords(semanageRecords):
                return l
 
 	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:
@@ -1814,6 +1822,18 @@ class booleanRecords(semanageRecords):
                 self.dict["1"] = 1
                 self.dict["0"] = 0
 
+		try:
+			rc, self.current_booleans = selinux.security_get_boolean_names()
+			rc, ptype = selinux.selinux_getpolicytype()
+		except:
+			self.current_booleans = []
+			ptype = None
+
+		if self.store == None or self.store == ptype:
+			self.modify_local = True
+		else:
+			self.modify_local = False
+
 	def __mod(self, name, value):
                 (rc, k) = semanage_bool_key_create(self.sh, name)
                 if rc < 0:
@@ -1833,9 +1853,10 @@ class booleanRecords(semanageRecords):
                 else:
                        raise ValueError(_("You must specify one of the following values: %s") % ", ".join(self.dict.keys()) )
                 
-                rc = semanage_bool_set_active(self.sh, k, b)
-                if rc < 0:
-                       raise ValueError(_("Could not set active value of boolean %s") % name)
+		if self.modify_local and name in self.current_booleans:
+			rc = semanage_bool_set_active(self.sh, k, b)
+			if rc < 0:
+				raise ValueError(_("Could not set active value of boolean %s") % name)
                 rc = semanage_bool_modify_local(self.sh, k, b)
                 if rc < 0:
                        raise ValueError(_("Could not modify boolean %s") % name)
@@ -1918,8 +1939,12 @@ class booleanRecords(semanageRecords):
                        value = []
                        name = semanage_bool_get_name(boolean)
                        value.append(semanage_bool_get_value(boolean))
-                       value.append(selinux.security_get_boolean_pending(name))
-                       value.append(selinux.security_get_boolean_active(name))
+		       if self.modify_local and boolean in self.current_booleans:
+			       value.append(selinux.security_get_boolean_pending(name))
+			       value.append(selinux.security_get_boolean_active(name))
+		       else:
+			       value.append(value[0])
+			       value.append(value[0])
                        ddict[name] = value
 
 		return ddict
diff --git a/policycoreutils/semodule_package/Makefile b/policycoreutils/semodule_package/Makefile
index 0a4a3a6..f84cd7e 100644
--- a/policycoreutils/semodule_package/Makefile
+++ b/policycoreutils/semodule_package/Makefile
@@ -9,15 +9,17 @@ CFLAGS ?= -Werror -Wall -W
 override CFLAGS += -I$(INCLUDEDIR)
 LDLIBS = -lsepol -lselinux -L$(LIBDIR)
 
-all: semodule_package
+all: semodule_package semodule_unpackage
 
 semodule_package:  semodule_package.o 
 
 install: all
 	-mkdir -p $(BINDIR)
 	install -m 755 semodule_package $(BINDIR)
+	install -m 755 semodule_unpackage $(BINDIR)
 	test -d $(MANDIR)/man8 || install -m 755 -d $(MANDIR)/man8
 	install -m 644 semodule_package.8 $(MANDIR)/man8/
+	install -m 644 semodule_unpackage.8 $(MANDIR)/man8/
 
 relabel:
 
diff --git a/policycoreutils/semodule_package/semodule_package.8 b/policycoreutils/semodule_package/semodule_package.8
index 29c9eb2..ddad2d2 100644
--- a/policycoreutils/semodule_package/semodule_package.8
+++ b/policycoreutils/semodule_package/semodule_package.8
@@ -44,7 +44,7 @@ File contexts file for the module (optional).
 netfilter context file to be included in the package.
 
 .SH SEE ALSO
-.B checkmodule(8), semodule(8)
+.B checkmodule(8), semodule(8), semodule_unpackage(8)
 .SH AUTHORS
 .nf
 This manual page was written by Dan Walsh <dwalsh@redhat.com>.
diff --git a/policycoreutils/semodule_package/semodule_unpackage.8 b/policycoreutils/semodule_package/semodule_unpackage.8
new file mode 100644
index 0000000..62dd53e
--- /dev/null
+++ b/policycoreutils/semodule_package/semodule_unpackage.8
@@ -0,0 +1,24 @@
+.TH SEMODULE_PACKAGE "8" "Nov 2005" "Security Enhanced Linux" NSA
+.SH NAME
+semodule_unpackage \- Extract polciy module and file context file from an SELinux policy module unpackage.
+
+.SH SYNOPSIS
+.B semodule_unpackage <module> [<file contexts>]
+.br
+.SH DESCRIPTION
+.PP
+semodule_unpackage is the tool used to extract the SELinux policy module
+ and file context file from an SELinux Policy Package.
+
+.SH EXAMPLE
+.nf
+# Extract the httpd module file from httpd policy package.
+$ semodule_unpackage httpd.pp httpd.mod httpd.fc
+.fi
+
+.SH SEE ALSO
+.B semodule_package(8)
+.SH AUTHORS
+.nf
+This manual page was written by Dan Walsh <dwalsh@redhat.com>.
+The program was written by Stephen Smalley <sds@tycho.nsa.gov>
diff --git a/policycoreutils/semodule_package/semodule_unpackage.c b/policycoreutils/semodule_package/semodule_unpackage.c
new file mode 100644
index 0000000..0120ee4
--- /dev/null
+++ b/policycoreutils/semodule_package/semodule_unpackage.c
@@ -0,0 +1,103 @@
+#include <sepol/module.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+
+char *progname = NULL;
+extern char *optarg;
+
+static void usage(char *progname)
+{
+	printf("usage: %s ppfile modfile [fcfile]\n", progname);
+	exit(1);
+}
+
+static int file_to_policy_file(char *filename, struct sepol_policy_file **pf, char *mode)
+{
+	FILE *f;
+
+	if (sepol_policy_file_create(pf)) {
+		fprintf(stderr, "%s:  Out of memory\n", progname);
+		return -1;
+	}
+
+	f = fopen(filename, mode);
+	if (!f) {
+		fprintf(stderr, "%s:  Could not open file %s:  %s\n", progname, strerror(errno), filename);
+		return -1;
+	}
+	sepol_policy_file_set_fp(*pf, f);
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	struct sepol_module_package *pkg;
+	struct sepol_policy_file *in, *out;
+	FILE *fp;
+	size_t len;
+	char *ppfile, *modfile, *fcfile = NULL, *fcdata;
+
+	progname = argv[0];
+
+	if (argc < 3) {
+		usage(progname);
+		exit(1);
+	}
+
+	ppfile = argv[1];
+	modfile = argv[2];
+	if (argc >= 3)
+		fcfile = argv[3];
+
+	if (file_to_policy_file(ppfile, &in, "r"))
+		exit(1);
+
+	if (sepol_module_package_create(&pkg)) {
+                fprintf(stderr, "%s:  Out of memory\n", progname);
+                exit(1);
+	}
+
+	if (sepol_module_package_read(pkg, in, 0) == -1) {
+                fprintf(stderr, "%s:  Error while reading policy module from %s\n",
+			progname, ppfile);
+                exit(1);
+	}
+
+	if (file_to_policy_file(modfile, &out, "w"))
+		exit(1);
+
+        if (sepol_policydb_write(sepol_module_package_get_policy(pkg), out)) {
+                fprintf(stderr, "%s:  Error while writing module to %s\n", progname, modfile);
+                exit(1);
+        }
+
+	sepol_policy_file_free(in);
+	sepol_policy_file_free(out);
+
+	len = sepol_module_package_get_file_contexts_len(pkg);
+	if (fcfile && len) {
+		fp = fopen(fcfile, "w");
+		if (!fp) {
+			fprintf(stderr, "%s:  Could not open file %s:  %s\n", progname, strerror(errno), fcfile);
+			exit(1);
+		}
+		fcdata = sepol_module_package_get_file_contexts(pkg);
+		if (fwrite(fcdata, 1, len, fp) != len) {
+			fprintf(stderr, "%s:  Could not write file %s:  %s\n", progname, strerror(errno), fcfile);
+			exit(1);
+		}
+		fclose(fp);
+	}
+
+	sepol_module_package_free(pkg);
+	exit(0);
+}
diff --git a/policycoreutils/sepolgen-ifgen/.gitignore b/policycoreutils/sepolgen-ifgen/.gitignore
new file mode 100644
index 0000000..3816d2e
--- /dev/null
+++ b/policycoreutils/sepolgen-ifgen/.gitignore
@@ -0,0 +1 @@
+sepolgen-ifgen-attr-helper
diff --git a/policycoreutils/sepolgen-ifgen/Makefile b/policycoreutils/sepolgen-ifgen/Makefile
new file mode 100644
index 0000000..99f8fd0
--- /dev/null
+++ b/policycoreutils/sepolgen-ifgen/Makefile
@@ -0,0 +1,25 @@
+# Installation directories.
+PREFIX ?= ${DESTDIR}/usr
+BINDIR ?= $(PREFIX)/bin
+LIBDIR ?= ${PREFIX}/lib
+INCLUDEDIR ?= $(PREFIX)/include
+
+CFLAGS ?= -Werror -Wall -W
+override CFLAGS += -I$(INCLUDEDIR)
+LDLIBS = $(LIBDIR)/libsepol.a
+
+all: sepolgen-ifgen-attr-helper
+
+sepolgen-ifgen-attr-helper: sepolgen-ifgen-attr-helper.o
+
+install: all
+	-mkdir -p $(BINDIR)
+	install -m 755 sepolgen-ifgen-attr-helper $(BINDIR)
+
+clean:
+	rm -f *~ *.o sepolgen-ifgen-attr-helper
+
+indent:
+	../../scripts/Lindent $(wildcard *.[ch])
+
+relabel: ;
diff --git a/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c b/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c
new file mode 100644
index 0000000..1ce37b0
--- /dev/null
+++ b/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c
@@ -0,0 +1,232 @@
+/* Authors: Frank Mayer <mayerf@tresys.com>
+ *   and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2003,2010 Tresys Technology, LLC
+ *
+ *	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, version 2.
+ *
+ * Adapted from dispol.c.
+ *
+ * This program is used by sepolgen-ifgen to get the access for all of
+ * the attributes in the policy so that it can resolve the
+ * typeattribute statements in the interfaces.
+ *
+ * It outputs the attribute access in a similar format to what sepolgen
+ * uses to store interface vectors:
+ *   [Attribute sandbox_x_domain]
+ *   sandbox_x_domain,samba_var_t,file,ioctl,read,getattr,lock,open
+ *   sandbox_x_domain,samba_var_t,dir,getattr,search,open
+ *   sandbox_x_domain,initrc_var_run_t,file,ioctl,read,getattr,lock,open
+ *
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/util.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+struct val_to_name {
+	unsigned int val;
+	char *name;
+};
+
+static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	struct val_to_name *v = data;
+	perm_datum_t *perdatum;
+
+	perdatum = (perm_datum_t *) datum;
+
+	if (v->val == perdatum->s.value) {
+		v->name = key;
+		return 1;
+	}
+
+	return 0;
+}
+
+int render_access_mask(uint32_t av, avtab_key_t *key, policydb_t *policydbp,
+		       FILE *fp)
+{
+	struct val_to_name v;
+	class_datum_t *cladatum;
+	char *perm = NULL;
+	unsigned int i;
+	int rc;
+	uint32_t tclass = key->target_class;
+
+	cladatum = policydbp->class_val_to_struct[tclass - 1];
+	for (i = 0; i < cladatum->permissions.nprim; i++) {
+		if (av & (1 << i)) {
+			v.val = i + 1;
+			rc = hashtab_map(cladatum->permissions.table,
+					 perm_name, &v);
+			if (!rc && cladatum->comdatum) {
+				rc = hashtab_map(cladatum->comdatum->
+						 permissions.table, perm_name,
+						 &v);
+			}
+			if (rc)
+				perm = v.name;
+			if (perm) {
+				fprintf(fp, ",%s", perm);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int render_key(avtab_key_t *key, policydb_t *p, FILE *fp)
+{
+	char *stype, *ttype, *tclass;
+	stype = p->p_type_val_to_name[key->source_type - 1];
+	ttype = p->p_type_val_to_name[key->target_type - 1];
+	tclass = p->p_class_val_to_name[key->target_class - 1];
+	if (stype && ttype) {
+		fprintf(fp, "%s,%s,%s", stype, ttype, tclass);
+	} else {
+		fprintf(stderr, "error rendering key\n");
+		exit(1);
+	}
+
+	return 0;
+}
+
+struct callback_data
+{
+	uint32_t attr;
+	policydb_t *policy;
+	FILE *fp;
+};
+
+int output_avrule(avtab_key_t *key, avtab_datum_t *datum, void *args)
+{
+	struct callback_data *cb_data = (struct callback_data *)args;
+
+	if (key->source_type != cb_data->attr)
+		return 0;
+
+	if (!(key->specified & AVTAB_AV && key->specified & AVTAB_ALLOWED))
+		return 0;
+
+	render_key(key, cb_data->policy, cb_data->fp);
+	render_access_mask(datum->data, key, cb_data->policy, cb_data->fp);
+	fprintf(cb_data->fp, "\n");
+
+	return 0;
+}
+
+static int attribute_callback(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+	struct callback_data *cb_data = (struct callback_data *)datap;
+	type_datum_t *t = (type_datum_t *)datum;
+
+	if (t->flavor == TYPE_ATTRIB) {
+		fprintf(cb_data->fp, "[Attribute %s]\n", key);
+		cb_data->attr = t->s.value;
+		if (avtab_map(&cb_data->policy->te_avtab, output_avrule, cb_data) < 0)
+			return -1;
+		if (avtab_map(&cb_data->policy->te_cond_avtab, output_avrule, cb_data) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+static policydb_t *load_policy(const char *filename)
+{
+	policydb_t *policydb;
+	struct policy_file pf;
+	FILE *fp;
+	int ret;
+
+	fp = fopen(filename, "r");
+	if (fp == NULL) {
+		fprintf(stderr, "Can't open '%s':  %s\n",
+			filename, strerror(errno));
+		return NULL;
+	}
+
+	policy_file_init(&pf);
+	pf.type = PF_USE_STDIO;
+	pf.fp = fp;
+
+	policydb = malloc(sizeof(policydb_t));
+	if (policydb == NULL) {
+		fprintf(stderr, "Out of memory!\n");
+		return NULL;
+	}
+
+	if (policydb_init(policydb)) {
+		fprintf(stderr, "Out of memory!\n");
+		free(policydb);
+		return NULL;
+	}
+
+	ret = policydb_read(policydb, &pf, 1);
+	if (ret) {
+		fprintf(stderr,
+			"error(s) encountered while parsing configuration\n");
+		free(policydb);
+		return NULL;
+	}
+
+	fclose(fp);
+
+	return policydb;
+
+}
+
+void usage(char *progname)
+{
+	printf("usage: %s policy_file out_file\n", progname);
+}
+
+int main(int argc, char **argv)
+{
+	policydb_t *p;
+	struct callback_data cb_data;
+	FILE *fp;
+
+	if (argc != 3) {
+		usage(argv[0]);
+		return -1;
+	}
+
+	/* Open the policy. */
+	p = load_policy(argv[1]);
+	if (p == NULL)
+		return -1;
+
+	/* Open the output policy. */
+	fp = fopen(argv[2], "w");
+	if (fp == NULL) {
+		fprintf(stderr, "error opening output file\n");
+		policydb_destroy(p);
+		free(p);
+		return -1;
+	}
+
+	/* Find all of the attributes and output their access. */
+	cb_data.policy = p;
+	cb_data.fp = fp;
+
+	if (hashtab_map(p->p_types.table, attribute_callback, &cb_data)) {
+		printf("error finding attributes\n");
+	}
+
+	policydb_destroy(p);
+	free(p);
+	fclose(fp);
+
+	return 0;
+}
diff --git a/policycoreutils/setfiles/restore.c b/policycoreutils/setfiles/restore.c
index e05761a..5bcb44a 100644
--- a/policycoreutils/setfiles/restore.c
+++ b/policycoreutils/setfiles/restore.c
@@ -318,11 +318,16 @@ static int process_one(char *name, int recurse_this_path)
 
 
 	ftsent = fts_read(fts_handle);
-	if (ftsent != NULL) {
-		/* Keep the inode of the first one. */
-		dev_num = ftsent->fts_statp->st_dev;
+	if (ftsent == NULL) {
+		fprintf(stderr,
+			"%s: error while labeling %s:  %s\n",
+			r_opts->progname, namelist[0], strerror(errno));
+		goto err;
 	}
 
+	/* Keep the inode of the first one. */
+	dev_num = ftsent->fts_statp->st_dev;
+
 	do {
 		rc = 0;
 		/* Skip the post order nodes. */
@@ -368,19 +373,21 @@ int process_glob(char *name, int recurse) {
 	int errors;
 	memset(&globbuf, 0, sizeof(globbuf));
 	errors = glob(name, GLOB_TILDE | GLOB_PERIOD, NULL, &globbuf);
-	if (errors)
-		errors = process_one_realpath(name, recurse);
-	else {
-		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;
-			errors |= process_one_realpath(globbuf.gl_pathv[i], recurse);
-		}
-		globfree(&globbuf);
+	if (errors == GLOB_NOMATCH)
+		return 0;
+
+	if (errors) 
+		return errors;
+
+	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;
+		errors |= process_one_realpath(globbuf.gl_pathv[i], recurse);
 	}
+	globfree(&globbuf);
 	return errors;
 }
 
@@ -388,7 +395,7 @@ int process_one_realpath(char *name, int recurse)
 {
 	int rc = 0;
 	char *p;
-	struct stat sb;
+	struct stat64 sb;
 
 	if (r_opts == NULL){
 		fprintf(stderr,
@@ -399,7 +406,7 @@ int process_one_realpath(char *name, int recurse)
 	if (!r_opts->expand_realpath) {
 		return process_one(name, recurse);
 	} else {
-		rc = lstat(name, &sb);
+		rc = lstat64(name, &sb);
 		if (rc < 0) {
 			if (r_opts->ignore_enoent && errno == ENOENT)
 				return 0;
@@ -566,7 +573,7 @@ static int filespec_add(ino_t ino, const security_context_t con, const char *fil
 {
 	file_spec_t *prevfl, *fl;
 	int h, ret;
-	struct stat sb;
+	struct stat64 sb;
 
 	if (!fl_head) {
 		fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS);
@@ -579,7 +586,7 @@ static int filespec_add(ino_t ino, const security_context_t con, const char *fil
 	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);
+			ret = lstat64(fl->file, &sb);
 			if (ret < 0 || sb.st_ino != ino) {
 				freecon(fl->con);
 				free(fl->file);
@@ -631,5 +638,67 @@ static int filespec_add(ino_t ino, const security_context_t con, const char *fil
 	return -1;
 }
 
+#include <sys/utsname.h>
+/*
+   Search /proc/mounts for all file systems that do not support extended
+   attributes and add them to the exclude directory table.  File systems
+   that support security labels have the seclabel option.
+*/
+void exclude_non_seclabel_mounts()
+{
+	struct utsname uts;
+	FILE *fp;
+	size_t len;
+	ssize_t num;
+	int index = 0, found = 0;
+	char *mount_info[4];
+	char *buf = NULL, *item;
+
+	/* Check to see if the kernel supports seclabel */
+	if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0)
+		return;
+	if (is_selinux_enabled() <= 0)
+		return;
+
+	fp = fopen("/proc/mounts", "r");
+	if (!fp)
+		return;
+
+	while ((num = getline(&buf, &len, fp)) != -1) {
+		found = 0;
+		index = 0;
+		item = strtok(buf, " ");
+		while (item != NULL) {
+			mount_info[index] = item;
+			if (index == 3)
+				break;
+			index++;
+			item = strtok(NULL, " ");
+		}
+		if (index < 3) {
+			fprintf(stderr,
+				"/proc/mounts record \"%s\" has incorrect format.\n",
+				buf);
+			continue;
+		}
 
+		/* remove pre-existing entry */
+		remove_exclude(mount_info[1]);
+
+		item = strtok(mount_info[3], ",");
+		while (item != NULL) {
+			if (strcmp(item, "seclabel") == 0) {
+				found = 1;
+				break;
+			}
+			item = strtok(NULL, ",");
+		}
+
+		/* exclude mount points without the seclabel option */
+		if (!found)
+			add_exclude(mount_info[1]);
+	}
+
+	free(buf);
+}
 
diff --git a/policycoreutils/setfiles/restore.h b/policycoreutils/setfiles/restore.h
index 7e988d5..ac27222 100644
--- a/policycoreutils/setfiles/restore.h
+++ b/policycoreutils/setfiles/restore.h
@@ -49,5 +49,6 @@ int exclude(const char *path);
 void remove_exclude(const char *directory);
 int process_one_realpath(char *name, int recurse);
 int process_glob(char *name, int recurse);
+void exclude_non_seclabel_mounts();
 
 #endif
diff --git a/policycoreutils/setfiles/setfiles.c b/policycoreutils/setfiles/setfiles.c
index d320e9f..fa0cd6a 100644
--- a/policycoreutils/setfiles/setfiles.c
+++ b/policycoreutils/setfiles/setfiles.c
@@ -5,7 +5,6 @@
 #include <ctype.h>
 #include <regex.h>
 #include <sys/vfs.h>
-#include <sys/utsname.h>
 #define __USE_XOPEN_EXTENDED 1	/* nftw */
 #include <libgen.h>
 #ifdef USE_AUDIT
@@ -15,8 +14,6 @@
 #define AUDIT_FS_RELABEL 2309
 #endif
 #endif
-static int mass_relabel;
-static int mass_relabel_errs;
 
 
 /* cmdline opts*/
@@ -24,7 +21,6 @@ static int mass_relabel_errs;
 static char *policyfile = NULL;
 static int warn_no_match = 0;
 static int null_terminated = 0;
-static int errors;
 static struct restore_opts r_opts;
 
 #define STAT_BLOCK_SIZE 1
@@ -108,10 +104,11 @@ int canoncon(char **contextp)
 }
 
 #ifndef USE_AUDIT
-static void maybe_audit_mass_relabel(void)
+static void maybe_audit_mass_relabel(int mass_relabel __attribute__((unused)),
+				     int mass_relabel_errs __attribute__((unused)))
 {
 #else
-static void maybe_audit_mass_relabel(void)
+static void maybe_audit_mass_relabel(int mass_relabel, int mass_relabel_errs)
 {
 	int audit_fd = -1;
 	int rc = 0;
@@ -137,69 +134,6 @@ static void maybe_audit_mass_relabel(void)
 #endif
 }
 
-/*
-   Search /proc/mounts for all file systems that do not support extended
-   attributes and add them to the exclude directory table.  File systems
-   that support security labels have the seclabel option.
-*/
-static void exclude_non_seclabel_mounts()
-{
-	struct utsname uts;
-	FILE *fp;
-	size_t len;
-	ssize_t num;
-	int index = 0, found = 0;
-	char *mount_info[4];
-	char *buf = NULL, *item;
-
-	/* Check to see if the kernel supports seclabel */
-	if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0)
-		return;
-	if (is_selinux_enabled() <= 0)
-		return;
-
-	fp = fopen("/proc/mounts", "r");
-	if (!fp)
-		return;
-
-	while ((num = getline(&buf, &len, fp)) != -1) {
-		found = 0;
-		index = 0;
-		item = strtok(buf, " ");
-		while (item != NULL) {
-			mount_info[index] = item;
-			if (index == 3)
-				break;
-			index++;
-			item = strtok(NULL, " ");
-		}
-		if (index < 3) {
-			fprintf(stderr,
-				"/proc/mounts record \"%s\" has incorrect format.\n",
-				buf);
-			continue;
-		}
-
-		/* remove pre-existing entry */
-		remove_exclude(mount_info[1]);
-
-		item = strtok(mount_info[3], ",");
-		while (item != NULL) {
-			if (strcmp(item, "seclabel") == 0) {
-				found = 1;
-				break;
-			}
-			item = strtok(NULL, ",");
-		}
-
-		/* exclude mount points without the seclabel option */
-		if (!found)
-			add_exclude(mount_info[1]);
-	}
-
-	free(buf);
-}
-
 int main(int argc, char **argv)
 {
 	struct stat sb;
@@ -210,6 +144,7 @@ int main(int argc, char **argv)
 	size_t buf_len;
 	int recurse; /* Recursive descent. */
 	char *base;
+	int mass_relabel = 0, errors = 0;
 	
 	memset(&r_opts, 0, sizeof(r_opts));
 
@@ -487,9 +422,7 @@ int main(int argc, char **argv)
 		}
 	}
 	
-	if (mass_relabel)
-		mass_relabel_errs = errors;
-	maybe_audit_mass_relabel();
+	maybe_audit_mass_relabel(mass_relabel, errors);
 
 	if (warn_no_match)
 		selabel_stats(r_opts.hnd);