71e0cd6
diff --git libsemanage-2.5/ChangeLog libsemanage-2.5/ChangeLog
9a2ed65
index 9b4d5b7..469c4b0 100644
71e0cd6
--- libsemanage-2.5/ChangeLog
71e0cd6
+++ libsemanage-2.5/ChangeLog
9a2ed65
@@ -1,3 +1,20 @@
9a2ed65
+	* Fixes bug preventing the installation of base modules, from James Carter.
9a2ed65
+2.6-rc1 2016-09-30
9a2ed65
+	* make distclean target work, from Nicolas Iooss.
9a2ed65
+	* Do not always print a module name warning, from Miroslav Grepl.
9a2ed65
+	* Use pp module name instead of filename when installing module, from Petr Lautrbach.
9a2ed65
+	* tests: Do not force using gcc, from Nicolas Iooss.
9a2ed65
+	* genhomedircon: remove hardcoded refpolicy strings, from Gary Tierney.
9a2ed65
+	* genhomedircon: add support for %group syntax, from Gary Tierney.
9a2ed65
+	* genhomedircon: generate contexts for logins mapped to the default user, from Gary Tierney.
9a2ed65
+	* Validate and compile file contexts before installing, from Stephen Smalley.
9a2ed65
+	* Swap tcp and udp protocol numbers, from Miroslav Vadkerti.
b007211
+	* Sort object files for deterministic linking order, from Laurent Bigonville.
b007211
+	* Support overriding Makefile RANLIB, from Julien Pivotto.
b007211
+	* Respect CC and PKG_CONFIG environment variable, from Julien Pivotto.
71e0cd6
+	* Fix multiple spelling errors, from Laurent Bigonville.
71e0cd6
+	* genhomedircon: %{USERID} and %{USERNAME} support and code cleanups, from Jason Zaman.
71e0cd6
+
71e0cd6
 2.5 2016-02-23
71e0cd6
 	* Do not overwrite CFLAGS in test Makefile, from Nicolas Iooss.
71e0cd6
 	* Fix uninitialized variable in direct_commit and direct_api, from Nicolas Iooss.
71e0cd6
diff --git libsemanage-2.5/include/semanage/handle.h libsemanage-2.5/include/semanage/handle.h
71e0cd6
index 6cad529..c816590 100644
71e0cd6
--- libsemanage-2.5/include/semanage/handle.h
71e0cd6
+++ libsemanage-2.5/include/semanage/handle.h
71e0cd6
@@ -130,7 +130,7 @@ int semanage_commit(semanage_handle_t *);
71e0cd6
 #define SEMANAGE_CAN_READ 1
71e0cd6
 #define SEMANAGE_CAN_WRITE 2
71e0cd6
 /* returns SEMANAGE_CAN_READ or SEMANAGE_CAN_WRITE if the store is readable
71e0cd6
- * or writable, respectively. <0 if an error occured */
71e0cd6
+ * or writable, respectively. <0 if an error occurred */
71e0cd6
 int semanage_access_check(semanage_handle_t * sh);
71e0cd6
 
71e0cd6
 /* returns 0 if not connected, 1 if connected */
b007211
diff --git libsemanage-2.5/src/Makefile libsemanage-2.5/src/Makefile
9a2ed65
index d1fcc0b..68aab72 100644
b007211
--- libsemanage-2.5/src/Makefile
b007211
+++ libsemanage-2.5/src/Makefile
b007211
@@ -5,6 +5,7 @@ PYTHON ?= python
b007211
 PYPREFIX ?= $(notdir $(PYTHON))
b007211
 RUBY ?= ruby
b007211
 RUBYPREFIX ?= $(notdir $(RUBY))
b007211
+PKG_CONFIG ?= pkg-config
b007211
 
b007211
 # Installation directories.
b007211
 PREFIX ?= $(DESTDIR)/usr
b007211
@@ -12,11 +13,11 @@ LIBDIR ?= $(PREFIX)/lib
b007211
 SHLIBDIR ?= $(DESTDIR)/lib
b007211
 INCLUDEDIR ?= $(PREFIX)/include
b007211
 PYLIBVER ?= $(shell $(PYTHON) -c 'import sys;print("python%d.%d" % sys.version_info[0:2])')
b007211
-PYINC ?= $(shell pkg-config --cflags $(PYPREFIX))
b007211
+PYINC ?= $(shell $(PKG_CONFIG) --cflags $(PYPREFIX))
b007211
 PYLIBDIR ?= $(LIBDIR)/$(PYLIBVER)
b007211
 RUBYLIBVER ?= $(shell $(RUBY) -e 'print RUBY_VERSION.split(".")[0..1].join(".")')
b007211
 RUBYPLATFORM ?= $(shell $(RUBY) -e 'print RUBY_PLATFORM')
b007211
-RUBYINC ?= $(shell pkg-config --cflags ruby-$(RUBYLIBVER))
b007211
+RUBYINC ?= $(shell $(PKG_CONFIG) --cflags ruby-$(RUBYLIBVER))
b007211
 RUBYINSTALL ?= $(LIBDIR)/ruby/site_ruby/$(RUBYLIBVER)/$(RUBYPLATFORM)
b007211
 
b007211
 LIBBASE=$(shell basename $(LIBDIR))
9a2ed65
@@ -50,8 +51,8 @@ SWIGFILES=$(SWIGSO) semanage.py
9a2ed65
 SWIGRUBYSO=$(RUBYPREFIX)_semanage.so
b007211
 LIBSO=$(TARGET).$(LIBVERSION)
b007211
 
9a2ed65
-GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) semanageswig_python_exception.i
b007211
-SRCS= $(filter-out $(GENERATED),$(wildcard *.c))
9a2ed65
+GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) semanageswig_python_exception.i $(wildcard conf-*.[ch])
b007211
+SRCS= $(filter-out $(GENERATED),$(sort $(wildcard *.c)))
b007211
 
b007211
 OBJS= $(patsubst %.c,%.o,$(SRCS)) conf-scan.o conf-parse.o
b007211
 LOBJS= $(patsubst %.c,%.lo,$(SRCS)) conf-scan.lo conf-parse.lo
9a2ed65
@@ -61,14 +62,12 @@ SWIG_CFLAGS += -Wno-error -Wno-unused-but-set-variable -Wno-unused-variable -Wno
b007211
 		-Wno-unused-parameter
b007211
 
b007211
 override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE 
b007211
-RANLIB=ranlib
b007211
+RANLIB ?= ranlib
b007211
 
b007211
 SWIG = swig -Wall -python -o $(SWIGCOUT) -outdir ./
b007211
 
9a2ed65
 SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./
9a2ed65
 
9a2ed65
-GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) $(wildcard conf-*.[ch])
9a2ed65
-
9a2ed65
 all: $(LIBA) $(LIBSO) $(LIBPC)
9a2ed65
 
9a2ed65
 pywrap: all $(SWIGSO)
9a2ed65
@@ -162,7 +161,7 @@ clean:
9a2ed65
 	-rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(SWIGLOBJ) $(SWIGSO) $(TARGET) conf-parse.c conf-parse.h conf-scan.c *.o *.lo *~
9a2ed65
 
9a2ed65
 distclean: clean
9a2ed65
-	rm -f $(SWIGCOUT) $(SWIGFILES)
9a2ed65
+	rm -f $(GENERATED) $(SWIGFILES)
9a2ed65
 
9a2ed65
 indent:
9a2ed65
 	../../scripts/Lindent $(filter-out $(GENERATED),$(wildcard *.[ch]))
71e0cd6
diff --git libsemanage-2.5/src/database.h libsemanage-2.5/src/database.h
71e0cd6
index e460379..6a4a164 100644
71e0cd6
--- libsemanage-2.5/src/database.h
71e0cd6
+++ libsemanage-2.5/src/database.h
71e0cd6
@@ -148,7 +148,7 @@ typedef struct dbase_table {
71e0cd6
 	 * This function must be invoked before using
71e0cd6
 	 * any of the database functions above. It may be invoked
71e0cd6
 	 * multiple times, and will update the cache if a commit
71e0cd6
-	 * occured between invocations */
71e0cd6
+	 * occurred between invocations */
71e0cd6
 	int (*cache) (struct semanage_handle * handle, dbase_t * dbase);
71e0cd6
 
71e0cd6
 	/* Forgets all changes that haven't been written
9a2ed65
diff --git libsemanage-2.5/src/direct_api.c libsemanage-2.5/src/direct_api.c
5012c31
index 2187b65..8bfbe5c 100644
9a2ed65
--- libsemanage-2.5/src/direct_api.c
9a2ed65
+++ libsemanage-2.5/src/direct_api.c
9a2ed65
@@ -363,6 +363,35 @@ static int semanage_direct_begintrans(semanage_handle_t * sh)
9a2ed65
 
9a2ed65
 /********************* utility functions *********************/
9a2ed65
 
9a2ed65
+/* Takes a module stored in 'module_data' and parses its headers.
9a2ed65
+ * Sets reference variables 'module_name' to module's name, and
9a2ed65
+ * 'version' to module's version.  The caller is responsible for
9a2ed65
+ * free()ing 'module_name', and 'version'; they will be
9a2ed65
+ * set to NULL upon entering this function.  Returns 0 on success, -1
9a2ed65
+ * if out of memory.
9a2ed65
+ */
9a2ed65
+static int parse_module_headers(semanage_handle_t * sh, char *module_data,
9a2ed65
+                               size_t data_len, char **module_name,
9a2ed65
+                               char **version)
9a2ed65
+{
9a2ed65
+       struct sepol_policy_file *pf;
9a2ed65
+       int file_type;
9a2ed65
+       *module_name = *version = NULL;
9a2ed65
+
9a2ed65
+       if (sepol_policy_file_create(&pf)) {
9a2ed65
+               ERR(sh, "Out of memory!");
9a2ed65
+               return -1;
9a2ed65
+       }
9a2ed65
+       sepol_policy_file_set_mem(pf, module_data, data_len);
9a2ed65
+       sepol_policy_file_set_handle(pf, sh->sepolh);
9a2ed65
+       if (module_data != NULL && data_len > 0)
9a2ed65
+           sepol_module_package_info(pf, &file_type, module_name,
9a2ed65
+                                     version);
9a2ed65
+       sepol_policy_file_free(pf);
9a2ed65
+
9a2ed65
+       return 0;
9a2ed65
+}
9a2ed65
+
9a2ed65
 #include <stdlib.h>
9a2ed65
 #include <bzlib.h>
9a2ed65
 #include <string.h>
5012c31
@@ -588,13 +617,33 @@ static int semanage_direct_update_user_extra(semanage_handle_t * sh, cil_db_t *c
5012c31
 	}
5012c31
 
5012c31
 	if (size > 0) {
5012c31
+		/*
5012c31
+		 * Write the users_extra entries from CIL modules.
5012c31
+		 * This file is used as our baseline when we do not require
5012c31
+		 * re-linking.
5012c31
+		 */
5012c31
+		ofilename = semanage_path(SEMANAGE_TMP,
5012c31
+					  SEMANAGE_USERS_EXTRA_LINKED);
5012c31
+		if (ofilename == NULL) {
5012c31
+			retval = -1;
5012c31
+			goto cleanup;
5012c31
+		}
5012c31
+		retval = write_file(sh, ofilename, data, size);
5012c31
+		if (retval < 0)
5012c31
+			goto cleanup;
5012c31
+
5012c31
+		/*
5012c31
+		 * Write the users_extra file; users_extra.local
5012c31
+		 * will be merged into this file.
5012c31
+		 */
5012c31
 		ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA);
5012c31
 		if (ofilename == NULL) {
5012c31
-			return retval;
5012c31
+			retval = -1;
5012c31
+			goto cleanup;
5012c31
 		}
5012c31
 		retval = write_file(sh, ofilename, data, size);
5012c31
 		if (retval < 0)
5012c31
-			return retval;
5012c31
+			goto cleanup;
5012c31
 
5012c31
 		pusers_extra->dtable->drop_cache(pusers_extra->dbase);
5012c31
 		
5012c31
@@ -623,11 +672,33 @@ static int semanage_direct_update_seuser(semanage_handle_t * sh, cil_db_t *cildb
5012c31
 	}
5012c31
 
5012c31
 	if (size > 0) {
5012c31
+		/*
5012c31
+		 * Write the seusers entries from CIL modules.
5012c31
+		 * This file is used as our baseline when we do not require
5012c31
+		 * re-linking.
5012c31
+		 */
5012c31
+		ofilename = semanage_path(SEMANAGE_TMP,
5012c31
+					  SEMANAGE_SEUSERS_LINKED);
5012c31
+		if (ofilename == NULL) {
5012c31
+			retval = -1;
5012c31
+			goto cleanup;
5012c31
+		}
5012c31
+		retval = write_file(sh, ofilename, data, size);
5012c31
+		if (retval < 0)
5012c31
+			goto cleanup;
5012c31
+
5012c31
+		/*
5012c31
+		 * Write the seusers file; seusers.local will be merged into
5012c31
+		 * this file.
5012c31
+		 */
5012c31
 		ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS);
5012c31
 		if (ofilename == NULL) {
5012c31
-			return -1;
5012c31
+			retval = -1;
5012c31
+			goto cleanup;
5012c31
 		}
5012c31
 		retval = write_file(sh, ofilename, data, size);
5012c31
+		if (retval < 0)
5012c31
+			goto cleanup;
5012c31
 
5012c31
 		pseusers->dtable->drop_cache(pseusers->dbase);
5012c31
 	} else {
5012c31
@@ -1066,21 +1137,18 @@ static int semanage_direct_commit(semanage_handle_t * sh)
5012c31
 	size_t fc_buffer_len = 0;
5012c31
 	const char *ofilename = NULL;
5012c31
 	const char *path;
5012c31
-	int retval = -1, num_modinfos = 0, i, missing_policy_kern = 0,
5012c31
-		missing_seusers = 0, missing_fc = 0, missing = 0;
5012c31
+	int retval = -1, num_modinfos = 0, i;
5012c31
 	sepol_policydb_t *out = NULL;
5012c31
 	struct cil_db *cildb = NULL;
5012c31
 	semanage_module_info_t *modinfos = NULL;
5012c31
 
5012c31
-	/* Declare some variables */
5012c31
-	int modified = 0, fcontexts_modified, ports_modified,
5012c31
-	    seusers_modified, users_extra_modified, dontaudit_modified,
5012c31
-	    preserve_tunables_modified, bools_modified = 0,
5012c31
+	int do_rebuild, do_write_kernel, do_install;
5012c31
+	int fcontexts_modified, ports_modified, seusers_modified,
5012c31
 		disable_dontaudit, preserve_tunables;
5012c31
 	dbase_config_t *users = semanage_user_dbase_local(sh);
5012c31
 	dbase_config_t *users_base = semanage_user_base_dbase_local(sh);
5012c31
 	dbase_config_t *pusers_base = semanage_user_base_dbase_policy(sh);
5012c31
-	dbase_config_t *users_extra = semanage_user_extra_dbase_local(sh);
5012c31
+	dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh);
5012c31
 	dbase_config_t *ports = semanage_port_dbase_local(sh);
5012c31
 	dbase_config_t *pports = semanage_port_dbase_policy(sh);
5012c31
 	dbase_config_t *bools = semanage_bool_dbase_local(sh);
5012c31
@@ -1092,13 +1160,22 @@ static int semanage_direct_commit(semanage_handle_t * sh)
5012c31
 	dbase_config_t *fcontexts = semanage_fcontext_dbase_local(sh);
5012c31
 	dbase_config_t *pfcontexts = semanage_fcontext_dbase_policy(sh);
5012c31
 	dbase_config_t *seusers = semanage_seuser_dbase_local(sh);
5012c31
+	dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh);
5012c31
+
5012c31
+	/* Modified flags that we need to use more than once. */
5012c31
+	ports_modified = ports->dtable->is_modified(ports->dbase);
5012c31
+	seusers_modified = seusers->dtable->is_modified(seusers->dbase);
5012c31
+	fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
5012c31
+
5012c31
+	/* Rebuild if explicitly requested or any module changes occurred. */
5012c31
+	do_rebuild = sh->do_rebuild | sh->modules_modified;
5012c31
 
5012c31
 	/* Create or remove the disable_dontaudit flag file. */
5012c31
 	path = semanage_path(SEMANAGE_TMP, SEMANAGE_DISABLE_DONTAUDIT);
5012c31
 	if (access(path, F_OK) == 0)
5012c31
-		dontaudit_modified = !(sepol_get_disable_dontaudit(sh->sepolh) == 1);
5012c31
+		do_rebuild |= !(sepol_get_disable_dontaudit(sh->sepolh) == 1);
5012c31
 	else
5012c31
-		dontaudit_modified = (sepol_get_disable_dontaudit(sh->sepolh) == 1);
5012c31
+		do_rebuild |= (sepol_get_disable_dontaudit(sh->sepolh) == 1);
5012c31
 	if (sepol_get_disable_dontaudit(sh->sepolh) == 1) {
5012c31
 		FILE *touch;
5012c31
 		touch = fopen(path, "w");
5012c31
@@ -1121,9 +1198,9 @@ static int semanage_direct_commit(semanage_handle_t * sh)
5012c31
 	/* Create or remove the preserve_tunables flag file. */
5012c31
 	path = semanage_path(SEMANAGE_TMP, SEMANAGE_PRESERVE_TUNABLES);
5012c31
 	if (access(path, F_OK) == 0)
5012c31
-		preserve_tunables_modified = !(sepol_get_preserve_tunables(sh->sepolh) == 1);
5012c31
+		do_rebuild |= !(sepol_get_preserve_tunables(sh->sepolh) == 1);
5012c31
 	else
5012c31
-		preserve_tunables_modified = (sepol_get_preserve_tunables(sh->sepolh) == 1);
5012c31
+		do_rebuild |= (sepol_get_preserve_tunables(sh->sepolh) == 1);
5012c31
 	if (sepol_get_preserve_tunables(sh->sepolh) == 1) {
5012c31
 		FILE *touch;
5012c31
 		touch = fopen(path, "w");
5012c31
@@ -1151,54 +1228,75 @@ static int semanage_direct_commit(semanage_handle_t * sh)
5012c31
 			goto cleanup;
5012c31
 	}
5012c31
 
5012c31
-	/* Decide if anything was modified */
5012c31
-	fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
5012c31
-	seusers_modified = seusers->dtable->is_modified(seusers->dbase);
5012c31
-	users_extra_modified =
5012c31
-	    users_extra->dtable->is_modified(users_extra->dbase);
5012c31
-	ports_modified = ports->dtable->is_modified(ports->dbase);
5012c31
-	bools_modified = bools->dtable->is_modified(bools->dbase);
5012c31
-
5012c31
-	modified = sh->modules_modified;
5012c31
-	modified |= seusers_modified;
5012c31
-	modified |= users_extra_modified;
5012c31
-	modified |= ports_modified;
5012c31
-	modified |= users->dtable->is_modified(users_base->dbase);
5012c31
-	modified |= ifaces->dtable->is_modified(ifaces->dbase);
5012c31
-	modified |= nodes->dtable->is_modified(nodes->dbase);
5012c31
-	modified |= dontaudit_modified;
5012c31
-	modified |= preserve_tunables_modified;
5012c31
-
5012c31
-	/* This is for systems that have already migrated with an older version
5012c31
-	 * of semanage_migrate_store. The older version did not copy policy.kern so
5012c31
-	 * the policy binary must be rebuilt here.
5012c31
+	/*
5012c31
+	 * This is for systems that have already migrated with an older version
5012c31
+	 * of semanage_migrate_store. The older version did not copy
5012c31
+	 * policy.kern so the policy binary must be rebuilt here.
5012c31
+	 * This also ensures that any linked files that are required
5012c31
+	 * in order to skip re-linking are present; otherwise, we force
5012c31
+	 * a rebuild.
5012c31
 	 */
5012c31
-	if (!sh->do_rebuild && !modified) {
5012c31
+	if (!do_rebuild) {
5012c31
 		path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL);
5012c31
-
5012c31
 		if (access(path, F_OK) != 0) {
5012c31
-			missing_policy_kern = 1;
5012c31
+			do_rebuild = 1;
5012c31
+			goto rebuild;
5012c31
 		}
5012c31
 
5012c31
 		path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC);
5012c31
-
5012c31
 		if (access(path, F_OK) != 0) {
5012c31
-			missing_fc = 1;
5012c31
+			do_rebuild = 1;
5012c31
+			goto rebuild;
5012c31
 		}
5012c31
 
5012c31
 		path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS);
5012c31
+		if (access(path, F_OK) != 0) {
5012c31
+			do_rebuild = 1;
5012c31
+			goto rebuild;
5012c31
+		}
5012c31
 
5012c31
+		path = semanage_path(SEMANAGE_TMP, SEMANAGE_LINKED);
5012c31
 		if (access(path, F_OK) != 0) {
5012c31
-			missing_seusers = 1;
5012c31
+			do_rebuild = 1;
5012c31
+			goto rebuild;
5012c31
 		}
5012c31
-	}
5012c31
 
5012c31
-	missing |= missing_policy_kern;
5012c31
-	missing |= missing_fc;
5012c31
-	missing |= missing_seusers;
5012c31
+		path = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS_LINKED);
5012c31
+		if (access(path, F_OK) != 0) {
5012c31
+			do_rebuild = 1;
5012c31
+			goto rebuild;
5012c31
+		}
5012c31
 
5012c31
-	/* If there were policy changes, or explicitly requested, rebuild the policy */
5012c31
-	if (sh->do_rebuild || modified || missing) {
5012c31
+		path = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA_LINKED);
5012c31
+		if (access(path, F_OK) != 0) {
5012c31
+			do_rebuild = 1;
5012c31
+			goto rebuild;
5012c31
+		}
5012c31
+	}
5012c31
+
5012c31
+rebuild:
5012c31
+	/*
5012c31
+	 * Now that we know whether or not a rebuild is required,
5012c31
+	 * we can determine what else needs to be done.
5012c31
+	 * We need to write the kernel policy if we are rebuilding
5012c31
+	 * or if any other policy component that lives in the kernel
5012c31
+	 * policy has been modified.
5012c31
+	 * We need to install the policy files if any of the managed files
5012c31
+	 * that live under /etc/selinux (kernel policy, seusers, file contexts)
5012c31
+	 * will be modified.
5012c31
+	 */
5012c31
+	do_write_kernel = do_rebuild | ports_modified |
5012c31
+		bools->dtable->is_modified(bools->dbase) |
5012c31
+		ifaces->dtable->is_modified(ifaces->dbase) |
5012c31
+		nodes->dtable->is_modified(nodes->dbase) |
5012c31
+		users->dtable->is_modified(users_base->dbase);
5012c31
+	do_install = do_write_kernel | seusers_modified | fcontexts_modified;
5012c31
+
5012c31
+	/*
5012c31
+	 * If there were policy changes, or explicitly requested, or
5012c31
+	 * any required files are missing, rebuild the policy.
5012c31
+	 */
5012c31
+	if (do_rebuild) {
5012c31
 		/* =================== Module expansion =============== */
5012c31
 
5012c31
 		retval = semanage_get_active_modules(sh, &modinfos, &num_modinfos);
5012c31
@@ -1287,43 +1385,72 @@ static int semanage_direct_commit(semanage_handle_t * sh)
5012c31
 			goto cleanup;
5012c31
 
5012c31
 		cil_db_destroy(&cildb);
5012c31
-	
5012c31
+
5012c31
+		/* Write the linked policy before merging local changes. */
5012c31
+		retval = semanage_write_policydb(sh, out,
5012c31
+						 SEMANAGE_LINKED);
5012c31
+		if (retval < 0)
5012c31
+			goto cleanup;
5012c31
 	} else {
5012c31
-		/* Load already linked policy */
5012c31
+		/* Load the existing linked policy, w/o local changes */
5012c31
 		retval = sepol_policydb_create(&out;;
5012c31
 		if (retval < 0)
5012c31
 			goto cleanup;
5012c31
 
5012c31
-		retval = semanage_read_policydb(sh, out);
5012c31
+		retval = semanage_read_policydb(sh, out, SEMANAGE_LINKED);
5012c31
 		if (retval < 0)
5012c31
 			goto cleanup;
5012c31
-	}
5012c31
 
5012c31
-	if (sh->do_rebuild || modified || bools_modified) {
5012c31
-		/* Attach to policy databases that work with a policydb. */
5012c31
-		dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out);
5012c31
-		dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
5012c31
-		dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out);
5012c31
-		dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out);
5012c31
-		dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out);
5012c31
+		path = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS_LINKED);
5012c31
+		if (access(path, F_OK) == 0) {
5012c31
+			retval = semanage_copy_file(path,
5012c31
+						    semanage_path(SEMANAGE_TMP,
5012c31
+								  SEMANAGE_STORE_SEUSERS),
5012c31
+						    sh->conf->file_mode);
5012c31
+			if (retval < 0)
5012c31
+				goto cleanup;
5012c31
+			pseusers->dtable->drop_cache(pseusers->dbase);
5012c31
+		} else {
5012c31
+			pseusers->dtable->clear(sh, pseusers->dbase);
5012c31
+		}
5012c31
 
5012c31
-		/* ============= Apply changes, and verify  =============== */
5012c31
+		path = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA_LINKED);
5012c31
+		if (access(path, F_OK) == 0) {
5012c31
+			retval = semanage_copy_file(path,
5012c31
+						    semanage_path(SEMANAGE_TMP,
5012c31
+								  SEMANAGE_USERS_EXTRA),
5012c31
+						    sh->conf->file_mode);
5012c31
+			if (retval < 0)
5012c31
+				goto cleanup;
5012c31
+			pusers_extra->dtable->drop_cache(pusers_extra->dbase);
5012c31
+		} else {
5012c31
+			pusers_extra->dtable->clear(sh, pusers_extra->dbase);
5012c31
+		}
5012c31
+	}
5012c31
 
5012c31
-		retval = semanage_base_merge_components(sh);
5012c31
-		if (retval < 0)
5012c31
-			goto cleanup;
5012c31
+	/* Attach our databases to the policydb we just created or loaded. */
5012c31
+	dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out);
5012c31
+	dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
5012c31
+	dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out);
5012c31
+	dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out);
5012c31
+	dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out);
5012c31
+
5012c31
+	/* Merge local changes */
5012c31
+	retval = semanage_base_merge_components(sh);
5012c31
+	if (retval < 0)
5012c31
+		goto cleanup;
5012c31
 
5012c31
-		retval = semanage_write_policydb(sh, out);
5012c31
+	if (do_write_kernel) {
5012c31
+		/* Write new kernel policy. */
5012c31
+		retval = semanage_write_policydb(sh, out,
5012c31
+						 SEMANAGE_STORE_KERNEL);
5012c31
 		if (retval < 0)
5012c31
 			goto cleanup;
5012c31
 
5012c31
+		/* Run the kernel policy verifier, if any. */
5012c31
 		retval = semanage_verify_kernel(sh);
5012c31
 		if (retval < 0)
5012c31
 			goto cleanup;
5012c31
-	} else {
5012c31
-		retval = semanage_base_merge_components(sh);
5012c31
-		if (retval < 0)
5012c31
-			goto cleanup;
5012c31
 	}
5012c31
 
5012c31
 	/* ======= Post-process: Validate non-policydb components ===== */
5012c31
@@ -1332,21 +1459,21 @@ static int semanage_direct_commit(semanage_handle_t * sh)
5012c31
 	 * Note: those are still cached, even though they've been 
5012c31
 	 * merged into the main file_contexts. We won't check the 
5012c31
 	 * large file_contexts - checked at compile time */
5012c31
-	if (sh->do_rebuild || modified || fcontexts_modified) {
5012c31
+	if (do_rebuild || fcontexts_modified) {
5012c31
 		retval = semanage_fcontext_validate_local(sh, out);
5012c31
 		if (retval < 0)
5012c31
 			goto cleanup;
5012c31
 	}
5012c31
 
5012c31
 	/* Validate local seusers against policy */
5012c31
-	if (sh->do_rebuild || modified || seusers_modified) {
5012c31
+	if (do_rebuild || seusers_modified) {
5012c31
 		retval = semanage_seuser_validate_local(sh, out);
5012c31
 		if (retval < 0)
5012c31
 			goto cleanup;
5012c31
 	}
5012c31
 
5012c31
 	/* Validate local ports for overlap */
5012c31
-	if (sh->do_rebuild || modified || ports_modified) {
5012c31
+	if (do_rebuild || ports_modified) {
5012c31
 		retval = semanage_port_validate_local(sh);
5012c31
 		if (retval < 0)
5012c31
 			goto cleanup;
5012c31
@@ -1415,9 +1542,8 @@ static int semanage_direct_commit(semanage_handle_t * sh)
5012c31
 	sepol_policydb_free(out);
5012c31
 	out = NULL;
5012c31
 
5012c31
-	if (sh->do_rebuild || modified || bools_modified || fcontexts_modified) {
5012c31
+	if (do_install)
5012c31
 		retval = semanage_install_sandbox(sh);
5012c31
-	}
5012c31
 
5012c31
 cleanup:
5012c31
 	for (i = 0; i < num_modinfos; i++) {
5012c31
@@ -1429,14 +1555,12 @@ cleanup:
5012c31
 		free(mod_filenames[i]);
5012c31
 	}
5012c31
 
5012c31
-	if (modified || bools_modified) {
5012c31
-		/* Detach from policydb, so it can be freed */
5012c31
-		dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase);
5012c31
-		dbase_policydb_detach((dbase_policydb_t *) pports->dbase);
5012c31
-		dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase);
5012c31
-		dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase);
5012c31
-		dbase_policydb_detach((dbase_policydb_t *) pbools->dbase);
5012c31
-	}
5012c31
+	/* Detach from policydb, so it can be freed */
5012c31
+	dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase);
5012c31
+	dbase_policydb_detach((dbase_policydb_t *) pports->dbase);
5012c31
+	dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase);
5012c31
+	dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase);
5012c31
+	dbase_policydb_detach((dbase_policydb_t *) pbools->dbase);
5012c31
 
5012c31
 	free(mod_filenames);
5012c31
 	sepol_policydb_free(out);
5012c31
@@ -1524,7 +1648,9 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
9a2ed65
 	char *path = NULL;
9a2ed65
 	char *filename;
9a2ed65
 	char *lang_ext = NULL;
9a2ed65
+	char *module_name = NULL;
9a2ed65
 	char *separator;
9a2ed65
+	char *version = NULL;
9a2ed65
 
9a2ed65
 	if ((data_len = map_file(sh, install_filename, &data, &compressed)) <= 0) {
9a2ed65
 		ERR(sh, "Unable to read file %s\n", install_filename);
5012c31
@@ -1564,10 +1690,29 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
9a2ed65
 		lang_ext = separator + 1;
9a2ed65
 	}
9a2ed65
 
9a2ed65
-	retval = semanage_direct_install(sh, data, data_len, filename, lang_ext);
9a2ed65
+	if (strcmp(lang_ext, "pp") == 0) {
9a2ed65
+		retval = parse_module_headers(sh, data, data_len, &module_name, &version);
9a2ed65
+		free(version);
9a2ed65
+		if (retval != 0)
9a2ed65
+			goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	if (module_name == NULL) {
9a2ed65
+		module_name = strdup(filename);
9a2ed65
+		if (module_name == NULL) {
9a2ed65
+			ERR(sh, "No memory available for module_name.\n");
9a2ed65
+			retval = -1;
9a2ed65
+			goto cleanup;
9a2ed65
+		}
9a2ed65
+	} else if (strcmp(module_name, filename) != 0) {
9a2ed65
+		fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename);
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	retval = semanage_direct_install(sh, data, data_len, module_name, lang_ext);
9a2ed65
 
9a2ed65
 cleanup:
9a2ed65
 	if (data_len > 0) munmap(data, data_len);
9a2ed65
+	free(module_name);
9a2ed65
 	free(path);
9a2ed65
 
9a2ed65
 	return retval;
5012c31
@@ -1931,7 +2076,7 @@ int semanage_direct_mls_enabled(semanage_handle_t * sh)
5012c31
 	if (retval < 0)
5012c31
 		goto cleanup;
5012c31
 
5012c31
-	retval = semanage_read_policydb(sh, p);
5012c31
+	retval = semanage_read_policydb(sh, p, SEMANAGE_STORE_KERNEL);
5012c31
 	if (retval < 0)
5012c31
 		goto cleanup;
5012c31
 
b007211
diff --git libsemanage-2.5/src/exception.sh libsemanage-2.5/src/exception.sh
b007211
index 94619d2..d18959c 100644
b007211
--- libsemanage-2.5/src/exception.sh
b007211
+++ libsemanage-2.5/src/exception.sh
b007211
@@ -9,6 +9,6 @@ echo "
b007211
 }
b007211
 "
b007211
 }
b007211
-gcc -x c -c -I../include - -aux-info temp.aux < ../include/semanage/semanage.h
b007211
+${CC:-gcc} -x c -c -I../include - -aux-info temp.aux < ../include/semanage/semanage.h
b007211
 for i in `awk '/extern int/ { print $6 }' temp.aux`; do except $i ; done
b007211
 rm -f -- temp.aux -.o
71e0cd6
diff --git libsemanage-2.5/src/genhomedircon.c libsemanage-2.5/src/genhomedircon.c
9a2ed65
index 1a9e87e..3fc9e7a 100644
71e0cd6
--- libsemanage-2.5/src/genhomedircon.c
71e0cd6
+++ libsemanage-2.5/src/genhomedircon.c
9a2ed65
@@ -48,6 +48,8 @@
9a2ed65
 #include <errno.h>
9a2ed65
 #include <unistd.h>
9a2ed65
 #include <regex.h>
9a2ed65
+#include <grp.h>
9a2ed65
+#include <search.h>
9a2ed65
 
9a2ed65
 /* paths used in get_home_dirs() */
9a2ed65
 #define PATH_ETC_USERADD "/etc/default/useradd"
9a2ed65
@@ -73,37 +75,44 @@
71e0cd6
    which are searched for and replaced */
71e0cd6
 #define TEMPLATE_HOME_ROOT "HOME_ROOT"
71e0cd6
 #define TEMPLATE_HOME_DIR "HOME_DIR"
71e0cd6
+/* these are legacy */
71e0cd6
 #define TEMPLATE_USER "USER"
71e0cd6
 #define TEMPLATE_ROLE "ROLE"
9a2ed65
-#define TEMPLATE_SEUSER "system_u"
9a2ed65
-#define TEMPLATE_LEVEL "s0"
9a2ed65
-
9a2ed65
-#define FALLBACK_USER "user_u"
9a2ed65
-#define FALLBACK_USER_PREFIX "user"
9a2ed65
-#define FALLBACK_USER_LEVEL "s0"
71e0cd6
+/* new names */
71e0cd6
+#define TEMPLATE_USERNAME "%{USERNAME}"
71e0cd6
+#define TEMPLATE_USERID "%{USERID}"
71e0cd6
+
71e0cd6
+#define FALLBACK_SENAME "user_u"
71e0cd6
+#define FALLBACK_PREFIX "user"
71e0cd6
+#define FALLBACK_LEVEL "s0"
71e0cd6
+#define FALLBACK_NAME "[^/]+"
71e0cd6
+#define FALLBACK_UIDGID "[0-9]+"
71e0cd6
 #define DEFAULT_LOGIN "__default__"
71e0cd6
 
71e0cd6
-typedef struct {
71e0cd6
-	const char *fcfilepath;
71e0cd6
-	int usepasswd;
71e0cd6
-	const char *homedir_template_path;
71e0cd6
-	char *fallback_user;
71e0cd6
-	char *fallback_user_prefix;
71e0cd6
-	char *fallback_user_level;
71e0cd6
-	semanage_handle_t *h_semanage;
71e0cd6
-	sepol_policydb_t *policydb;
71e0cd6
-} genhomedircon_settings_t;
9a2ed65
+#define CONTEXT_NONE "<<none>>"
9a2ed65
 
71e0cd6
 typedef struct user_entry {
71e0cd6
 	char *name;
71e0cd6
+	char *uid;
71e0cd6
+	char *gid;
71e0cd6
 	char *sename;
71e0cd6
 	char *prefix;
71e0cd6
 	char *home;
9a2ed65
 	char *level;
9a2ed65
+	char *login;
9a2ed65
 	struct user_entry *next;
71e0cd6
 } genhomedircon_user_entry_t;
71e0cd6
 
71e0cd6
 typedef struct {
71e0cd6
+	const char *fcfilepath;
71e0cd6
+	int usepasswd;
71e0cd6
+	const char *homedir_template_path;
71e0cd6
+	genhomedircon_user_entry_t *fallback;
71e0cd6
+	semanage_handle_t *h_semanage;
71e0cd6
+	sepol_policydb_t *policydb;
71e0cd6
+} genhomedircon_settings_t;
71e0cd6
+
71e0cd6
+typedef struct {
71e0cd6
 	const char *search_for;
71e0cd6
 	const char *replace_with;
71e0cd6
 } replacement_pair_t;
9a2ed65
@@ -461,11 +470,29 @@ static int HOME_DIR_PRED(const char *string)
71e0cd6
 	return semanage_is_prefix(string, TEMPLATE_HOME_DIR);
71e0cd6
 }
71e0cd6
 
71e0cd6
+/* new names */
71e0cd6
+static int USERNAME_CONTEXT_PRED(const char *string)
71e0cd6
+{
71e0cd6
+	return (int)(
71e0cd6
+		(strstr(string, TEMPLATE_USERNAME) != NULL) ||
71e0cd6
+		(strstr(string, TEMPLATE_USERID) != NULL)
71e0cd6
+	);
71e0cd6
+}
71e0cd6
+
71e0cd6
+/* This will never match USER if USERNAME or USERID are found. */
71e0cd6
 static int USER_CONTEXT_PRED(const char *string)
71e0cd6
 {
71e0cd6
+	if (USERNAME_CONTEXT_PRED(string))
71e0cd6
+		return 0;
71e0cd6
+
71e0cd6
 	return (int)(strstr(string, TEMPLATE_USER) != NULL);
71e0cd6
 }
71e0cd6
 
9a2ed65
+static int STR_COMPARATOR(const void *a, const void *b)
9a2ed65
+{
9a2ed65
+	return strcmp((const char *) a, (const char *) b);
9a2ed65
+}
9a2ed65
+
9a2ed65
 /* make_tempate
9a2ed65
  * @param	s	  the settings holding the paths to various files
9a2ed65
  * @param	pred	function pointer to function to use as filter for slurp
9a2ed65
@@ -548,23 +575,12 @@ static int check_line(genhomedircon_settings_t * s, Ustr *line)
71e0cd6
 	return result;
71e0cd6
 }
71e0cd6
 
71e0cd6
-static int write_home_dir_context(genhomedircon_settings_t * s, FILE * out,
71e0cd6
-				  semanage_list_t * tpl, const char *user,
71e0cd6
-				  const char *seuser, const char *home,
71e0cd6
-				  const char *role_prefix, const char *level)
71e0cd6
+static int write_replacements(genhomedircon_settings_t * s, FILE * out,
71e0cd6
+			      const semanage_list_t * tpl,
71e0cd6
+			      const replacement_pair_t *repl)
71e0cd6
 {
71e0cd6
-	replacement_pair_t repl[] = {
71e0cd6
-		{.search_for = TEMPLATE_SEUSER,.replace_with = seuser},
71e0cd6
-		{.search_for = TEMPLATE_HOME_DIR,.replace_with = home},
71e0cd6
-		{.search_for = TEMPLATE_ROLE,.replace_with = role_prefix},
71e0cd6
-		{.search_for = TEMPLATE_LEVEL,.replace_with = level},
71e0cd6
-		{NULL, NULL}
71e0cd6
-	};
71e0cd6
 	Ustr *line = USTR_NULL;
71e0cd6
 
71e0cd6
-	if (fprintf(out, COMMENT_USER_HOME_CONTEXT, user) < 0)
71e0cd6
-		return STATUS_ERR;
71e0cd6
-
71e0cd6
 	for (; tpl; tpl = tpl->next) {
71e0cd6
 		line = replace_all(tpl->data, repl);
71e0cd6
 		if (!line)
9a2ed65
@@ -582,59 +598,148 @@ static int write_home_dir_context(genhomedircon_settings_t * s, FILE * out,
9a2ed65
 	return STATUS_ERR;
9a2ed65
 }
9a2ed65
 
9a2ed65
-static int write_home_root_context(genhomedircon_settings_t * s, FILE * out,
9a2ed65
-				   semanage_list_t * tpl, char *homedir)
9a2ed65
+static int write_contexts(genhomedircon_settings_t *s, FILE *out,
9a2ed65
+			  semanage_list_t *tpl, const replacement_pair_t *repl,
9a2ed65
+			  const genhomedircon_user_entry_t *user)
9a2ed65
 {
9a2ed65
-	replacement_pair_t repl[] = {
9a2ed65
-		{.search_for = TEMPLATE_HOME_ROOT,.replace_with = homedir},
9a2ed65
-		{NULL, NULL}
9a2ed65
-	};
9a2ed65
 	Ustr *line = USTR_NULL;
9a2ed65
+	sepol_context_t *context = NULL;
9a2ed65
+	char *new_context_str = NULL;
9a2ed65
 
9a2ed65
 	for (; tpl; tpl = tpl->next) {
9a2ed65
 		line = replace_all(tpl->data, repl);
9a2ed65
-		if (!line)
9a2ed65
+		if (!line) {
9a2ed65
+			goto fail;
9a2ed65
+		}
9a2ed65
+
9a2ed65
+		const char *old_context_str = extract_context(line);
9a2ed65
+		if (!old_context_str) {
9a2ed65
+			goto fail;
9a2ed65
+		}
9a2ed65
+
9a2ed65
+		if (strcmp(old_context_str, CONTEXT_NONE) == 0) {
9a2ed65
+			if (check_line(s, line) == STATUS_SUCCESS &&
9a2ed65
+			    !ustr_io_putfileline(&line, out)) {
9a2ed65
+				goto fail;
9a2ed65
+			}
9a2ed65
+
9a2ed65
+			continue;
9a2ed65
+		}
9a2ed65
+
9a2ed65
+		sepol_handle_t *sepolh = s->h_semanage->sepolh;
9a2ed65
+
9a2ed65
+		if (sepol_context_from_string(sepolh, old_context_str,
9a2ed65
+					      &context) < 0) {
9a2ed65
 			goto fail;
9a2ed65
+		}
9a2ed65
+
9a2ed65
+		if (sepol_context_set_user(sepolh, context, user->sename) < 0 ||
9a2ed65
+		    sepol_context_set_mls(sepolh, context, user->level) < 0) {
9a2ed65
+			goto fail;
9a2ed65
+		}
9a2ed65
+
9a2ed65
+		if (sepol_context_to_string(sepolh, context,
9a2ed65
+					    &new_context_str) < 0) {
9a2ed65
+			goto fail;
9a2ed65
+		}
9a2ed65
+
9a2ed65
+		if (!ustr_replace_cstr(&line, old_context_str,
9a2ed65
+				       new_context_str, 1)) {
9a2ed65
+			goto fail;
9a2ed65
+		}
9a2ed65
+
9a2ed65
 		if (check_line(s, line) == STATUS_SUCCESS) {
9a2ed65
-			if (!ustr_io_putfileline(&line, out))
9a2ed65
+			if (!ustr_io_putfileline(&line, out)) {
9a2ed65
 				goto fail;
9a2ed65
+			}
9a2ed65
 		}
9a2ed65
+
9a2ed65
 		ustr_sc_free(&line);
9a2ed65
+		sepol_context_free(context);
9a2ed65
+		free(new_context_str);
9a2ed65
 	}
9a2ed65
-	return STATUS_SUCCESS;
9a2ed65
 
9a2ed65
-      fail:
9a2ed65
+	return STATUS_SUCCESS;
9a2ed65
+fail:
9a2ed65
 	ustr_sc_free(&line);
9a2ed65
+	sepol_context_free(context);
9a2ed65
+	free(new_context_str);
71e0cd6
 	return STATUS_ERR;
71e0cd6
 }
71e0cd6
 
71e0cd6
+static int write_home_dir_context(genhomedircon_settings_t * s, FILE * out,
71e0cd6
+				  semanage_list_t * tpl, const genhomedircon_user_entry_t *user)
71e0cd6
+{
71e0cd6
+	replacement_pair_t repl[] = {
71e0cd6
+		{.search_for = TEMPLATE_HOME_DIR,.replace_with = user->home},
71e0cd6
+		{.search_for = TEMPLATE_ROLE,.replace_with = user->prefix},
71e0cd6
+		{NULL, NULL}
71e0cd6
+	};
71e0cd6
+
71e0cd6
+	if (strcmp(user->name, FALLBACK_NAME) == 0) {
71e0cd6
+		if (fprintf(out, COMMENT_USER_HOME_CONTEXT, FALLBACK_SENAME) < 0)
71e0cd6
+			return STATUS_ERR;
71e0cd6
+	} else {
71e0cd6
+		if (fprintf(out, COMMENT_USER_HOME_CONTEXT, user->name) < 0)
71e0cd6
+			return STATUS_ERR;
71e0cd6
+	}
71e0cd6
+
9a2ed65
+	return write_contexts(s, out, tpl, repl, user);
71e0cd6
+}
71e0cd6
+
9a2ed65
+static int write_home_root_context(genhomedircon_settings_t * s, FILE * out,
9a2ed65
+				   semanage_list_t * tpl, char *homedir)
9a2ed65
+{
9a2ed65
+	replacement_pair_t repl[] = {
9a2ed65
+		{.search_for = TEMPLATE_HOME_ROOT,.replace_with = homedir},
9a2ed65
+		{NULL, NULL}
9a2ed65
+	};
9a2ed65
+
71e0cd6
+	return write_replacements(s, out, tpl, repl);
71e0cd6
+}
9a2ed65
+
71e0cd6
+static int write_username_context(genhomedircon_settings_t * s, FILE * out,
71e0cd6
+				  semanage_list_t * tpl,
71e0cd6
+				  const genhomedircon_user_entry_t *user)
71e0cd6
+{
71e0cd6
+	replacement_pair_t repl[] = {
71e0cd6
+		{.search_for = TEMPLATE_USERNAME,.replace_with = user->name},
71e0cd6
+		{.search_for = TEMPLATE_USERID,.replace_with = user->uid},
71e0cd6
+		{.search_for = TEMPLATE_ROLE,.replace_with = user->prefix},
71e0cd6
+		{NULL, NULL}
71e0cd6
+	};
71e0cd6
+
9a2ed65
+	return write_contexts(s, out, tpl, repl, user);
9a2ed65
+}
9a2ed65
+
71e0cd6
 static int write_user_context(genhomedircon_settings_t * s, FILE * out,
71e0cd6
-			      semanage_list_t * tpl, const char *user,
71e0cd6
-			      const char *seuser, const char *role_prefix)
71e0cd6
+			      semanage_list_t * tpl, const genhomedircon_user_entry_t *user)
71e0cd6
 {
71e0cd6
 	replacement_pair_t repl[] = {
71e0cd6
-		{.search_for = TEMPLATE_USER,.replace_with = user},
71e0cd6
-		{.search_for = TEMPLATE_ROLE,.replace_with = role_prefix},
71e0cd6
-		{.search_for = TEMPLATE_SEUSER,.replace_with = seuser},
71e0cd6
+		{.search_for = TEMPLATE_USER,.replace_with = user->name},
71e0cd6
+		{.search_for = TEMPLATE_ROLE,.replace_with = user->prefix},
71e0cd6
 		{NULL, NULL}
71e0cd6
 	};
71e0cd6
-	Ustr *line = USTR_NULL;
9a2ed65
 
71e0cd6
-	for (; tpl; tpl = tpl->next) {
71e0cd6
-		line = replace_all(tpl->data, repl);
71e0cd6
-		if (!line)
71e0cd6
-			goto fail;
71e0cd6
-		if (check_line(s, line) == STATUS_SUCCESS) {
71e0cd6
-			if (!ustr_io_putfileline(&line, out))
71e0cd6
-				goto fail;
71e0cd6
-		}
71e0cd6
-		ustr_sc_free(&line);
9a2ed65
+	return write_contexts(s, out, tpl, repl, user);
9a2ed65
+}
9a2ed65
+
9a2ed65
+static int seuser_sort_func(const void *arg1, const void *arg2)
9a2ed65
+{
9a2ed65
+	const semanage_seuser_t **u1 = (const semanage_seuser_t **) arg1;
9a2ed65
+	const semanage_seuser_t **u2 = (const semanage_seuser_t **) arg2;;
9a2ed65
+	const char *name1 = semanage_seuser_get_name(*u1);
9a2ed65
+	const char *name2 = semanage_seuser_get_name(*u2);
9a2ed65
+
9a2ed65
+	if (name1[0] == '%' && name2[0] == '%') {
9a2ed65
+		return 0;
9a2ed65
+	} else if (name1[0] == '%') {
9a2ed65
+		return 1;
9a2ed65
+	} else if (name2[0] == '%') {
9a2ed65
+		return -1;
9a2ed65
 	}
71e0cd6
-	return STATUS_SUCCESS;
71e0cd6
 
71e0cd6
-      fail:
71e0cd6
-	ustr_sc_free(&line);
71e0cd6
-	return STATUS_ERR;
9a2ed65
+	return strcmp(name1, name2);
71e0cd6
 }
71e0cd6
 
71e0cd6
 static int user_sort_func(semanage_user_t ** arg1, semanage_user_t ** arg2)
9a2ed65
@@ -649,15 +754,19 @@ static int name_user_cmp(char *key, semanage_user_t ** val)
71e0cd6
 }
71e0cd6
 
71e0cd6
 static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n,
71e0cd6
-			   const char *sen, const char *pre, const char *h,
71e0cd6
-			   const char *l)
71e0cd6
+			   const char *u, const char *g, const char *sen,
9a2ed65
+			   const char *pre, const char *h, const char *l,
9a2ed65
+			   const char *ln)
71e0cd6
 {
71e0cd6
 	genhomedircon_user_entry_t *temp = NULL;
71e0cd6
 	char *name = NULL;
71e0cd6
+	char *uid = NULL;
71e0cd6
+	char *gid = NULL;
71e0cd6
 	char *sename = NULL;
71e0cd6
 	char *prefix = NULL;
71e0cd6
 	char *home = NULL;
9a2ed65
 	char *level = NULL;
9a2ed65
+	char *lname = NULL;
9a2ed65
 
9a2ed65
 	temp = malloc(sizeof(genhomedircon_user_entry_t));
9a2ed65
 	if (!temp)
9a2ed65
@@ -665,6 +774,12 @@ static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n,
71e0cd6
 	name = strdup(n);
71e0cd6
 	if (!name)
71e0cd6
 		goto cleanup;
71e0cd6
+	uid = strdup(u);
71e0cd6
+	if (!uid)
71e0cd6
+		goto cleanup;
71e0cd6
+	gid = strdup(g);
71e0cd6
+	if (!gid)
71e0cd6
+		goto cleanup;
71e0cd6
 	sename = strdup(sen);
71e0cd6
 	if (!sename)
71e0cd6
 		goto cleanup;
9a2ed65
@@ -677,12 +792,18 @@ static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n,
9a2ed65
 	level = strdup(l);
9a2ed65
 	if (!level)
71e0cd6
 		goto cleanup;
9a2ed65
+	lname = strdup(ln);
9a2ed65
+	if (!lname)
9a2ed65
+		goto cleanup;
71e0cd6
 
71e0cd6
 	temp->name = name;
71e0cd6
+	temp->uid = uid;
71e0cd6
+	temp->gid = gid;
71e0cd6
 	temp->sename = sename;
71e0cd6
 	temp->prefix = prefix;
71e0cd6
 	temp->home = home;
9a2ed65
 	temp->level = level;
9a2ed65
+	temp->login = lname;
9a2ed65
 	temp->next = (*list);
9a2ed65
 	(*list) = temp;
9a2ed65
 
9a2ed65
@@ -690,10 +811,13 @@ static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n,
71e0cd6
 
71e0cd6
       cleanup:
71e0cd6
 	free(name);
71e0cd6
+	free(uid);
71e0cd6
+	free(gid);
71e0cd6
 	free(sename);
71e0cd6
 	free(prefix);
71e0cd6
 	free(home);
9a2ed65
 	free(level);
9a2ed65
+	free(lname);
9a2ed65
 	free(temp);
9a2ed65
 	return STATUS_ERR;
9a2ed65
 }
9a2ed65
@@ -708,39 +832,16 @@ static void pop_user_entry(genhomedircon_user_entry_t ** list)
71e0cd6
 	temp = *list;
71e0cd6
 	*list = temp->next;
71e0cd6
 	free(temp->name);
71e0cd6
+	free(temp->uid);
71e0cd6
+	free(temp->gid);
71e0cd6
 	free(temp->sename);
71e0cd6
 	free(temp->prefix);
71e0cd6
 	free(temp->home);
9a2ed65
 	free(temp->level);
9a2ed65
+	free(temp->login);
71e0cd6
 	free(temp);
71e0cd6
 }
71e0cd6
 
71e0cd6
-static int set_fallback_user(genhomedircon_settings_t *s, const char *user,
71e0cd6
-			     const char *prefix, const char *level)
71e0cd6
-{
71e0cd6
-	char *fallback_user = strdup(user);
71e0cd6
-	char *fallback_user_prefix = strdup(prefix);
71e0cd6
-	char *fallback_user_level = NULL;
71e0cd6
-	if (level) 
71e0cd6
-		fallback_user_level = strdup(level);
71e0cd6
-
71e0cd6
-	if (fallback_user == NULL || fallback_user_prefix == NULL ||
71e0cd6
-	    (fallback_user_level == NULL && level != NULL)) {
71e0cd6
-		free(fallback_user);
71e0cd6
-		free(fallback_user_prefix);
71e0cd6
-		free(fallback_user_level);
71e0cd6
-		return STATUS_ERR;
71e0cd6
-	}
71e0cd6
-
71e0cd6
-	free(s->fallback_user);
71e0cd6
-	free(s->fallback_user_prefix);
71e0cd6
-	free(s->fallback_user_level);
71e0cd6
-	s->fallback_user = fallback_user;
71e0cd6
-	s->fallback_user_prefix = fallback_user_prefix;
71e0cd6
-	s->fallback_user_level = fallback_user_level;
71e0cd6
-	return STATUS_SUCCESS;
71e0cd6
-}
71e0cd6
-
71e0cd6
 static int setup_fallback_user(genhomedircon_settings_t * s)
71e0cd6
 {
71e0cd6
 	semanage_seuser_t **seuser_list = NULL;
9a2ed65
@@ -775,17 +876,20 @@ static int setup_fallback_user(genhomedircon_settings_t * s)
71e0cd6
 			if (semanage_user_query(s->h_semanage, key, &u) < 0)
71e0cd6
 			{
71e0cd6
 				prefix = name;
71e0cd6
-				level = FALLBACK_USER_LEVEL;
71e0cd6
+				level = FALLBACK_LEVEL;
71e0cd6
 			}
71e0cd6
 			else
71e0cd6
 			{
71e0cd6
 				prefix = semanage_user_get_prefix(u);
71e0cd6
 				level = semanage_user_get_mlslevel(u);
71e0cd6
 				if (!level)
71e0cd6
-					level = FALLBACK_USER_LEVEL;
71e0cd6
+					level = FALLBACK_LEVEL;
71e0cd6
 			}
71e0cd6
 
71e0cd6
-			if (set_fallback_user(s, seuname, prefix, level) != 0)
71e0cd6
+			if (push_user_entry(&(s->fallback), FALLBACK_NAME,
71e0cd6
+					    FALLBACK_UIDGID, FALLBACK_UIDGID,
9a2ed65
+					    seuname, prefix, "", level,
9a2ed65
+					    FALLBACK_NAME) != 0)
71e0cd6
 				errors = STATUS_ERR;
71e0cd6
 			semanage_user_key_free(key);
71e0cd6
 			if (u)
9a2ed65
@@ -801,6 +905,202 @@ static int setup_fallback_user(genhomedircon_settings_t * s)
9a2ed65
 	return errors;
9a2ed65
 }
9a2ed65
 
9a2ed65
+static genhomedircon_user_entry_t *find_user(genhomedircon_user_entry_t *head,
9a2ed65
+					     const char *name)
9a2ed65
+{
9a2ed65
+	for(; head; head = head->next) {
9a2ed65
+		if (strcmp(head->name, name) == 0) {
9a2ed65
+			return head;
9a2ed65
+		}
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	return NULL;
9a2ed65
+}
9a2ed65
+
9a2ed65
+static int add_user(genhomedircon_settings_t * s,
9a2ed65
+		    genhomedircon_user_entry_t **head,
9a2ed65
+		    semanage_user_t *user,
9a2ed65
+		    const char *name,
9a2ed65
+		    const char *sename,
9a2ed65
+		    const char *selogin)
9a2ed65
+{
9a2ed65
+	if (selogin[0] == '%') {
9a2ed65
+		genhomedircon_user_entry_t *orig = find_user(*head, name);
9a2ed65
+		if (orig != NULL && orig->login[0] == '%') {
9a2ed65
+			ERR(s->h_semanage, "User %s is already mapped to"
9a2ed65
+			    " group %s, but also belongs to group %s. Add an"
9a2ed65
+			    " explicit mapping for this user to"
9a2ed65
+			    " override group mappings.",
9a2ed65
+			    name, orig->login + 1, selogin + 1);
9a2ed65
+			return STATUS_ERR;
9a2ed65
+		} else if (orig != NULL) {
9a2ed65
+			// user mappings take precedence
9a2ed65
+			return STATUS_SUCCESS;
9a2ed65
+		}
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	int retval = STATUS_ERR;
9a2ed65
+
9a2ed65
+	char *rbuf = NULL;
9a2ed65
+	long rbuflen;
9a2ed65
+	struct passwd pwstorage, *pwent = NULL;
9a2ed65
+	const char *prefix = NULL;
9a2ed65
+	const char *level = NULL;
71e0cd6
+	char uid[11];
71e0cd6
+	char gid[11];
9a2ed65
+
9a2ed65
+	/* Allocate space for the getpwnam_r buffer */
9a2ed65
+	rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
9a2ed65
+	if (rbuflen <= 0)
9a2ed65
+		goto cleanup;
9a2ed65
+	rbuf = malloc(rbuflen);
9a2ed65
+	if (rbuf == NULL)
9a2ed65
+		goto cleanup;
9a2ed65
+
9a2ed65
+	if (user) {
9a2ed65
+		prefix = semanage_user_get_prefix(user);
9a2ed65
+		level = semanage_user_get_mlslevel(user);
9a2ed65
+
9a2ed65
+		if (!level) {
9a2ed65
+			level = FALLBACK_LEVEL;
9a2ed65
+		}
9a2ed65
+	} else {
9a2ed65
+		prefix = name;
9a2ed65
+		level = FALLBACK_LEVEL;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent);
9a2ed65
+	if (retval != 0 || pwent == NULL) {
9a2ed65
+		if (retval != 0 && retval != ENOENT) {
9a2ed65
+			goto cleanup;
9a2ed65
+		}
9a2ed65
+
9a2ed65
+		WARN(s->h_semanage,
9a2ed65
+		     "user %s not in password file", name);
9a2ed65
+		retval = STATUS_SUCCESS;
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	int len = strlen(pwent->pw_dir) -1;
9a2ed65
+	for(; len > 0 && pwent->pw_dir[len] == '/'; len--) {
9a2ed65
+		pwent->pw_dir[len] = '\0';
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	if (strcmp(pwent->pw_dir, "/") == 0) {
9a2ed65
+		/* don't relabel / genhomdircon checked to see if root
9a2ed65
+		 * was the user and if so, set his home directory to
9a2ed65
+		 * /root */
9a2ed65
+		retval = STATUS_SUCCESS;
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	if (ignore(pwent->pw_dir)) {
9a2ed65
+		retval = STATUS_SUCCESS;
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	len = snprintf(uid, sizeof(uid), "%u", pwent->pw_uid);
9a2ed65
+	if (len < 0 || len >= (int)sizeof(uid)) {
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	len = snprintf(gid, sizeof(gid), "%u", pwent->pw_gid);
9a2ed65
+	if (len < 0 || len >= (int)sizeof(gid)) {
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	retval = push_user_entry(head, name, uid, gid, sename, prefix,
9a2ed65
+				pwent->pw_dir, level, selogin);
9a2ed65
+cleanup:
9a2ed65
+	free(rbuf);
9a2ed65
+	return retval;
9a2ed65
+}
9a2ed65
+
9a2ed65
+static int get_group_users(genhomedircon_settings_t * s,
9a2ed65
+			  genhomedircon_user_entry_t **head,
9a2ed65
+			  semanage_user_t *user,
9a2ed65
+			  const char *sename,
9a2ed65
+			  const char *selogin)
9a2ed65
+{
9a2ed65
+	int retval = STATUS_ERR;
9a2ed65
+	unsigned int i;
9a2ed65
+
9a2ed65
+	long grbuflen;
9a2ed65
+	char *grbuf = NULL;
9a2ed65
+	struct group grstorage, *group = NULL;
9a2ed65
+
9a2ed65
+	long prbuflen;
9a2ed65
+	char *pwbuf = NULL;
9a2ed65
+	struct passwd pwstorage, *pw = NULL;
9a2ed65
+
9a2ed65
+	grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
9a2ed65
+	if (grbuflen <= 0)
9a2ed65
+		goto cleanup;
9a2ed65
+	grbuf = malloc(grbuflen);
9a2ed65
+	if (grbuf == NULL)
9a2ed65
+		goto cleanup;
9a2ed65
+
9a2ed65
+	const char *grname = selogin + 1;
9a2ed65
+
9a2ed65
+	if (getgrnam_r(grname, &grstorage, grbuf,
9a2ed65
+			(size_t) grbuflen, &group) != 0) {
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	if (group == NULL) {
9a2ed65
+		ERR(s->h_semanage, "Can't find group named %s\n", grname);
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	size_t nmembers = 0;
9a2ed65
+	char **members = group->gr_mem;
9a2ed65
+
9a2ed65
+	while (*members != NULL) {
9a2ed65
+		nmembers++;
9a2ed65
+		members++;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	for (i = 0; i < nmembers; i++) {
9a2ed65
+		const char *uname = group->gr_mem[i];
9a2ed65
+
9a2ed65
+		if (add_user(s, head, user, uname, sename, selogin) < 0) {
9a2ed65
+			goto cleanup;
9a2ed65
+		}
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	prbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
9a2ed65
+	if (prbuflen <= 0)
9a2ed65
+		goto cleanup;
9a2ed65
+	pwbuf = malloc(prbuflen);
9a2ed65
+	if (pwbuf == NULL)
9a2ed65
+		goto cleanup;
9a2ed65
+
9a2ed65
+	setpwent();
9a2ed65
+	while ((retval = getpwent_r(&pwstorage, pwbuf, prbuflen, &pw)) == 0) {
9a2ed65
+		// skip users who also have this group as their
9a2ed65
+		// primary group
9a2ed65
+		if (lfind(pw->pw_name, group->gr_mem, &nmembers,
9a2ed65
+			  sizeof(char *), &STR_COMPARATOR)) {
9a2ed65
+			continue;
9a2ed65
+		}
9a2ed65
+
9a2ed65
+		if (group->gr_gid == pw->pw_gid) {
9a2ed65
+			if (add_user(s, head, user, pw->pw_name,
9a2ed65
+				     sename, selogin) < 0) {
9a2ed65
+				goto cleanup;
9a2ed65
+			}
9a2ed65
+		}
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	retval = STATUS_SUCCESS;
9a2ed65
+cleanup:
9a2ed65
+	endpwent();
9a2ed65
+	free(pwbuf);
9a2ed65
+	free(grbuf);
9a2ed65
+
9a2ed65
+	return retval;
9a2ed65
+}
9a2ed65
+
9a2ed65
 static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s,
9a2ed65
 					     int *errors)
9a2ed65
 {
9a2ed65
@@ -812,12 +1112,7 @@ static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s,
9a2ed65
 	semanage_user_t **u = NULL;
9a2ed65
 	const char *name = NULL;
9a2ed65
 	const char *seuname = NULL;
9a2ed65
-	const char *prefix = NULL;
9a2ed65
-	const char *level = NULL;
9a2ed65
-	struct passwd pwstorage, *pwent = NULL;
71e0cd6
 	unsigned int i;
9a2ed65
-	long rbuflen;
9a2ed65
-	char *rbuf = NULL;
9a2ed65
 	int retval;
9a2ed65
 
9a2ed65
 	*errors = 0;
9a2ed65
@@ -831,82 +1126,39 @@ static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s,
9a2ed65
 		nusers = 0;
9a2ed65
 	}
9a2ed65
 
9a2ed65
+	qsort(seuser_list, nseusers, sizeof(semanage_seuser_t *),
9a2ed65
+	      &seuser_sort_func);
9a2ed65
 	qsort(user_list, nusers, sizeof(semanage_user_t *),
9a2ed65
 	      (int (*)(const void *, const void *))&user_sort_func);
9a2ed65
 
9a2ed65
-	/* Allocate space for the getpwnam_r buffer */
9a2ed65
-	rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
9a2ed65
-	if (rbuflen <= 0)
9a2ed65
-		goto cleanup;
9a2ed65
-	rbuf = malloc(rbuflen);
9a2ed65
-	if (rbuf == NULL)
9a2ed65
-		goto cleanup;
9a2ed65
-
9a2ed65
 	for (i = 0; i < nseusers; i++) {
71e0cd6
 		seuname = semanage_seuser_get_sename(seuser_list[i]);
71e0cd6
 		name = semanage_seuser_get_name(seuser_list[i]);
71e0cd6
 
71e0cd6
-		if (strcmp(name,"root") && strcmp(seuname, s->fallback_user) == 0)
9a2ed65
-			continue;
9a2ed65
-
9a2ed65
 		if (strcmp(name, DEFAULT_LOGIN) == 0)
71e0cd6
 			continue;
71e0cd6
 
9a2ed65
-		if (strcmp(name, TEMPLATE_SEUSER) == 0)
9a2ed65
-			continue;
9a2ed65
-
9a2ed65
-		/* %groupname syntax */
9a2ed65
-		if (name[0] == '%')
9a2ed65
-			continue;
9a2ed65
-
9a2ed65
 		/* find the user structure given the name */
9a2ed65
 		u = bsearch(seuname, user_list, nusers, sizeof(semanage_user_t *),
9a2ed65
 			    (int (*)(const void *, const void *))
9a2ed65
 			    &name_user_cmp);
9a2ed65
-		if (u) {
9a2ed65
-			prefix = semanage_user_get_prefix(*u);
9a2ed65
-			level = semanage_user_get_mlslevel(*u);
9a2ed65
-			if (!level)
71e0cd6
-				level = FALLBACK_USER_LEVEL;
9a2ed65
-		} else {
9a2ed65
-			prefix = name;
71e0cd6
-			level = FALLBACK_USER_LEVEL;
9a2ed65
-		}
9a2ed65
-
9a2ed65
-		retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent);
9a2ed65
-		if (retval != 0 || pwent == NULL) {
9a2ed65
-			if (retval != 0 && retval != ENOENT) {
9a2ed65
-				*errors = STATUS_ERR;
9a2ed65
-				goto cleanup;
9a2ed65
-			}
9a2ed65
-
9a2ed65
-			WARN(s->h_semanage,
9a2ed65
-			     "user %s not in password file", name);
9a2ed65
-			continue;
9a2ed65
-		}
71e0cd6
 
9a2ed65
-		int len = strlen(pwent->pw_dir) -1;
9a2ed65
-		for(; len > 0 && pwent->pw_dir[len] == '/'; len--) {
9a2ed65
-			pwent->pw_dir[len] = '\0';
9a2ed65
+		/* %groupname syntax */
9a2ed65
+		if (name[0] == '%') {
9a2ed65
+			retval = get_group_users(s, &head, *u, seuname,
9a2ed65
+						name);
9a2ed65
+		} else {
9a2ed65
+			retval = add_user(s, &head, *u, name,
9a2ed65
+					  seuname, name);
71e0cd6
 		}
9a2ed65
 
9a2ed65
-		if (strcmp(pwent->pw_dir, "/") == 0) {
9a2ed65
-			/* don't relabel / genhomdircon checked to see if root
9a2ed65
-			 * was the user and if so, set his home directory to
9a2ed65
-			 * /root */
9a2ed65
-			continue;
9a2ed65
-		}
9a2ed65
-		if (ignore(pwent->pw_dir))
9a2ed65
-			continue;
71e0cd6
-		if (push_user_entry(&head, name, seuname,
9a2ed65
-				    prefix, pwent->pw_dir, level) != STATUS_SUCCESS) {
9a2ed65
+		if (retval != 0) {
71e0cd6
 			*errors = STATUS_ERR;
9a2ed65
-			break;
9a2ed65
+			goto cleanup;
9a2ed65
 		}
9a2ed65
 	}
9a2ed65
 
9a2ed65
       cleanup:
9a2ed65
-	free(rbuf);
9a2ed65
 	if (*errors) {
9a2ed65
 		for (; head; pop_user_entry(&head)) {
9a2ed65
 			/* the pop function takes care of all the cleanup
9a2ed65
@@ -927,6 +1179,7 @@ static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s,
71e0cd6
 }
71e0cd6
 
71e0cd6
 static int write_gen_home_dir_context(genhomedircon_settings_t * s, FILE * out,
71e0cd6
+				      semanage_list_t * username_context_tpl,
71e0cd6
 				      semanage_list_t * user_context_tpl,
71e0cd6
 				      semanage_list_t * homedir_context_tpl)
71e0cd6
 {
9a2ed65
@@ -939,13 +1192,11 @@ static int write_gen_home_dir_context(genhomedircon_settings_t * s, FILE * out,
71e0cd6
 	}
71e0cd6
 
71e0cd6
 	for (; users; pop_user_entry(&users)) {
71e0cd6
-		if (write_home_dir_context(s, out, homedir_context_tpl,
71e0cd6
-					   users->name,
71e0cd6
-					   users->sename, users->home,
71e0cd6
-					   users->prefix, users->level))
71e0cd6
+		if (write_home_dir_context(s, out, homedir_context_tpl, users))
71e0cd6
 			goto err;
71e0cd6
-		if (write_user_context(s, out, user_context_tpl, users->name,
71e0cd6
-				       users->sename, users->prefix))
71e0cd6
+		if (write_username_context(s, out, username_context_tpl, users))
71e0cd6
+			goto err;
71e0cd6
+		if (write_user_context(s, out, user_context_tpl, users))
71e0cd6
 			goto err;
71e0cd6
 	}
71e0cd6
 
9a2ed65
@@ -968,16 +1219,21 @@ static int write_context_file(genhomedircon_settings_t * s, FILE * out)
71e0cd6
 {
71e0cd6
 	semanage_list_t *homedirs = NULL;
71e0cd6
 	semanage_list_t *h = NULL;
71e0cd6
-	semanage_list_t *user_context_tpl = NULL;
71e0cd6
 	semanage_list_t *homedir_context_tpl = NULL;
71e0cd6
 	semanage_list_t *homeroot_context_tpl = NULL;
71e0cd6
+	semanage_list_t *username_context_tpl = NULL;
71e0cd6
+	semanage_list_t *user_context_tpl = NULL;
71e0cd6
 	int retval = STATUS_SUCCESS;
71e0cd6
 
71e0cd6
 	homedir_context_tpl = make_template(s, &HOME_DIR_PRED);
71e0cd6
 	homeroot_context_tpl = make_template(s, &HOME_ROOT_PRED);
71e0cd6
+	username_context_tpl = make_template(s, &USERNAME_CONTEXT_PRED);
71e0cd6
 	user_context_tpl = make_template(s, &USER_CONTEXT_PRED);
71e0cd6
 
71e0cd6
-	if (!homedir_context_tpl && !homeroot_context_tpl && !user_context_tpl)
71e0cd6
+	if (!homedir_context_tpl
71e0cd6
+	 && !homeroot_context_tpl
71e0cd6
+	 && !username_context_tpl
71e0cd6
+	 && !user_context_tpl)
71e0cd6
 		goto done;
71e0cd6
 
71e0cd6
 	if (write_file_context_header(out) != STATUS_SUCCESS) {
9a2ed65
@@ -1001,19 +1257,19 @@ static int write_context_file(genhomedircon_settings_t * s, FILE * out)
71e0cd6
 		for (h = homedirs; h; h = h->next) {
71e0cd6
 			Ustr *temp = ustr_dup_cstr(h->data);
71e0cd6
 
71e0cd6
-			if (!temp || !ustr_add_cstr(&temp, "/[^/]*")) {
71e0cd6
+			if (!temp || !ustr_add_cstr(&temp, "/" FALLBACK_NAME)) {
71e0cd6
 				ustr_sc_free(&temp);
71e0cd6
 				retval = STATUS_ERR;
71e0cd6
 				goto done;
71e0cd6
 			}
71e0cd6
 
71e0cd6
-			if (write_home_dir_context(s, out,
71e0cd6
-						   homedir_context_tpl,
71e0cd6
-						   s->fallback_user, s->fallback_user,
71e0cd6
-						   ustr_cstr(temp),
71e0cd6
-						   s->fallback_user_prefix, s->fallback_user_level) !=
71e0cd6
-			    STATUS_SUCCESS) {
71e0cd6
+			free(s->fallback->home);
71e0cd6
+			s->fallback->home = (char*) ustr_cstr(temp);
71e0cd6
+
71e0cd6
+			if (write_home_dir_context(s, out, homedir_context_tpl,
71e0cd6
+						   s->fallback) != STATUS_SUCCESS) {
71e0cd6
 				ustr_sc_free(&temp);
71e0cd6
+				s->fallback->home = NULL;
71e0cd6
 				retval = STATUS_ERR;
71e0cd6
 				goto done;
71e0cd6
 			}
9a2ed65
@@ -1021,23 +1277,31 @@ static int write_context_file(genhomedircon_settings_t * s, FILE * out)
71e0cd6
 						    homeroot_context_tpl,
71e0cd6
 						    h->data) != STATUS_SUCCESS) {
71e0cd6
 				ustr_sc_free(&temp);
71e0cd6
+				s->fallback->home = NULL;
71e0cd6
 				retval = STATUS_ERR;
71e0cd6
 				goto done;
71e0cd6
 			}
71e0cd6
 
71e0cd6
 			ustr_sc_free(&temp);
71e0cd6
+			s->fallback->home = NULL;
71e0cd6
 		}
71e0cd6
 	}
71e0cd6
-	if (user_context_tpl) {
71e0cd6
+	if (user_context_tpl || username_context_tpl) {
71e0cd6
+		if (write_username_context(s, out, username_context_tpl,
71e0cd6
+					   s->fallback) != STATUS_SUCCESS) {
71e0cd6
+			retval = STATUS_ERR;
71e0cd6
+			goto done;
71e0cd6
+		}
71e0cd6
+
71e0cd6
 		if (write_user_context(s, out, user_context_tpl,
71e0cd6
-				       ".*", s->fallback_user,
71e0cd6
-				       s->fallback_user_prefix) != STATUS_SUCCESS) {
71e0cd6
+				       s->fallback) != STATUS_SUCCESS) {
71e0cd6
 			retval = STATUS_ERR;
71e0cd6
 			goto done;
71e0cd6
 		}
71e0cd6
 
71e0cd6
-		if (write_gen_home_dir_context(s, out, user_context_tpl,
71e0cd6
-					       homedir_context_tpl) != STATUS_SUCCESS) {
71e0cd6
+		if (write_gen_home_dir_context(s, out, username_context_tpl,
71e0cd6
+					       user_context_tpl, homedir_context_tpl)
71e0cd6
+				!= STATUS_SUCCESS) {
71e0cd6
 			retval = STATUS_ERR;
71e0cd6
 		}
71e0cd6
 	}
9a2ed65
@@ -1045,6 +1309,7 @@ static int write_context_file(genhomedircon_settings_t * s, FILE * out)
71e0cd6
 done:
71e0cd6
 	/* Cleanup */
71e0cd6
 	semanage_list_destroy(&homedirs);
71e0cd6
+	semanage_list_destroy(&username_context_tpl);
71e0cd6
 	semanage_list_destroy(&user_context_tpl);
71e0cd6
 	semanage_list_destroy(&homedir_context_tpl);
71e0cd6
 	semanage_list_destroy(&homeroot_context_tpl);
9a2ed65
@@ -1068,10 +1333,20 @@ int semanage_genhomedircon(semanage_handle_t * sh,
71e0cd6
 	s.fcfilepath = semanage_final_path(SEMANAGE_FINAL_TMP,
71e0cd6
 					   SEMANAGE_FC_HOMEDIRS);
71e0cd6
 
71e0cd6
-	s.fallback_user = strdup(FALLBACK_USER);
71e0cd6
-	s.fallback_user_prefix = strdup(FALLBACK_USER_PREFIX);
71e0cd6
-	s.fallback_user_level = strdup(FALLBACK_USER_LEVEL);
71e0cd6
-	if (s.fallback_user == NULL || s.fallback_user_prefix == NULL || s.fallback_user_level == NULL) {
71e0cd6
+	s.fallback = calloc(1, sizeof(genhomedircon_user_entry_t));
71e0cd6
+	if (s.fallback == NULL) {
71e0cd6
+		retval = STATUS_ERR;
71e0cd6
+		goto done;
71e0cd6
+	}
71e0cd6
+
71e0cd6
+	s.fallback->name = strdup(FALLBACK_NAME);
71e0cd6
+	s.fallback->sename = strdup(FALLBACK_SENAME);
71e0cd6
+	s.fallback->prefix = strdup(FALLBACK_PREFIX);
71e0cd6
+	s.fallback->level = strdup(FALLBACK_LEVEL);
71e0cd6
+	if (s.fallback->name == NULL
71e0cd6
+	 || s.fallback->sename == NULL
71e0cd6
+	 || s.fallback->prefix == NULL
71e0cd6
+	 || s.fallback->level == NULL) {
71e0cd6
 		retval = STATUS_ERR;
71e0cd6
 		goto done;
71e0cd6
 	}
9a2ed65
@@ -1095,9 +1370,7 @@ done:
71e0cd6
 	if (out != NULL)
71e0cd6
 		fclose(out);
71e0cd6
 
71e0cd6
-	free(s.fallback_user);
71e0cd6
-	free(s.fallback_user_prefix);
71e0cd6
-	free(s.fallback_user_level);
71e0cd6
+	pop_user_entry(&(s.fallback));
71e0cd6
 	ignore_free();
71e0cd6
 
71e0cd6
 	return retval;
9a2ed65
diff --git libsemanage-2.5/src/semanage_store.c libsemanage-2.5/src/semanage_store.c
5012c31
index fa0876f..340c123 100644
9a2ed65
--- libsemanage-2.5/src/semanage_store.c
9a2ed65
+++ libsemanage-2.5/src/semanage_store.c
5012c31
@@ -95,7 +95,7 @@ static const char *semanage_store_paths[SEMANAGE_NUM_STORES] = {
5012c31
 static const char *semanage_sandbox_paths[SEMANAGE_STORE_NUM_PATHS] = {
5012c31
 	"",
5012c31
 	"/modules",
5012c31
-	"/base.linked",
5012c31
+	"/policy.linked",
5012c31
 	"/homedir_template",
5012c31
 	"/file_contexts.template",
5012c31
 	"/commit_num",
5012c31
@@ -104,8 +104,10 @@ static const char *semanage_sandbox_paths[SEMANAGE_STORE_NUM_PATHS] = {
5012c31
 	"/nodes.local",
5012c31
 	"/booleans.local",
5012c31
 	"/seusers.local",
5012c31
+	"/seusers.linked",
5012c31
 	"/users.local",
5012c31
 	"/users_extra.local",
5012c31
+	"/users_extra.linked",
5012c31
 	"/users_extra",
5012c31
 	"/disable_dontaudit",
5012c31
 	"/preserve_tunables",
5012c31
@@ -292,6 +294,13 @@ static int semanage_init_final_suffix(semanage_handle_t *sh)
9a2ed65
 		goto cleanup;
9a2ed65
 	}
9a2ed65
 
9a2ed65
+	if (asprintf(&semanage_final_suffix[SEMANAGE_FC_BIN], "%s.bin",
9a2ed65
+		     semanage_final_suffix[SEMANAGE_FC]) < 0) {
9a2ed65
+		ERR(sh, "Unable to allocate space for file context path.");
9a2ed65
+		status = -1;
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
 	semanage_final_suffix[SEMANAGE_FC_HOMEDIRS] =
9a2ed65
 		strdup(selinux_file_context_homedir_path() + offset);
9a2ed65
 	if (semanage_final_suffix[SEMANAGE_FC_HOMEDIRS] == NULL) {
5012c31
@@ -300,6 +309,13 @@ static int semanage_init_final_suffix(semanage_handle_t *sh)
9a2ed65
 		goto cleanup;
9a2ed65
 	}
9a2ed65
 
9a2ed65
+	if (asprintf(&semanage_final_suffix[SEMANAGE_FC_HOMEDIRS_BIN], "%s.bin",
9a2ed65
+		     semanage_final_suffix[SEMANAGE_FC_HOMEDIRS]) < 0) {
9a2ed65
+		ERR(sh, "Unable to allocate space for file context home directory path.");
9a2ed65
+		status = -1;
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
 	semanage_final_suffix[SEMANAGE_FC_LOCAL] =
9a2ed65
 		strdup(selinux_file_context_local_path() + offset);
9a2ed65
 	if (semanage_final_suffix[SEMANAGE_FC_LOCAL] == NULL) {
5012c31
@@ -308,6 +324,13 @@ static int semanage_init_final_suffix(semanage_handle_t *sh)
9a2ed65
 		goto cleanup;
9a2ed65
 	}
9a2ed65
 
9a2ed65
+	if (asprintf(&semanage_final_suffix[SEMANAGE_FC_LOCAL_BIN], "%s.bin",
9a2ed65
+		     semanage_final_suffix[SEMANAGE_FC_LOCAL]) < 0) {
9a2ed65
+		ERR(sh, "Unable to allocate space for local file context path.");
9a2ed65
+		status = -1;
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
 	semanage_final_suffix[SEMANAGE_NC] =
9a2ed65
 		strdup(selinux_netfilter_context_path() + offset);
9a2ed65
 	if (semanage_final_suffix[SEMANAGE_NC] == NULL) {
5012c31
@@ -1491,6 +1514,45 @@ static int sefcontext_compile(semanage_handle_t * sh, const char *path) {
9a2ed65
 	return 0;
9a2ed65
 }
9a2ed65
 
9a2ed65
+static int semanage_validate_and_compile_fcontexts(semanage_handle_t * sh)
9a2ed65
+{
9a2ed65
+	int status = -1;
9a2ed65
+
9a2ed65
+	if (sh->do_check_contexts) {
9a2ed65
+		int ret;
9a2ed65
+		ret = semanage_exec_prog(
9a2ed65
+			sh,
9a2ed65
+			sh->conf->setfiles,
9a2ed65
+			semanage_final_path(SEMANAGE_FINAL_TMP,
9a2ed65
+					    SEMANAGE_KERNEL),
9a2ed65
+			semanage_final_path(SEMANAGE_FINAL_TMP,
9a2ed65
+					    SEMANAGE_FC));
9a2ed65
+		if (ret != 0) {
9a2ed65
+			ERR(sh, "setfiles returned error code %d.", ret);
9a2ed65
+			goto cleanup;
9a2ed65
+		}
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	if (sefcontext_compile(sh,
9a2ed65
+		    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC)) != 0) {
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	if (sefcontext_compile(sh,
9a2ed65
+		    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL)) != 0) {
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	if (sefcontext_compile(sh,
9a2ed65
+		    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS)) != 0) {
9a2ed65
+		goto cleanup;
9a2ed65
+	}
9a2ed65
+
9a2ed65
+	status = 0;
9a2ed65
+cleanup:
9a2ed65
+	return status;
9a2ed65
+}
9a2ed65
+
9a2ed65
 /* Load the contexts of the final tmp into the final selinux directory.
9a2ed65
  * Return 0 on success, -3 on error.
9a2ed65
  */
5012c31
@@ -1566,35 +1628,6 @@ static int semanage_install_final_tmp(semanage_handle_t * sh)
9a2ed65
 	}
9a2ed65
 
9a2ed65
 skip_reload:
9a2ed65
-	if (sh->do_check_contexts) {
9a2ed65
-		ret = semanage_exec_prog(
9a2ed65
-			sh,
9a2ed65
-			sh->conf->setfiles,
9a2ed65
-			semanage_final_path(SEMANAGE_FINAL_SELINUX,
9a2ed65
-					    SEMANAGE_KERNEL),
9a2ed65
-			semanage_final_path(SEMANAGE_FINAL_SELINUX,
9a2ed65
-					    SEMANAGE_FC));
9a2ed65
-		if (ret != 0) {
9a2ed65
-			ERR(sh, "setfiles returned error code %d.", ret);
9a2ed65
-			goto cleanup;
9a2ed65
-		}
9a2ed65
-	}
9a2ed65
-
9a2ed65
-	if (sefcontext_compile(sh,
9a2ed65
-		    semanage_final_path(SEMANAGE_FINAL_SELINUX, SEMANAGE_FC)) != 0) {
9a2ed65
-		goto cleanup;
9a2ed65
-	}
9a2ed65
-
9a2ed65
-	if (sefcontext_compile(sh,
9a2ed65
-		    semanage_final_path(SEMANAGE_FINAL_SELINUX, SEMANAGE_FC_LOCAL)) != 0) {
9a2ed65
-		goto cleanup;
9a2ed65
-	}
9a2ed65
-
9a2ed65
-	if (sefcontext_compile(sh,
9a2ed65
-		    semanage_final_path(SEMANAGE_FINAL_SELINUX, SEMANAGE_FC_HOMEDIRS)) != 0) {
9a2ed65
-		goto cleanup;
9a2ed65
-	}
9a2ed65
-
9a2ed65
 	status = 0;
9a2ed65
 cleanup:
9a2ed65
 	return status;
5012c31
@@ -1737,6 +1770,9 @@ int semanage_install_sandbox(semanage_handle_t * sh)
9a2ed65
 		goto cleanup;
9a2ed65
 	}
9a2ed65
 
9a2ed65
+	if (semanage_validate_and_compile_fcontexts(sh) < 0)
9a2ed65
+		goto cleanup;
9a2ed65
+
9a2ed65
 	if ((commit_num = semanage_commit_sandbox(sh)) < 0) {
9a2ed65
 		retval = commit_num;
9a2ed65
 		goto cleanup;
5012c31
@@ -2003,9 +2039,10 @@ int semanage_load_files(semanage_handle_t * sh, cil_db_t *cildb, char **filename
5012c31
  */
5012c31
 
5012c31
 /**
5012c31
- * Read the policy from the sandbox (kernel)
5012c31
+ * Read the policy from the sandbox (linked or kernel)
5012c31
  */
5012c31
-int semanage_read_policydb(semanage_handle_t * sh, sepol_policydb_t * in)
5012c31
+int semanage_read_policydb(semanage_handle_t * sh, sepol_policydb_t * in,
5012c31
+			   enum semanage_sandbox_defs file)
5012c31
 {
5012c31
 
5012c31
 	int retval = STATUS_ERR;
5012c31
@@ -2014,7 +2051,7 @@ int semanage_read_policydb(semanage_handle_t * sh, sepol_policydb_t * in)
5012c31
 	FILE *infile = NULL;
5012c31
 
5012c31
 	if ((kernel_filename =
5012c31
-	     semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL)) == NULL) {
5012c31
+	     semanage_path(SEMANAGE_ACTIVE, file)) == NULL) {
5012c31
 		goto cleanup;
5012c31
 	}
5012c31
 	if ((infile = fopen(kernel_filename, "r")) == NULL) {
5012c31
@@ -2044,9 +2081,10 @@ int semanage_read_policydb(semanage_handle_t * sh, sepol_policydb_t * in)
5012c31
 	return retval;
5012c31
 }
5012c31
 /**
5012c31
- * Writes the final policy to the sandbox (kernel)
5012c31
+ * Writes the policy to the sandbox (linked or kernel)
5012c31
  */
5012c31
-int semanage_write_policydb(semanage_handle_t * sh, sepol_policydb_t * out)
5012c31
+int semanage_write_policydb(semanage_handle_t * sh, sepol_policydb_t * out,
5012c31
+			    enum semanage_sandbox_defs file)
5012c31
 {
5012c31
 
5012c31
 	int retval = STATUS_ERR;
5012c31
@@ -2055,7 +2093,7 @@ int semanage_write_policydb(semanage_handle_t * sh, sepol_policydb_t * out)
5012c31
 	FILE *outfile = NULL;
5012c31
 
5012c31
 	if ((kernel_filename =
5012c31
-	     semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL)) == NULL) {
5012c31
+	     semanage_path(SEMANAGE_TMP, file)) == NULL) {
5012c31
 		goto cleanup;
5012c31
 	}
5012c31
 	if ((outfile = fopen(kernel_filename, "wb")) == NULL) {
9a2ed65
diff --git libsemanage-2.5/src/semanage_store.h libsemanage-2.5/src/semanage_store.h
5012c31
index acb6e3f..0b96fbe 100644
9a2ed65
--- libsemanage-2.5/src/semanage_store.h
9a2ed65
+++ libsemanage-2.5/src/semanage_store.h
5012c31
@@ -49,8 +49,10 @@ enum semanage_sandbox_defs {
5012c31
 	SEMANAGE_NODES_LOCAL,
5012c31
 	SEMANAGE_BOOLEANS_LOCAL,
5012c31
 	SEMANAGE_SEUSERS_LOCAL,
5012c31
+	SEMANAGE_SEUSERS_LINKED,
5012c31
 	SEMANAGE_USERS_BASE_LOCAL,
5012c31
 	SEMANAGE_USERS_EXTRA_LOCAL,
5012c31
+	SEMANAGE_USERS_EXTRA_LINKED,
5012c31
 	SEMANAGE_USERS_EXTRA,
5012c31
 	SEMANAGE_DISABLE_DONTAUDIT,
5012c31
 	SEMANAGE_PRESERVE_TUNABLES,
5012c31
@@ -71,8 +73,11 @@ enum semanage_final_defs {
9a2ed65
 enum semanage_final_path_defs {
9a2ed65
 	SEMANAGE_FINAL_TOPLEVEL,
9a2ed65
 	SEMANAGE_FC,
9a2ed65
+	SEMANAGE_FC_BIN,
9a2ed65
 	SEMANAGE_FC_HOMEDIRS,
9a2ed65
+	SEMANAGE_FC_HOMEDIRS_BIN,
9a2ed65
 	SEMANAGE_FC_LOCAL,
9a2ed65
+	SEMANAGE_FC_LOCAL_BIN,
9a2ed65
 	SEMANAGE_KERNEL,
9a2ed65
 	SEMANAGE_NC,
9a2ed65
 	SEMANAGE_SEUSERS,
5012c31
@@ -126,10 +131,12 @@ int semanage_load_files(semanage_handle_t * sh,
5012c31
 			    cil_db_t *cildb, char **filenames, int num_modules);
5012c31
 
5012c31
 int semanage_read_policydb(semanage_handle_t * sh,
5012c31
-			    sepol_policydb_t * policydb);
5012c31
+			   sepol_policydb_t * policydb,
5012c31
+			   enum semanage_sandbox_defs file);
5012c31
 
5012c31
 int semanage_write_policydb(semanage_handle_t * sh,
5012c31
-			    sepol_policydb_t * policydb);
5012c31
+			    sepol_policydb_t * policydb,
5012c31
+			    enum semanage_sandbox_defs file);
5012c31
 
5012c31
 int semanage_install_sandbox(semanage_handle_t * sh);
5012c31
 
b007211
diff --git libsemanage-2.5/tests/.gitignore libsemanage-2.5/tests/.gitignore
b007211
new file mode 100644
b007211
index 0000000..f07111d
b007211
--- /dev/null
b007211
+++ libsemanage-2.5/tests/.gitignore
b007211
@@ -0,0 +1 @@
b007211
+libsemanage-tests
9a2ed65
diff --git libsemanage-2.5/tests/Makefile libsemanage-2.5/tests/Makefile
9a2ed65
index fec96ff..4b81fed 100644
9a2ed65
--- libsemanage-2.5/tests/Makefile
9a2ed65
+++ libsemanage-2.5/tests/Makefile
9a2ed65
@@ -10,7 +10,6 @@ LIBS = ../src/libsemanage.a ../../libselinux/src/libselinux.a ../../libsepol/src
9a2ed65
 ###########################################################################
9a2ed65
 
9a2ed65
 EXECUTABLE = libsemanage-tests
9a2ed65
-CC = gcc
9a2ed65
 CFLAGS += -g -O0 -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute -Wno-unused-parameter
9a2ed65
 INCLUDE = -I$(TESTSRC) -I$(TESTSRC)/../include
9a2ed65
 LDFLAGS += -lcunit -lustr -lbz2 -laudit
83d1ec7
diff --git libsemanage-2.5/utils/semanage_migrate_store libsemanage-2.5/utils/semanage_migrate_store
288daf8
index 0ebd285..2bdcc05 100755
83d1ec7
--- libsemanage-2.5/utils/semanage_migrate_store
83d1ec7
+++ libsemanage-2.5/utils/semanage_migrate_store
288daf8
@@ -1,4 +1,4 @@
288daf8
-#!/usr/bin/python -E
288daf8
+#!/usr/bin/python3 -E
288daf8
 
288daf8
 
288daf8
 from __future__ import print_function
288daf8
@@ -16,7 +16,7 @@ try:
288daf8
 	import selinux
288daf8
 	import semanage
288daf8
 except:
288daf8
-	print("You must install libselinux-python and libsemanage-python before running this tool", file=sys.stderr)
288daf8
+	print("You must install libselinux-python3 and libsemanage-python3 before running this tool", file=sys.stderr)
288daf8
 	exit(1)
288daf8
 
288daf8