[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Useradd Integration (v. 3)


On Sat, 2005-06-18 at 18:42 -0400, Ivan Gyurdiev wrote:
> > Next, I will work on writing C functions for manipulating the
> > homedir_template file. They will be analogous to users_file.c,
> > and basically move genhomedircon's job into the libsepol library.
> 
> Actually, I think it would be better if I pulled out 
> iterate, mod_user, add... into a more generic thing I can reuse
> for net_contexts, and homedir... 

Attached libsepol changes for v.3.

I've changed some of the functions above into
generic parser utilities, and created a concept of a record - 
you can provide a table of methods for how to work with a particular
record, and then use the record_file.c methods to iterate over
records in a file using the same code, just a different parsing
function.

I am still not quite happy with this. It could be made simpler,
and better. I'm pretty sure the MLS parsing code is broken,
and I need to rewrite/test this. 

On the other hand I got multiline parsing to work,
and parsing is simpler in general. I can also
reuse a large part of the code to parse other things
than the users file.

Next - homedir template file..

-- 
Ivan Gyurdiev <ivg2@xxxxxxxxxxx>
Cornell University
diff -Naur libsepol-1.5.9.orig/include/sepol/booleans.h libsepol-1.5.9.new/include/sepol/booleans.h
--- libsepol-1.5.9.orig/include/sepol/booleans.h	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/include/sepol/booleans.h	2005-06-18 00:04:32.000000000 -0400
@@ -0,0 +1,10 @@
+#ifndef _SEPOL_BOOLEANS_H
+#define _SEPOL_BOOLEANS_H
+
+#include <sepol/policydb.h>
+
+extern int sepol_load_booleans(policydb_t* policydb, const char *boolpath);
+extern int sepol_load_booleans_array(
+	policydb_t* policydb, char **names, int *values, int nel);
+
+#endif
diff -Naur libsepol-1.5.9.orig/include/sepol/context.h libsepol-1.5.9.new/include/sepol/context.h
--- libsepol-1.5.9.orig/include/sepol/context.h	2005-06-16 12:35:08.000000000 -0400
+++ libsepol-1.5.9.new/include/sepol/context.h	2005-06-17 21:33:31.000000000 -0400
@@ -20,7 +20,6 @@
 #define _CONTEXT_H_
 
 #include <sepol/ebitmap.h>
-#include <sepol/sepol.h>
 #include <sepol/mls_types.h>
 
 /*
diff -Naur libsepol-1.5.9.orig/include/sepol/hashtab.h libsepol-1.5.9.new/include/sepol/hashtab.h
--- libsepol-1.5.9.orig/include/sepol/hashtab.h	2005-06-16 12:35:06.000000000 -0400
+++ libsepol-1.5.9.new/include/sepol/hashtab.h	2005-06-16 12:36:18.000000000 -0400
@@ -18,8 +18,8 @@
 #include <errno.h>
 #include <stdio.h>
 
-typedef char *hashtab_key_t;	/* generic key type */
-typedef void *hashtab_datum_t;	/* generic datum type */
+typedef char *hashtab_key_t;		/* generic key type */
+typedef void *hashtab_datum_t;		/* generic datum type */
 
 typedef struct hashtab_node *hashtab_ptr_t;
 
diff -Naur libsepol-1.5.9.orig/include/sepol/mls_types.h libsepol-1.5.9.new/include/sepol/mls_types.h
--- libsepol-1.5.9.orig/include/sepol/mls_types.h	2005-06-16 12:35:07.000000000 -0400
+++ libsepol-1.5.9.new/include/sepol/mls_types.h	2005-06-17 21:34:21.000000000 -0400
@@ -19,7 +19,6 @@
 
 #include <stdint.h>
 #include <sepol/ebitmap.h>
-#include <sepol/sepol.h>
 #include <sepol/flask_types.h>
 
 typedef struct mls_level {
diff -Naur libsepol-1.5.9.orig/include/sepol/policydb.h libsepol-1.5.9.new/include/sepol/policydb.h
--- libsepol-1.5.9.orig/include/sepol/policydb.h	2005-06-16 12:35:06.000000000 -0400
+++ libsepol-1.5.9.new/include/sepol/policydb.h	2005-06-17 21:08:35.000000000 -0400
@@ -289,6 +289,10 @@
 
 extern int policydb_write(struct policydb *p, struct policy_file *pf);
 
+extern int policydb_from_image(void* data, size_t len, policydb_t* policydb);
+
+extern int policydb_to_image(policydb_t* policydb, void **newdata, size_t *newlen);
+
 #define PERM_SYMTAB_SIZE 32
 
 /* Identify specific policy version changes */
diff -Naur libsepol-1.5.9.orig/include/sepol/sepol.h libsepol-1.5.9.new/include/sepol/sepol.h
--- libsepol-1.5.9.orig/include/sepol/sepol.h	2005-06-16 12:35:07.000000000 -0400
+++ libsepol-1.5.9.new/include/sepol/sepol.h	2005-06-19 00:57:33.000000000 -0400
@@ -3,6 +3,16 @@
 
 #include <sys/types.h>
 #include <stdio.h>
+#include <stdarg.h>
+
+/* Draw in extra headers that should be visible from outside */
+
+#include <sepol/policydb.h>
+#include <sepol/booleans.h>
+#include <sepol/users_policy.h>
+#include <sepol/users_file.h>
+
+/*==== Backwards Compatibility definitions ==== */
 
 /* Given an existing binary policy (starting at 'data', with length 'len')
    and a boolean configuration file named by 'boolpath', rewrite the binary
@@ -16,20 +26,39 @@
    with 'nel' elements, rewrite the binary policy for the boolean settings.  
    The binary policy is rewritten in place in memory.
    Returns 0 upon success or -1 otherwise. */
-extern int sepol_genbools_array(void *data, size_t len, char **names, int *values, int nel);
+extern int sepol_genbools_array(
+	void *data, size_t len, 
+	char **names, int *values, int nel);
 
 /* Given an existing binary policy (starting at 'data with length 'len')
    and user configurations living in 'usersdir', generate a new binary
    policy for the new user configurations.  Sets '*newdata' and '*newlen'
    to refer to the new binary policy image. */
-extern int sepol_genusers(void *data, size_t len,
-			  const char *usersdir,
-			  void **newdata, size_t *newlen);
+extern int sepol_genusers(
+	void *data, size_t len, 
+	const char *usersdir,
+	void **newdata, size_t *newlen);
+
+static inline int sepol_genbools_policydb(
+	policydb_t* policydb, char *boolpath) {
+
+	return sepol_load_booleans(policydb, boolpath);
+}
+
+static inline int sepol_genusers_policydb( 
+	policydb_t* policydb, const char* usersdir) {
+
+	return sepol_load_users_file(policydb, usersdir);
+}
 
 /* Enable or disable deletion of users by sepol_genusers(3) when
    a user in original binary policy image is not defined by the
    new user configurations.  Defaults to disabled. */
-extern void sepol_set_delusers(int on);
+static inline void sepol_set_delusers(int on) {
+	sepol_set_delusers_policy(on);
+}
+
+/* ==== End backwards compatibility ==== */
 
 /* Set internal policydb from a file for subsequent service calls. */
 extern int sepol_set_policydb_from_file(FILE *fp);
@@ -39,4 +68,5 @@
 
 /* Turn on or off sepol error messages. */
 extern void sepol_debug(int on);
+
 #endif
diff -Naur libsepol-1.5.9.orig/include/sepol/services.h libsepol-1.5.9.new/include/sepol/services.h
--- libsepol-1.5.9.orig/include/sepol/services.h	2005-06-16 12:35:08.000000000 -0400
+++ libsepol-1.5.9.new/include/sepol/services.h	2005-06-18 00:50:28.000000000 -0400
@@ -25,13 +25,6 @@
 extern int sepol_set_policydb(policydb_t *p);
 extern int sepol_set_sidtab(sidtab_t *s);
 
-/* Modify a policydb for boolean settings. */
-int sepol_genbools_policydb(policydb_t *policydb, const char *booleans);
-
-/* Modify a policydb for user settings. */
-int sepol_genusers_policydb(policydb_t *policydb,
-			    const char *usersdir);
-
 /* Load the security policy. This initializes the policydb
    and sidtab based on the provided binary policy. */
 int sepol_load_policy(void * data, size_t len);
diff -Naur libsepol-1.5.9.orig/include/sepol/user_config.h libsepol-1.5.9.new/include/sepol/user_config.h
--- libsepol-1.5.9.orig/include/sepol/user_config.h	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/include/sepol/user_config.h	2005-06-16 12:36:21.000000000 -0400
@@ -0,0 +1,90 @@
+#ifndef __SEPOL_USER_CONFIG_H
+#define __SEPOL_USER_CONFIG_H 
+
+#include <string.h>
+
+typedef struct user_config* user_config_t;
+
+struct role {
+	char* role;
+	struct role* next;
+};
+
+struct user_config {
+	/* This user's name */
+	char* name;
+
+	/* This user's mls level (only required for mls) */
+	char* mls_level;
+
+	/* This user's mls range (only required for mls) */
+	char* mls_range;
+
+	/* The number of roles */
+	int num_roles;
+
+	/* The default role */
+	struct role* def_role;
+
+	/* All roles (num_roles of them) */
+	struct role* roles;
+
+	/* Focus role (for iterator) */
+	struct role* next_role;
+};
+
+/* Name */
+static inline const char* uc_get_name(user_config_t user) {
+	return user->name;
+}
+
+static inline int uc_set_name(user_config_t user, const char* name) {
+	user->name = strdup(name);
+	return (user->name)? 0:-1;
+}
+
+/* MLS */
+static inline const char* uc_get_mls_level(user_config_t user) {
+	return user->mls_level;
+}
+
+static inline int uc_set_mls_level(user_config_t user, const char* mls_level) {
+	user->mls_level = strdup(mls_level);
+	return (user->mls_level)? 0:-1;
+}
+
+static inline const char* uc_get_mls_range(user_config_t user) {
+	return user->mls_range;
+}
+
+static inline int uc_set_mls_range(user_config_t user, const char* mls_range) {
+	user->mls_range = strdup(mls_range);
+	return (user->mls_range)? 0:-1;
+}
+
+/* Roles */
+static inline int uc_get_num_roles(user_config_t user) {
+	return user->num_roles;
+}
+
+static inline const char* uc_get_def_role(user_config_t user) {
+	return (user->def_role == NULL)? NULL : user->def_role->role;
+}
+
+extern int uc_add_role(user_config_t user, const char* role);
+extern int uc_del_role(user_config_t user, const char* role);
+extern int uc_has_role(user_config_t user, const char* role);
+extern int uc_set_def_role(user_config_t user, const char* role);
+extern int uc_reset_roles(user_config_t user);
+
+/* Iterator */
+static inline void uc_iter_init(user_config_t user) {
+	user->next_role = user->roles;
+}
+extern const char* uc_next_role(user_config_t user);
+
+/* Create/Destroy */
+extern user_config_t uc_create();
+extern void uc_destroy(user_config_t user);
+
+#endif
diff -Naur libsepol-1.5.9.orig/include/sepol/users_file.h libsepol-1.5.9.new/include/sepol/users_file.h
--- libsepol-1.5.9.orig/include/sepol/users_file.h	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/include/sepol/users_file.h	2005-06-19 00:29:04.000000000 -0400
@@ -0,0 +1,39 @@
+#ifndef _SEPOL_USERS_FILE_H
+#define _SEPOL_USERS_FILE_H
+
+#include <sepol/user_config.h>
+#include <sepol/policydb.h>
+
+extern int sepol_load_users_file(
+	policydb_t* policydb,
+	const char* usersdir);
+
+extern int sepol_add_user_file(
+	policydb_t* policydb,
+	const char* usersdir,
+	user_config_t user);
+
+extern int sepol_del_user_file(
+	policydb_t* policydb,
+	const char* usersdir,
+	const char* username);
+
+extern int sepol_set_roles_file(
+	policydb_t* policydb,
+	const char* usersdir,
+	const char* username,
+	const char** roles);
+
+extern int sepol_add_role_file(
+	policydb_t* policydb,
+	const char* usersdir,
+	const char* username,
+	const char* role);
+
+extern int sepol_del_role_file(
+	policydb_t* policydb,
+	const char* usersdir,
+	const char* username,
+	const char* role);
+
+#endif
diff -Naur libsepol-1.5.9.orig/include/sepol/users_policy.h libsepol-1.5.9.new/include/sepol/users_policy.h
--- libsepol-1.5.9.orig/include/sepol/users_policy.h	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/include/sepol/users_policy.h	2005-06-19 00:52:34.000000000 -0400
@@ -0,0 +1,18 @@
+#ifndef __SEPOL_USERS_INTERNAL_H
+#define __SEPOL_USERS_INTERNAL_H
+
+#include <sepol/policydb.h>
+#include <sepol/user_config.h>
+
+/* Del users */
+extern void sepol_set_delusers_policy(int on);
+
+/* Clear unused users (before reloading policy */
+void sepol_clear_users_policy(policydb_t *policydb);
+
+/* Add/delete/load users from the policy */
+extern int sepol_add_user_policy(policydb_t *policydb, user_config_t user);
+extern int sepol_del_user_policy(policydb_t *policydb, const char *username);
+extern int sepol_load_user_policy(policydb_t *policydb, user_config_t user);
+
+#endif
diff -Naur libsepol-1.5.9.orig/src/booleans.c libsepol-1.5.9.new/src/booleans.c
--- libsepol-1.5.9.orig/src/booleans.c	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/src/booleans.c	2005-06-18 00:04:54.000000000 -0400
@@ -0,0 +1,172 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <sepol/hashtab.h>
+#include <sepol/policydb.h>
+#include <sepol/conditional.h>
+
+#include "private.h"
+
+static char *strtrim(char *dest, char *source, int size) {
+	int i=0;
+	char *ptr=source;
+	i=0;
+	while(isspace(*ptr) && i < size) {
+		ptr++;
+		i++;
+	}
+	strncpy(dest,ptr,size);
+	for(i=strlen(dest)-1; i> 0; i--) {
+		if (!isspace(dest[i])) break;
+	}
+	dest[i+1]='\0';
+	return dest;
+}
+
+static int process_boolean(char *buffer, char *name, int namesize, int *val) {
+	char name1[BUFSIZ];
+	char *ptr;
+	char *tok=strtok_r(buffer,"=",&ptr);
+	if (tok) {
+		strncpy(name1,tok, BUFSIZ-1);
+		strtrim(name,name1,namesize-1);
+		if ( name[0]=='#' ) return 0;
+		tok=strtok_r(NULL,"\0",&ptr);
+		if (tok) {
+			while (isspace(*tok)) tok++;
+			*val = -1;
+			if (isdigit(tok[0]))
+				*val=atoi(tok);
+			else if (!strncasecmp(tok, "true", sizeof("true")-1))
+				*val = 1;
+			else if (!strncasecmp(tok, "false", sizeof("false")-1))
+				*val = 0;
+			if (*val != 0 && *val != 1) {
+				fprintf(stderr,"illegal value for boolean "
+					"%s=%s\n", name, tok);
+				return -1;
+			}
+			
+		}
+	}
+	return 1;
+}
+
+static int load_booleans(struct policydb *policydb, const char *path) {
+	FILE *boolf;
+	char *buffer=NULL;
+	size_t size=0;
+	char localbools[BUFSIZ];
+	char name[BUFSIZ];
+	int val;
+	int errors=0;
+	struct cond_bool_datum *datum;
+
+	boolf = fopen(path,"r");
+	if (boolf == NULL) 
+		goto localbool;
+
+	while (getline(&buffer, &size, boolf) > 0) {
+		int ret=process_boolean(buffer, name, sizeof(name), &val);
+		if (ret==-1) 
+			errors++;
+		if (ret==1) {
+			datum = hashtab_search(policydb->p_bools.table, name);
+			if (!datum) {
+				fprintf(stderr,"unknown boolean %s\n", name);
+				errors++;
+				continue;
+			}
+			datum->state = val;
+		}
+	}
+	fclose(boolf);
+localbool:
+	snprintf(localbools,sizeof(localbools), "%s.local", path);
+	boolf = fopen(localbools,"r");
+	if (boolf != NULL) {
+		while (getline(&buffer, &size, boolf) > 0) {
+			int ret = process_boolean(buffer, name, 
+				sizeof(name), &val);
+			if (ret == -1) 
+				errors++;
+			if (ret == 1) {
+				datum = hashtab_search(
+					policydb->p_bools.table, name);
+				if (!datum) {
+					fprintf(stderr,
+						"unknown boolean %s\n", name);
+					errors++;
+					continue;
+				}
+				datum->state = val;
+			}
+		}
+		fclose(boolf);
+	}
+	free(buffer);
+	if (errors)
+		errno = EINVAL;
+
+	return errors ? SEPOL_ERR : SEPOL_SUCCESS;
+}
+
+int sepol_load_booleans(policydb_t* policydb, const char *boolpath) {
+
+	if (load_booleans(policydb, boolpath) < 0)
+		__sepol_debug_printf("%s:  Warning! Error while reading %s\n",
+			__FUNCTION__, boolpath);
+
+	if (evaluate_conds(policydb) < 0) {
+		__sepol_debug_printf("%s:  Error while re-evaluating "
+                        "conditionals\n", __FUNCTION__);
+		errno = EINVAL;
+		return SEPOL_ERR;
+        }
+
+	return SEPOL_SUCCESS;
+}
+
+
+int sepol_load_booleans_array(
+	policydb_t* policydb, char **names, 
+	int *values, int nel) {
+		
+	int i, errors = 0;
+	struct cond_bool_datum *datum;
+
+	for (i = 0; i < nel; i++) {
+		datum = hashtab_search(policydb->p_bools.table, names[i]);
+		if (!datum) {
+			__sepol_debug_printf("%s:  unknown boolean %s\n",
+				__FUNCTION__, names[i]);
+			errors++;
+			continue;
+		}
+		if (values[i] != 0 && values[i] != 1) {
+			__sepol_debug_printf("%s: illegal value %d "
+			"for boolean %s\n", __FUNCTION__,values[i], names[i]);
+			errors++;
+			continue;
+		}
+		datum->state = values[i];
+	}
+
+	if (evaluate_conds(policydb) < 0) {
+		__sepol_debug_printf("%s:  Error while re-evaluating "
+			"conditionals\n", __FUNCTION__);
+		errno = EINVAL;
+		goto err;
+	}
+
+	if (errors) {
+		errno = EINVAL;
+		goto err;
+	}
+
+	return SEPOL_SUCCESS;
+	err:
+	return SEPOL_ERR;
+}
diff -Naur libsepol-1.5.9.orig/src/compatibility.c libsepol-1.5.9.new/src/compatibility.c
--- libsepol-1.5.9.orig/src/compatibility.c	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/src/compatibility.c	2005-06-19 00:36:46.000000000 -0400
@@ -0,0 +1,87 @@
+#include <stdlib.h>
+#include <string.h>
+#include <sepol/policydb.h>
+#include <sepol/users_file.h>
+#include <sepol/booleans.h>
+
+#include "private.h"
+
+/* Compatibility */
+int sepol_genusers(void *data, size_t len,
+                   const char *usersdir,
+                   void **new_data, size_t *new_len) {
+
+	struct policydb policydb;
+
+	if (policydb_from_image(data, len, &policydb) < 0)
+		return SEPOL_ERR;
+
+	if (sepol_load_users_file(&policydb, usersdir) < 0)
+		goto err;
+
+        if (policydb_to_image(&policydb, new_data, new_len) < 0) 
+		goto err;
+
+	policydb_destroy(&policydb);
+        return SEPOL_SUCCESS;
+
+	err:
+	policydb_destroy(&policydb);
+	return SEPOL_ERR;
+}
+
+int sepol_genbools(void *data, size_t len, char *booleans) {
+
+	struct policydb policydb;
+	void* new_data;
+	size_t new_len;
+
+	if (policydb_from_image(data, len, &policydb) < 0)
+		return SEPOL_ERR;
+
+	if (sepol_load_booleans(&policydb, booleans) < 0)
+		goto err;
+
+	if (policydb_to_image(&policydb, &new_data, &new_len) < 0)
+		goto err;
+
+	memcpy(data, new_data, len);
+
+	free(new_data);
+	policydb_destroy(&policydb);
+	return SEPOL_SUCCESS;
+
+        err:
+	free(new_data);
+        policydb_destroy(&policydb);
+        return SEPOL_ERR;
+}
+
+int sepol_genbools_array(
+		void *data, size_t len, 
+		char **names, int *values, int nel)
+{
+	struct policydb policydb;
+	void* new_data;
+	size_t new_len;
+
+	if (policydb_from_image(data, len, &policydb) < 0)
+		return SEPOL_ERR;
+
+	if (sepol_load_booleans_array(&policydb, names, values, nel) < 0)
+		goto err;
+
+	if (policydb_to_image(&policydb, &new_data, &new_len) < 0)
+		goto err;
+	
+	memcpy(data, new_data, len);		
+
+	free(new_data);
+	policydb_destroy(&policydb);
+	return SEPOL_SUCCESS;
+
+	err:
+	free(new_data);
+	policydb_destroy(&policydb);
+	return SEPOL_ERR;
+}
diff -Naur libsepol-1.5.9.orig/src/debug.c libsepol-1.5.9.new/src/debug.c
--- libsepol-1.5.9.orig/src/debug.c	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/src/debug.c	2005-06-19 21:47:29.000000000 -0400
@@ -0,0 +1,18 @@
+#include <stdarg.h>
+#include <stdio.h>
+
+static int gdebug = 1;
+
+void sepol_debug(int on) {
+	gdebug = on;
+}
+
+__attribute__ ((format (printf, 1, 2))) 
+void __sepol_debug_printf(const char *fmt, ...) {
+	if (gdebug) {
+		va_list ap;
+		va_start(ap, fmt);
+		vfprintf (stderr, fmt, ap);
+		va_end(ap);
+	}
+}
diff -Naur libsepol-1.5.9.orig/src/genbools.c libsepol-1.5.9.new/src/genbools.c
--- libsepol-1.5.9.orig/src/genbools.c	2005-06-16 12:35:12.000000000 -0400
+++ libsepol-1.5.9.new/src/genbools.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,238 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include <sepol/policydb.h>
-#include <sepol/conditional.h>
-
-#include "private.h"
-
-static char *strtrim(char *dest, char *source, int size) {
-	int i=0;
-	char *ptr=source;
-	i=0;
-	while(isspace(*ptr) && i < size) {
-		ptr++;
-		i++;
-	}
-	strncpy(dest,ptr,size);
-	for(i=strlen(dest)-1; i> 0; i--) {
-		if (!isspace(dest[i])) break;
-	}
-	dest[i+1]='\0';
-	return dest;
-}
-
-static int process_boolean(char *buffer, char *name, int namesize, int *val) {
-	char name1[BUFSIZ];
-	char *ptr;
-	char *tok=strtok_r(buffer,"=",&ptr);
-	if (tok) {
-		strncpy(name1,tok, BUFSIZ-1);
-		strtrim(name,name1,namesize-1);
-		if ( name[0]=='#' ) return 0;
-		tok=strtok_r(NULL,"\0",&ptr);
-		if (tok) {
-			while (isspace(*tok)) tok++;
-			*val = -1;
-			if (isdigit(tok[0]))
-				*val=atoi(tok);
-			else if (!strncasecmp(tok, "true", sizeof("true")-1))
-				*val = 1;
-			else if (!strncasecmp(tok, "false", sizeof("false")-1))
-				*val = 0;
-			if (*val != 0 && *val != 1) {
-				fprintf(stderr,"illegal value for boolean %s=%s\n", name, tok);
-				return -1;
-			}
-			
-		}
-	}
-	return 1;
-}
-
-static int load_booleans(struct policydb *policydb, const char *path) {
-	FILE *boolf;
-	char *buffer=NULL;
-	size_t size=0;
-	char localbools[BUFSIZ];
-	char name[BUFSIZ];
-	int val;
-	int errors=0;
-	struct cond_bool_datum *datum;
-
-	boolf = fopen(path,"r");
-	if (boolf == NULL) 
-		goto localbool;
-
-	while (getline(&buffer, &size, boolf) > 0) {
-		int ret=process_boolean(buffer, name, sizeof(name), &val);
-		if (ret==-1) 
-			errors++;
-		if (ret==1) {
-			datum = hashtab_search(policydb->p_bools.table, name);
-			if (!datum) {
-				fprintf(stderr,"unknown boolean %s\n", name);
-				errors++;
-				continue;
-			}
-			datum->state = val;
-		}
-	}
-	fclose(boolf);
-localbool:
-	snprintf(localbools,sizeof(localbools), "%s.local", path);
-	boolf = fopen(localbools,"r");
-	if (boolf != NULL) {
-		while (getline(&buffer, &size, boolf) > 0) {
-			int ret=process_boolean(buffer, name, sizeof(name), &val);
-			if (ret==-1) 
-				errors++;
-			if (ret==1) {
-				datum = hashtab_search(policydb->p_bools.table, name);
-				if (!datum) {
-					fprintf(stderr,"unknown boolean %s\n", name);
-					errors++;
-					continue;
-				}
-				datum->state = val;
-			}
-		}
-		fclose(boolf);
-	}
-	free(buffer);
-	if (errors)
-		errno = EINVAL;
-
-	return errors ? -1 : 0;
-}
-
-int sepol_genbools(void *data, size_t len, char *booleans)
-{
-	struct policydb policydb;
-	struct policy_file pf;
-	int rc;
-
-	pf.type = PF_USE_MEMORY;
-	pf.data = data;
-	pf.len = len;
-	if (policydb_read(&policydb,&pf, 0)) {
-		__sepol_debug_printf("%s:  binary policy image is invalid\n",
-			__FUNCTION__);
-		errno = EINVAL;
-		return -1;
-	}
-
-	/* Preserve the policy version of the original policy
-	   for the new policy. */
-	sepol_set_policyvers(policydb.policyvers);
-
-	if (load_booleans(&policydb, booleans) < 0) {
-		__sepol_debug_printf("%s:  Warning!  Error while reading %s\n",
-				     __FUNCTION__, booleans);
-	}
-
-	if (evaluate_conds(&policydb) < 0) {
-		__sepol_debug_printf("%s:  Error while re-evaluating conditionals\n",
-				     __FUNCTION__);
-		errno = EINVAL;
-		goto err;
-	}
-
-	pf.data = data;
-	pf.len = len;
-	rc = policydb_write(&policydb, &pf);
-	if (rc) {
-		__sepol_debug_printf("%s: Can't write new binary policy image\n",
-				     __FUNCTION__);
-		errno = EINVAL;
-		goto err;
-	}
-
-	policydb_destroy(&policydb);
-	return 0;
-
- err:
-	policydb_destroy(&policydb);
-	return -1;
-}
-
-int sepol_genbools_policydb(policydb_t *policydb, const char *booleans)
-{
-	int rc;
-
-	rc = load_booleans(policydb, booleans);
-	if (!rc)
-		rc = evaluate_conds(policydb);
-	if (rc)
-		errno = EINVAL;
-	return rc;
-}
-
-int sepol_genbools_array(void *data, size_t len, char **names, int *values, int nel)
-{
-	struct policydb policydb;
-	struct policy_file pf;
-	int rc, i, errors = 0;
-	struct cond_bool_datum *datum;
-
-	pf.type = PF_USE_MEMORY;
-	pf.data = data;
-	pf.len = len;
-	if (policydb_read(&policydb,&pf, 0)) {
-		__sepol_debug_printf("%s:  binary policy image is invalid\n",
-				     __FUNCTION__);
-		errno = EINVAL;
-		return -1;
-	}
-
-	/* Preserve the policy version of the original policy
-	   for the new policy. */
-	sepol_set_policyvers(policydb.policyvers);
-
-	for (i = 0; i < nel; i++) {
-		datum = hashtab_search(policydb.p_bools.table, names[i]);
-		if (!datum) {
-			__sepol_debug_printf("%s:  unknown boolean %s\n", 
-					     __FUNCTION__, names[i]);
-			errors++;
-			continue;
-		}
-		if (values[i] != 0 && values[i] != 1) {
-			fprintf(stderr,"illegal value %d for boolean %s\n", values[i], names[i]);
-			errors++;
-			continue;
-		}
-		datum->state = values[i];
-	}
-
-	if (evaluate_conds(&policydb) < 0) {
-		__sepol_debug_printf("%s:  Error while re-evaluating conditionals\n",
-				     __FUNCTION__);
-		errno = EINVAL;
-		goto err;
-	}
-
-	pf.data = data;
-	pf.len = len;
-	rc = policydb_write(&policydb, &pf);
-	if (rc) {
-		__sepol_debug_printf("%s:  Can't write binary policy\n",
-				     __FUNCTION__);
-		errno = EINVAL;
-		goto err;
-	}
-	if (errors) {
-		errno = EINVAL;
-		goto err;
-	}
-
-	policydb_destroy(&policydb);
-	return 0;
-err:
-	policydb_destroy(&policydb);
-	return -1;
-}
-
-
diff -Naur libsepol-1.5.9.orig/src/genbools.c.~1.8.~ libsepol-1.5.9.new/src/genbools.c.~1.8.~
--- libsepol-1.5.9.orig/src/genbools.c.~1.8.~	2005-06-16 12:35:12.000000000 -0400
+++ libsepol-1.5.9.new/src/genbools.c.~1.8.~	1969-12-31 19:00:00.000000000 -0500
@@ -1,177 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include <sepol/policydb.h>
-#include <sepol/conditional.h>
-
-#include "private.h"
-
-static char *strtrim(char *dest, char *source, int size) {
-	int i=0;
-	char *ptr=source;
-	i=0;
-	while(isspace(*ptr) && i < size) {
-		ptr++;
-		i++;
-	}
-	strncpy(dest,ptr,size);
-	for(i=strlen(dest)-1; i> 0; i--) {
-		if (!isspace(dest[i])) break;
-	}
-	dest[i+1]='\0';
-	return dest;
-}
-
-static int load_booleans(struct policydb *policydb, char *path) {
-	FILE *boolf;
-	char buffer[BUFSIZ];
-	char name[BUFSIZ];
-	char name1[BUFSIZ];
-	int val;
-	int errors=0;
-	struct cond_bool_datum *datum;
-
-	boolf = fopen(path,"r");
-	if (boolf == NULL) 
-		return -1;
-
-        while (fgets(buffer, sizeof(buffer), boolf)) {
-		char *tok=strtok(buffer,"=");
-		if (tok) {
-			strncpy(name1,tok, BUFSIZ-1);
-			strtrim(name,name1,BUFSIZ-1);
-			if ( name[0]=='#' ) continue;
-			tok=strtok(NULL,"\0");
-			if (tok) {
-				while (isspace(*tok)) tok++;
-				val = -1;
-				if (isdigit(tok[0]))
-					val=atoi(tok);
-				else if (!strncasecmp(tok, "true", sizeof("true")-1))
-					val = 1;
-				else if (!strncasecmp(tok, "false", sizeof("false")-1))
-					val = 0;
-				if (val != 0 && val != 1) {
-					fprintf(stderr,"illegal value for boolean %s=%s\n", name, tok);
-					errors++;
-					continue;
-				}
-
-				datum = hashtab_search(policydb->p_bools.table, name);
-				if (!datum) {
-					fprintf(stderr,"unknown boolean %s\n", name);
-					errors++;
-					continue;
-				}
-				datum->state = val;
-			}
-		}
-	}
-	fclose(boolf);
-
-	if (errors)
-		errno = EINVAL;
-
-	return errors ? -1 : 0;
-}
-
-int sepol_genbools(void *data, size_t len, char *booleans)
-{
-	struct policydb policydb;
-	struct policy_file pf;
-	int rc;
-
-	pf.type = PF_USE_MEMORY;
-	pf.data = data;
-	pf.len = len;
-	if (policydb_read(&policydb,&pf, 0)) {
-		fprintf(stderr, "Can't read binary policy:  %s\n",
-			strerror(errno));
-		return -1;
-	}
-
-	/* Preserve the policy version of the original policy
-	   for the new policy. */
-	sepol_set_policyvers(policydb.policyvers);
-
-	if (load_booleans(&policydb, booleans) < 0) {
-		fprintf(stderr, "Warning!  Error while reading %s:  %s\n",
-			booleans, strerror(errno));
-	}
-
-	if (evaluate_conds(&policydb) < 0) {
-		fprintf(stderr, "Error while re-evaluating conditionals: %s\n",
-			strerror(errno));
-		return -1;
-	}
-
-	pf.data = data;
-	pf.len = len;
-	rc = policydb_write(&policydb, &pf);
-	if (rc) {
-		fprintf(stderr, "Can't write binary policy:  %s\n",
-			strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-int sepol_genbools_array(void *data, size_t len, char **names, int *values, int nel)
-{
-	struct policydb policydb;
-	struct policy_file pf;
-	int rc, i, errors = 0;
-	struct cond_bool_datum *datum;
-
-	pf.type = PF_USE_MEMORY;
-	pf.data = data;
-	pf.len = len;
-	if (policydb_read(&policydb,&pf, 0)) {
-		fprintf(stderr, "Can't read binary policy:  %s\n",
-			strerror(errno));
-		return -1;
-	}
-
-	/* Preserve the policy version of the original policy
-	   for the new policy. */
-	sepol_set_policyvers(policydb.policyvers);
-
-	for (i = 0; i < nel; i++) {
-		datum = hashtab_search(policydb.p_bools.table, names[i]);
-		if (!datum) {
-			fprintf(stderr,"unknown boolean %s\n", names[i]);
-			errors++;
-			continue;
-		}
-		if (values[i] != 0 && values[i] != 1) {
-			fprintf(stderr,"illegal value %d for boolean %s\n", values[i], names[i]);
-			errors++;
-			continue;
-		}
-		datum->state = values[i];
-	}
-
-	if (evaluate_conds(&policydb) < 0) {
-		fprintf(stderr, "Error while re-evaluating conditionals: %s\n",
-			strerror(errno));
-		return -1;
-	}
-
-	pf.data = data;
-	pf.len = len;
-	rc = policydb_write(&policydb, &pf);
-	if (rc) {
-		fprintf(stderr, "Can't write binary policy:  %s\n",
-			strerror(errno));
-		return -1;
-	}
-	if (errors) {
-		errno = EINVAL;
-		return -1;
-	}
-	return 0;
-}
-
-
diff -Naur libsepol-1.5.9.orig/src/genusers.c libsepol-1.5.9.new/src/genusers.c
--- libsepol-1.5.9.orig/src/genusers.c	2005-06-16 12:35:11.000000000 -0400
+++ libsepol-1.5.9.new/src/genusers.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,477 +0,0 @@
-#include <stdio.h>
-#include <stdio_ext.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-
-#include <sepol/policydb.h>
-#include <sepol/mls.h>
-#include <stdarg.h>
-
-#include "private.h"
-
-static int gdebug=1;
-
-void sepol_debug(int on) { gdebug=on; };
-
-void __sepol_debug_printf(const char *fmt, ...) {
-	if (gdebug) {
-		va_list ap;
-		va_start(ap, fmt);
-		vfprintf (stderr, fmt, ap);
-		va_end(ap);
-	}
-}
-
-static int delusers = 0;
-
-void sepol_set_delusers(int on)
-{
-	delusers = on;
-}
-
-#undef BADLINE
-#define BADLINE() { \
-	__sepol_debug_printf("%s:  invalid entry %s on line %u\n", \
-		path, buffer, lineno); \
-	continue; \
-}
-
-static int load_users(struct policydb *policydb, const char *path) {
-	FILE *fp;
-	char *buffer = NULL, *p, *q, oldc;
-	size_t len = 0;
-	int rc;
-	unsigned lineno = 0, islist = 0, bit;
-	user_datum_t *usrdatum;
-	role_datum_t *roldatum;
-
-	fp = fopen(path,"r");
-	if (fp == NULL) 
-		return -1;
-	__fsetlocking(fp, FSETLOCKING_BYCALLER);
-
-        while (getline(&buffer, &len, fp) > 0) {
-		lineno++;
-		if (buffer[len - 1] == '\n')
-			buffer[len - 1] = 0;
-		p = buffer;
-		while (*p && isspace(*p))
-			p++;
-		if (!(*p) || *p == '#')
-			continue;
-
-		if (strncasecmp(p, "user", 4))
-			BADLINE();
-		p += 4;
-		if (!isspace(*p))
-			BADLINE();
-		while (*p && isspace(*p))
-			p++;
-		if (!(*p))
-			BADLINE();
-		q = p;
-		while (*p && !isspace(*p)) 
-			p++;
-		if (!(*p)) 
-			BADLINE();
-		*p++ = 0;
-
-		usrdatum = hashtab_search(policydb->p_users.table, q);
-		if (usrdatum) {
-			/* Replacing an existing user definition. */
-			ebitmap_init(&usrdatum->roles);
-			usrdatum->defined = 1;
-		} else {
-			char *id = strdup(q);
-			
-			/* Adding a new user definition. */
-			usrdatum = (user_datum_t *) malloc(sizeof(user_datum_t));
-			if (!id || !usrdatum) {
-				__sepol_debug_printf("%s:  out of memory for %s on line %u\n",
-					path, buffer, lineno);
-				errno = ENOMEM;
-				free(buffer);
-				fclose(fp);
-				return -1;
-			}
-			memset(usrdatum, 0, sizeof(user_datum_t));
-			usrdatum->value = ++policydb->p_users.nprim;
-			ebitmap_init(&usrdatum->roles);
-			usrdatum->defined = 1;
-			rc = hashtab_insert(policydb->p_users.table,
-					    id, (hashtab_datum_t) usrdatum);
-			if (rc) {
-				__sepol_debug_printf("%s:  out of memory for %s on line %u\n",
-					path, buffer, lineno);
-				errno = ENOMEM;
-				free(buffer);
-				fclose(fp);
-				return -1;
-			}
-		}
-
-		while (*p && isspace(*p))
-			p++;
-		if (!(*p))
-			BADLINE();
-		if (strncasecmp(p, "roles", 5))
-			BADLINE();
-		p += 5;
-		if (!isspace(*p))
-			BADLINE();
-		while (*p && isspace(*p))
-			p++;
-		if (!(*p))
-			BADLINE();
-		if (*p == '{') {
-			islist = 1;
-			p++;
-		} else 
-			islist = 0;
-
-		do { 
-			while (*p && isspace(*p))
-				p++;
-			if (!(*p))
-				BADLINE();
-
-			q = p;
-			while (*p && *p != ';' && *p != '}' && !isspace(*p)) 
-				p++;
-			if (!(*p)) 
-				BADLINE();
-			if (*p == '}') 
-				islist = 0;
-			oldc = *p;
-			*p++ = 0;
-			if (!q[0])
-				break;
-
-			roldatum = hashtab_search(policydb->p_roles.table, q);
-			if (!roldatum) {
-				__sepol_debug_printf("%s:  undefined role %s in %s on line %u\n",
-					path, q, buffer, lineno);
-				continue;
-			}
-			/* Set the role and every role it dominates */
-			for (bit = ebitmap_startbit(&roldatum->dominates); bit < ebitmap_length(&roldatum->dominates); bit++) {
-				if (ebitmap_get_bit(&roldatum->dominates, bit))
-					if (ebitmap_set_bit(&usrdatum->roles, bit, 1)) {
-						__sepol_debug_printf("%s:  out of memory for %s on line %u\n",
-							path, buffer, lineno);
-						errno = ENOMEM;
-						free(buffer);
-						fclose(fp);
-						return -1;
-					}
-			}
-		} while (islist);
-
-		if (mls_enabled) {
-			context_struct_t context;
-			char *scontext, *r, *s;
-
-			while (*p && isspace(*p))
-				p++;
-			if (!(*p))
-				BADLINE();
-			if (strncasecmp(p, "level", 5))
-				BADLINE();
-			p += 5;
-			if (!isspace(*p))
-				BADLINE();
-			while (*p && isspace(*p))
-				p++;
-			if (!(*p))
-				BADLINE();
-			q = p;
-			while (*p && strncasecmp(p, "range", 5))
-				p++;
-			if (!(*p)) 
-				BADLINE();
-			*--p = 0;
-			p++;
-
-			scontext = malloc(p - q);
-			if (!scontext) {
-				__sepol_debug_printf("%s:  out of memory for %s on line %u\n",
-					path, buffer, lineno);
-				errno = ENOMEM;
-				free(buffer);
-				fclose(fp);
-				return -1;
-			}
-			r = scontext;
-			s = q;
-			while (*s) {
-				if (!isspace(*s))
-					*r++ = *s;
-				s++;
-			}
-			*r = 0;
-			r = scontext;
-
-			context_init(&context);
-			rc = mls_context_to_sid(policydb, oldc, &r, &context);
-			if (rc) {
-				__sepol_debug_printf("%s:  invalid level %s in %s on line %u\n",
-					path, scontext, buffer, lineno);
-				free(scontext);
-				continue;
-
-			}
-			free(scontext);
-			memcpy(&usrdatum->dfltlevel, &context.range.level[0], sizeof(usrdatum->dfltlevel));
-
-			if (strncasecmp(p, "range", 5))
-				BADLINE();
-			p += 5;
-			if (!isspace(*p))
-				BADLINE();
-			while (*p && isspace(*p))
-				p++;
-			if (!(*p))
-				BADLINE();
-			q = p;
-			while (*p && *p != ';')
-				p++;
-			if (!(*p)) 
-				BADLINE();
-			*p++ = 0;
-
-			scontext = malloc(p - q);
-			if (!scontext) {
-				__sepol_debug_printf("%s:  out of memory for %s on line %u\n",
-					path, buffer, lineno);
-				errno = ENOMEM;
-				free(buffer);
-				fclose(fp);
-				return -1;
-			}
-			r = scontext;
-			s = q;
-			while (*s) {
-				if (!isspace(*s))
-					*r++ = *s;
-				s++;
-			}
-			*r = 0;
-			r = scontext;
-
-			context_init(&context);
-			rc = mls_context_to_sid(policydb, oldc, &r, &context);
-			if (rc) {
-				__sepol_debug_printf("%s:  invalid range %s in %s on line %u\n",
-					path, scontext, buffer, lineno);
-				free(scontext);
-				continue;
-			}
-			free(scontext);
-			memcpy(&usrdatum->range, &context.range, sizeof(usrdatum->range));
-		}
-	}
-
-	free(buffer);
-	fclose(fp);
-	return 0;
-}
-
-/* Select users for removal based on whether they were defined in the
-   new users configuration. */
-static int select_user(hashtab_key_t key, hashtab_datum_t datum, void *datap)
-{
-	user_datum_t *usrdatum = datum;
-	
-	if (!usrdatum->defined)
-		return 1;
-	return 0;
-}
-
-struct kill_user_data {
-	struct policydb *policydb;
-	ebitmap_t *free_users;
-};
-
-/* Kill the user entries selected by select_user, and
-   record that their slots are free. */
-static void kill_user(hashtab_key_t key, hashtab_datum_t datum, void *p)
-{
-	user_datum_t *usrdatum;
-	struct kill_user_data *kud = p;
-	struct policydb *pol = kud->policydb;
-	ebitmap_t *free_users = kud->free_users;
-
-	if (key)
-		free(key);
-
-	usrdatum = (user_datum_t *) datum;
-	ebitmap_set_bit(free_users, usrdatum->value - 1, 1);
-
-	ebitmap_destroy(&usrdatum->roles);
-	free(datum);
-	pol->p_users.nprim--;
-}
-
-/* Fold user values down to avoid holes generated by removal.
-   As the SID table is remapped by the kernel upon a policy reload,
-   this is safe for existing SIDs.  But it could be a problem for
-   constraints if they refer to the particular user.  */
-static int remap_users(hashtab_key_t key, hashtab_datum_t datum, void *p)
-{
-	user_datum_t *usrdatum = datum;
-	struct kill_user_data *kud = p;
-	struct policydb *pol = kud->policydb;
-	ebitmap_t *free_users = kud->free_users;
-	int i;
-
-	if (usrdatum->value > pol->p_users.nprim) {
-		for (i = ebitmap_startbit(free_users); i < ebitmap_length(free_users); i++) {
-			if (ebitmap_get_bit(free_users, i)) {
-				usrdatum->value = i+1;
-				ebitmap_set_bit(free_users, i, 0);
-				return 0;
-			}
-		}
-	}
-	return 0;
-}
-
-int sepol_genusers(void *data, size_t len,
-		   const char *usersdir,
-		   void **newdata, size_t *newlen)
-{
-	struct policydb policydb;
-	struct policy_file pf;
-	struct ebitmap free_users;
-	struct kill_user_data kud;
-	char path[PATH_MAX];
-	int rc;
-
-	/* Parse the original binary policy image into a struct policydb. */
-	pf.type = PF_USE_MEMORY;
-	pf.data = data;
-	pf.len = len;
-	if (policydb_read(&policydb,&pf, 0)) {
-		__sepol_debug_printf("%s:  binary policy image is invalid\n",
-				     __FUNCTION__);
-		errno = EINVAL;
-		return -1;
-	}
-
-	/* Load base set of system users from the policy package. */
-	snprintf(path, sizeof path, "%s/system.users", usersdir);
-	if (load_users(&policydb, path) < 0) {
-		__sepol_debug_printf("%s: Can't load system.users:  %s\n",
-				     __FUNCTION__, strerror(errno));
-		goto err;
-	}
-
-	/* Load locally defined users. */
-	snprintf(path, sizeof path, "%s/local.users", usersdir);
-	if (load_users(&policydb, path) < 0) {
-		__sepol_debug_printf("%s:  Can't load local.users:  %s\n",
-				     __FUNCTION__, strerror(errno));
-		goto err;
-	}
-
-	if (delusers) {
-		/* Kill unused users and remap to avoid holes. */
-		ebitmap_init(&free_users);
-		kud.policydb = &policydb;
-		kud.free_users = &free_users;
-		hashtab_map_remove_on_error(policydb.p_users.table, select_user, kill_user, &kud);
-		hashtab_map(policydb.p_users.table, remap_users, &kud);
-		ebitmap_destroy(&free_users);
-	}
-
-	/* Set the policy version for the new binary policy image we are
-	   about to generate so that it stays the same as the original,
-	   even if we support a newer one. */
-	sepol_set_policyvers(policydb.policyvers);
-
-	/* Compute the length for the new binary policy image. */
-	pf.type = PF_LEN;
-	pf.data = NULL;
-	pf.len = 0;
-	rc = policydb_write(&policydb, &pf);
-	if (rc) {
-		__sepol_debug_printf("%s: Can't compute length of binary policy\n",
-				     __FUNCTION__);
-		errno = EINVAL;
-		goto err;
-	}
-
-	/* Allocate the new binary policy image. */
-	pf.type = PF_USE_MEMORY;	
-	pf.data = malloc(pf.len);
-	if (!pf.data) {
-		__sepol_debug_printf("%s:  out of memory\n", __FUNCTION__);
-		goto err;
-	}
-
-	/* Need to save len and data prior to modification by policydb_write. */
-	*newlen = pf.len;
-	*newdata = pf.data;
-
-	/* Write out the new binary policy image. */
-	rc = policydb_write(&policydb, &pf);
-	if (rc) {
-		__sepol_debug_printf("%s:  Can't write binary policy\n",
-				     __FUNCTION__);
-		free(pf.data);
-		errno = EINVAL;
-		goto err;
-	}
-	policydb_destroy(&policydb);
-
-	/* Verify the new binary policy image. */
-	pf.type = PF_USE_MEMORY;
-	pf.data = *newdata;
-	pf.len = *newlen;
-	if (policydb_read(&policydb,&pf, 0)) {
-		__sepol_debug_printf("%s:  new binary policy image is invalid\n",
-				     __FUNCTION__);
-		errno = EINVAL;
-		return -1;
-	}
-
-	policydb_destroy(&policydb);
-	return 0;
-
-err:
-	policydb_destroy(&policydb);
-	return -1;
-}
-
-int sepol_genusers_policydb(policydb_t *policydb,
-			    const char *usersdir)
-{
-	char path[PATH_MAX];
-
-	/* Load base set of system users from the policy package. */
-	snprintf(path, sizeof path, "%s/system.users", usersdir);
-	if (load_users(policydb, path) < 0) {
-		__sepol_debug_printf("%s: Can't load system.users:  %s\n",
-				     __FUNCTION__, strerror(errno));
-		return -1;
-	}
-
-	/* Load locally defined users. */
-	snprintf(path, sizeof path, "%s/local.users", usersdir);
-	if (load_users(policydb, path) < 0) {
-		__sepol_debug_printf("%s:  Can't load local.users:  %s\n",
-				     __FUNCTION__, strerror(errno));
-		return -1;
-	}
-
-	if (policydb_reindex_users(policydb) < 0) {
-		__sepol_debug_printf("%s:  Can't reindex users:  %s\n",
-				     __FUNCTION__, strerror(errno));
-		return -1;
-
-	}
-
-	return 0;
-}
diff -Naur libsepol-1.5.9.orig/src/genusers.c.~1.2.~ libsepol-1.5.9.new/src/genusers.c.~1.2.~
--- libsepol-1.5.9.orig/src/genusers.c.~1.2.~	2005-06-16 12:35:12.000000000 -0400
+++ libsepol-1.5.9.new/src/genusers.c.~1.2.~	1969-12-31 19:00:00.000000000 -0500
@@ -1,404 +0,0 @@
-#include <stdio.h>
-#include <stdio_ext.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-
-#include <sepol/policydb.h>
-#include <sepol/mls.h>
-
-#include "private.h"
-
-#undef BADLINE
-#define BADLINE() { \
-	fprintf(stderr, "%s:  invalid entry %s on line %u\n", \
-		path, buffer, lineno); \
-	continue; \
-}
-
-static int load_users(struct policydb *policydb, const char *path) {
-	FILE *fp;
-	char *buffer = NULL, *p, *q, oldc;
-	size_t len = 0;
-	int rc;
-	unsigned lineno = 0, islist = 0, bit;
-	user_datum_t *usrdatum;
-	role_datum_t *roldatum;
-
-	fp = fopen(path,"r");
-	if (fp == NULL) 
-		return -1;
-	__fsetlocking(fp, FSETLOCKING_BYCALLER);
-
-        while (getline(&buffer, &len, fp) > 0) {
-		lineno++;
-		if (buffer[len - 1] == '\n')
-			buffer[len - 1] = 0;
-		p = buffer;
-		while (*p && isspace(*p))
-			p++;
-		if (!(*p) || *p == '#')
-			continue;
-
-		if (strncasecmp(p, "user", 4))
-			BADLINE();
-		p += 4;
-		if (!isspace(*p))
-			BADLINE();
-		while (*p && isspace(*p))
-			p++;
-		if (!(*p))
-			BADLINE();
-		q = p;
-		while (*p && !isspace(*p)) 
-			p++;
-		if (!(*p)) 
-			BADLINE();
-		*p++ = 0;
-
-		usrdatum = hashtab_search(policydb->p_users.table, q);
-		if (usrdatum) {
-			/* Replacing an existing user definition. */
-			ebitmap_init(&usrdatum->roles);
-			usrdatum->defined = 1;
-		} else {
-			char *id = strdup(q);
-			
-			/* Adding a new user definition. */
-			usrdatum = (user_datum_t *) malloc(sizeof(user_datum_t));
-			if (!id || !usrdatum) {
-				fprintf(stderr, "%s:  out of memory for %s on line %u\n",
-					path, buffer, lineno);
-				errno = ENOMEM;
-				free(buffer);
-				return -1;
-			}
-			memset(usrdatum, 0, sizeof(user_datum_t));
-			usrdatum->value = ++policydb->p_users.nprim;
-			ebitmap_init(&usrdatum->roles);
-			usrdatum->defined = 1;
-			rc = hashtab_insert(policydb->p_users.table,
-					    id, (hashtab_datum_t) usrdatum);
-			if (rc) {
-				fprintf(stderr, "%s:  out of memory for %s on line %u\n",
-					path, buffer, lineno);
-				errno = ENOMEM;
-				free(buffer);
-				return -1;
-			}
-		}
-
-		while (*p && isspace(*p))
-			p++;
-		if (!(*p))
-			BADLINE();
-		if (strncasecmp(p, "roles", 5))
-			BADLINE();
-		p += 5;
-		if (!isspace(*p))
-			BADLINE();
-		while (*p && isspace(*p))
-			p++;
-		if (!(*p))
-			BADLINE();
-		if (*p == '{') {
-			islist = 1;
-			p++;
-		} else 
-			islist = 0;
-
-		do { 
-			while (*p && isspace(*p))
-				p++;
-			if (!(*p))
-				BADLINE();
-
-			q = p;
-			while (*p && *p != ';' && *p != '}' && !isspace(*p)) 
-				p++;
-			if (!(*p)) 
-				BADLINE();
-			if (*p == '}') 
-				islist = 0;
-			oldc = *p;
-			*p++ = 0;
-			if (!q[0])
-				break;
-
-			roldatum = hashtab_search(policydb->p_roles.table, q);
-			if (!roldatum) {
-				fprintf(stderr, "%s:  undefined role %s in %s on line %u\n",
-					path, q, buffer, lineno);
-				continue;
-			}
-			/* Set the role and every role it dominates */
-			for (bit = ebitmap_startbit(&roldatum->dominates); bit < ebitmap_length(&roldatum->dominates); bit++) {
-				if (ebitmap_get_bit(&roldatum->dominates, bit))
-					if (ebitmap_set_bit(&usrdatum->roles, bit, 1)) {
-						fprintf(stderr, "%s:  out of memory for %s on line %u\n",
-							path, buffer, lineno);
-						errno = ENOMEM;
-						free(buffer);
-						return -1;
-					}
-			}
-		} while (islist);
-
-		if (mls_enabled) {
-			context_struct_t context;
-			char *scontext, *r, *s;
-
-			while (*p && isspace(*p))
-				p++;
-			if (!(*p))
-				BADLINE();
-			if (strncasecmp(p, "level", 5))
-				BADLINE();
-			p += 5;
-			if (!isspace(*p))
-				BADLINE();
-			while (*p && isspace(*p))
-				p++;
-			if (!(*p))
-				BADLINE();
-			q = p;
-			while (*p && strncasecmp(p, "range", 5))
-				p++;
-			if (!(*p)) 
-				BADLINE();
-			*--p = 0;
-			p++;
-
-			scontext = malloc(p - q);
-			if (!scontext) {
-				fprintf(stderr, "%s:  out of memory for %s on line %u\n",
-					path, buffer, lineno);
-				errno = ENOMEM;
-				free(buffer);
-				return -1;
-			}
-			r = scontext;
-			s = q;
-			while (*s) {
-				if (!isspace(*s))
-					*r++ = *s;
-				s++;
-			}
-			*r = 0;
-			r = scontext;
-
-			context_init(&context);
-			rc = mls_context_to_sid(policydb, oldc, &r, &context);
-			if (rc) {
-				fprintf(stderr, "%s:  invalid level %s in %s on line %u\n",
-					path, scontext, buffer, lineno);
-				free(scontext);
-				continue;
-
-			}
-			free(scontext);
-			memcpy(&usrdatum->dfltlevel, &context.range.level[0], sizeof(usrdatum->dfltlevel));
-
-			if (strncasecmp(p, "range", 5))
-				BADLINE();
-			p += 5;
-			if (!isspace(*p))
-				BADLINE();
-			while (*p && isspace(*p))
-				p++;
-			if (!(*p))
-				BADLINE();
-			q = p;
-			while (*p && *p != ';')
-				p++;
-			if (!(*p)) 
-				BADLINE();
-			*p++ = 0;
-
-			scontext = malloc(p - q);
-			if (!scontext) {
-				fprintf(stderr, "%s:  out of memory for %s on line %u\n",
-					path, buffer, lineno);
-				errno = ENOMEM;
-				free(buffer);
-				return -1;
-			}
-			r = scontext;
-			s = q;
-			while (*s) {
-				if (!isspace(*s))
-					*r++ = *s;
-				s++;
-			}
-			*r = 0;
-			r = scontext;
-
-			context_init(&context);
-			rc = mls_context_to_sid(policydb, oldc, &r, &context);
-			if (rc) {
-				fprintf(stderr, "%s:  invalid range %s in %s on line %u\n",
-					path, scontext, buffer, lineno);
-				free(scontext);
-				continue;
-			}
-			free(scontext);
-			memcpy(&usrdatum->range, &context.range, sizeof(usrdatum->range));
-		}
-	}
-
-	free(buffer);
-
-	return 0;
-}
-
-/* Select users for removal based on whether they were defined in the
-   new users configuration. */
-static int select_user(hashtab_key_t key, hashtab_datum_t datum, void *datap)
-{
-	char *name = key;
-	user_datum_t *usrdatum = datum;
-	
-	if (!usrdatum->defined) {
-		/* XXX Hack:  Don't accidentally remove SELinux-only users. */
-		if (!strcmp(name, "system_u") || !strcmp(name, "user_u")) {
-			return 0;
-		}
-		return 1;
-	}
-	return 0;
-}
-
-struct kill_user_data {
-	struct policydb *policydb;
-	ebitmap_t *free_users;
-};
-
-/* Kill the user entries selected by select_user, and
-   record that their slots are free. */
-static void kill_user(hashtab_key_t key, hashtab_datum_t datum, void *p)
-{
-	user_datum_t *usrdatum;
-	struct kill_user_data *kud = p;
-	struct policydb *pol = kud->policydb;
-	ebitmap_t *free_users = kud->free_users;
-
-	if (key)
-		free(key);
-
-	usrdatum = (user_datum_t *) datum;
-	ebitmap_set_bit(free_users, usrdatum->value - 1, 1);
-
-	ebitmap_destroy(&usrdatum->roles);
-	free(datum);
-	pol->p_users.nprim--;
-}
-
-/* Fold user values down to avoid holes generated by removal.
-   As the SID table is remapped by the kernel upon a policy reload,
-   this is safe for existing SIDs.  But it could be a problem for
-   constraints if they refer to the particular user.  */
-static int remap_users(hashtab_key_t key, hashtab_datum_t datum, void *p)
-{
-	user_datum_t *usrdatum = datum;
-	struct kill_user_data *kud = p;
-	struct policydb *pol = kud->policydb;
-	ebitmap_t *free_users = kud->free_users;
-	int i;
-
-	if (usrdatum->value > pol->p_users.nprim) {
-		for (i = ebitmap_startbit(free_users); i < ebitmap_length(free_users); i++) {
-			if (ebitmap_get_bit(free_users, i)) {
-				usrdatum->value = i+1;
-				ebitmap_set_bit(free_users, i, 0);
-				return 0;
-			}
-		}
-	}
-	return 0;
-}
-
-int sepol_genusers(void *data, size_t len,
-		   const char *usersdir,
-		   void **newdata, size_t *newlen)
-{
-	struct policydb policydb;
-	struct policy_file pf;
-	struct ebitmap free_users;
-	struct kill_user_data kud;
-	char path[PATH_MAX];
-	int rc;
-
-	/* Parse the original binary policy image into a struct policydb. */
-	pf.type = PF_USE_MEMORY;
-	pf.data = data;
-	pf.len = len;
-	if (policydb_read(&policydb,&pf, 0)) {
-		fprintf(stderr, "%s:  Can't read binary policy:  %s\n",
-			__FUNCTION__, strerror(errno));
-		return -1;
-	}
-
-	/* Load base set of system users from the policy package. */
-	snprintf(path, sizeof path, "%s/system.users", usersdir);
-	if (load_users(&policydb, path) < 0) {
-		fprintf(stderr, "%s: Can't load system.users:  %s\n",
-			__FUNCTION__, strerror(errno));
-		return -1;
-	}
-
-	/* Load locally defined users. */
-	snprintf(path, sizeof path, "%s/local.users", usersdir);
-	if (load_users(&policydb, path) < 0) {
-		fprintf(stderr, "%s:  Can't load local.users:  %s\n",
-			__FUNCTION__, strerror(errno));
-		return -1;
-	}
-
-        /* Kill unused users and remap to avoid holes. */
-	ebitmap_init(&free_users);
-	kud.policydb = &policydb;
-	kud.free_users = &free_users;
-	hashtab_map_remove_on_error(policydb.p_users.table, select_user, kill_user, &kud);
-	hashtab_map(policydb.p_users.table, remap_users, &kud);
-	ebitmap_destroy(&free_users);
-
-	/* Set the policy version for the new binary policy image we are
-	   about to generate so that it stays the same as the original,
-	   even if we support a newer one. */
-	sepol_set_policyvers(policydb.policyvers);
-
-	/* Compute the length for the new binary policy image. */
-	pf.type = PF_LEN;
-	pf.data = NULL;
-	pf.len = 0;
-	rc = policydb_write(&policydb, &pf);
-	if (rc) {
-		fprintf(stderr, "Can't compute length of binary policy:  %s\n",
-			strerror(errno));
-		return -1;
-	}
-
-	/* Allocate the new binary policy image. */
-	pf.type = PF_USE_MEMORY;	
-	pf.data = malloc(pf.len);
-	if (!pf.data) {
-		fprintf(stderr, "%s:  %s\n", __FUNCTION__, strerror(errno));
-		return -1;
-	}
-
-	/* Need to save len and data prior to modification by policydb_write. */
-	*newlen = pf.len;
-	*newdata = pf.data;
-
-	/* Write out the new binary policy image. */
-	rc = policydb_write(&policydb, &pf);
-	if (rc) {
-		fprintf(stderr, "Can't write binary policy:  %s\n",
-			strerror(errno));
-		free(pf.data);
-		return -1;
-	}
-	policydb_destroy(&policydb);
-	return 0;
-}
diff -Naur libsepol-1.5.9.orig/src/libsepol.map libsepol-1.5.9.new/src/libsepol.map
--- libsepol-1.5.9.orig/src/libsepol.map	2005-06-16 12:35:12.000000000 -0400
+++ libsepol-1.5.9.new/src/libsepol.map	2005-06-19 00:36:06.000000000 -0400
@@ -1,4 +1,4 @@
 {
-  global: sepol_genbools*; sepol_set_policydb_from_file; sepol_check_context; sepol_genusers; sepol_debug; sepol_set_delusers;
+  global: sepol_*; policydb_*_image; policydb_destroy; uc_*;  
   local: *;
 };
diff -Naur libsepol-1.5.9.orig/src/Makefile libsepol-1.5.9.new/src/Makefile
--- libsepol-1.5.9.orig/src/Makefile	2005-06-16 12:35:13.000000000 -0400
+++ libsepol-1.5.9.new/src/Makefile	2005-06-16 12:36:43.000000000 -0400
@@ -10,7 +10,7 @@
 LIBSO=$(TARGET).$(LIBVERSION)
 OBJS= $(patsubst %.c,%.o,$(wildcard *.c))
 LOBJS= $(patsubst %.c,%.lo,$(wildcard *.c))
-CFLAGS = -Wall
+CFLAGS = -Wall -g 
 override CFLAGS += -I. -I../include -D_GNU_SOURCE
 
 all: $(LIBA) $(LIBSO)
diff -Naur libsepol-1.5.9.orig/src/policydb.c libsepol-1.5.9.new/src/policydb.c
--- libsepol-1.5.9.orig/src/policydb.c	2005-06-16 12:35:14.000000000 -0400
+++ libsepol-1.5.9.new/src/policydb.c	2005-06-17 18:18:47.000000000 -0400
@@ -1756,6 +1756,3 @@
 
 	return 0;
 }
-
-
-
diff -Naur libsepol-1.5.9.orig/src/policydb_convert.c libsepol-1.5.9.new/src/policydb_convert.c
--- libsepol-1.5.9.orig/src/policydb_convert.c	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/src/policydb_convert.c	2005-06-18 01:36:09.000000000 -0400
@@ -0,0 +1,98 @@
+#include <stdlib.h>
+#include <sepol/policydb.h>
+
+#include "private.h"
+
+/* Construct a policydb from the supplied (data, len) pair */
+
+int policydb_from_image(void* data, size_t len, policydb_t* policydb) {
+
+        struct policy_file pf;
+
+        pf.type = PF_USE_MEMORY;
+        pf.data = data;
+        pf.len = len;
+
+        if (policydb_read(policydb, &pf, 0)) {
+                __sepol_debug_printf("%s: binary policy image is invalid\n",
+                        __FUNCTION__);
+
+                errno = EINVAL;
+                return SEPOL_ERR;
+        }
+
+        return SEPOL_SUCCESS;
+}
+
+/* Write a policydb to a memory region, and return the (data, len) pair. */
+
+int policydb_to_image(
+	policydb_t* policydb, void **newdata, size_t *newlen) {
+
+	void *tmp_data = NULL;
+	size_t tmp_len;
+	struct policy_file pf;
+	struct policydb tmp_policydb;
+
+	/* Set the policy version for the new binary policy image we are
+	   about to generate so that it stays the same as the original,
+	   even if we support a newer one. */
+	sepol_set_policyvers(policydb->policyvers);
+
+	/* Compute the length for the new binary policy image. */
+	pf.type = PF_LEN;
+	pf.data = NULL;
+	pf.len = 0;
+	if (policydb_write(policydb, &pf)) {
+		__sepol_debug_printf("%s: Can't compute length of binary "
+			"policy\n", __FUNCTION__);
+		errno = EINVAL;	
+		goto err;
+	}
+
+	/* Allocate the new binary policy image. */
+	pf.type = PF_USE_MEMORY;
+	pf.data = malloc(pf.len);
+	if (!pf.data) {
+		__sepol_debug_printf("%s:  out of memory\n", __FUNCTION__);
+		goto err;
+        }
+
+	/* Need to save len and data prior to modification by policydb_write.*/
+	tmp_len = pf.len;
+	tmp_data = pf.data;
+
+	/* Write out the new binary policy image. */
+	if (policydb_write(policydb, &pf)) {
+		__sepol_debug_printf("%s:  Can't write binary policy\n",
+			__FUNCTION__);
+		errno = EINVAL;
+		goto err;
+        }
+
+	/* Verify the new binary policy image. */
+	pf.type = PF_USE_MEMORY;
+	pf.data = tmp_data;
+        pf.len = tmp_len;
+        if (policydb_read(&tmp_policydb, &pf, 0)) {
+		__sepol_debug_printf("%s:  new binary policy image is "
+			"invalid\n", __FUNCTION__);
+                errno = EINVAL;
+		goto err;
+        }
+	policydb_destroy(&tmp_policydb);
+
+	/* Update (newdata, newlen) */
+	*newdata = tmp_data;
+	*newlen = tmp_len;
+
+	/* Recover */
+	sepol_set_policyvers(POLICYDB_VERSION_MAX);
+        return SEPOL_SUCCESS;
+
+err:
+	/* Recover */
+	sepol_set_policyvers(POLICYDB_VERSION_MAX);
+	free(tmp_data);
+        return SEPOL_ERR;
+}
diff -Naur libsepol-1.5.9.orig/src/private.h libsepol-1.5.9.new/src/private.h
--- libsepol-1.5.9.orig/src/private.h	2005-06-16 12:35:12.000000000 -0400
+++ libsepol-1.5.9.new/src/private.h	2005-06-19 19:02:55.000000000 -0400
@@ -4,6 +4,11 @@
 
 #include <byteswap.h>
 #include <endian.h>
+#include <sepol/policydb.h>
+
+#define SEPOL_EXIT 1
+#define SEPOL_SUCCESS 0
+#define SEPOL_ERR -1
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #define cpu_to_le32(x) (x)
@@ -25,7 +30,9 @@
 };
 
 extern struct policydb_compat_info *policydb_lookup_compat(int version);
-extern void __sepol_debug_printf(const char *fmt, ...);
+
+__attribute__ ((format (printf, 1, 2))) 
+void __sepol_debug_printf(const char *fmt, ...);
 
 /* Reading from a policy "file". */
 static inline void *next_entry(struct policy_file * fp, size_t bytes)
diff -Naur libsepol-1.5.9.orig/src/record_file.c libsepol-1.5.9.new/src/record_file.c
--- libsepol-1.5.9.orig/src/record_file.c	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/src/record_file.c	2005-06-19 22:27:23.000000000 -0400
@@ -0,0 +1,343 @@
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "record_file.h"
+#include "private.h"
+
+void record_dispose_line(parse_info_t* info) {
+	if (info->orig_line) {
+		free(info->orig_line);
+		info->orig_line = NULL;
+	}
+
+	if (info->working_copy) {
+		free(info->working_copy);
+		info->working_copy = NULL;
+	}
+
+	info->ptr = NULL;
+}
+
+char* record_fetch_string(parse_info_t* info) {
+	char* start = info->ptr;
+
+	while (*(info->ptr) && !isspace(*(info->ptr)))
+		info->ptr++;
+	*(info->ptr)++ = '\0';
+
+	return start;
+}
+
+int record_assert_noeof(parse_info_t* info) {
+	if (!info->ptr) {
+		__sepol_debug_printf("%s: unexpected end of file\n",
+			__FUNCTION__);
+		return SEPOL_ERR;
+	}
+	return SEPOL_SUCCESS;
+}
+
+int record_assert_space(parse_info_t* info) {
+	if (!isspace(*(info->ptr))) {
+		__sepol_debug_printf("%s: malformed line %u in %s: \n%s\n",
+			__FUNCTION__, info->lineno, info->filename,
+			info->orig_line);
+		return SEPOL_ERR;
+	}
+	return SEPOL_SUCCESS;
+}
+
+
+int record_assert_ch(parse_info_t* info, const char ch) {
+
+	if (record_assert_noeof(info) < 0)
+		return SEPOL_ERR;
+
+	if (*(info->ptr) != ch) {
+		__sepol_debug_printf("%s: malformed line %u in %s: \n%s\n"
+		"expected character \'%c\', but found \'%c\'\n", 
+		__FUNCTION__, info->lineno, info->filename, 
+		info->orig_line, ch, *(info->ptr));
+
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_SUCCESS;
+}
+
+int record_assert_str(parse_info_t* info, const char* assert_str) {
+
+	if (record_assert_noeof(info) < 0)
+		return SEPOL_ERR;
+
+        if (strncasecmp(info->ptr, assert_str, strlen(assert_str))) {
+		__sepol_debug_printf("%s: malformed line %u in %s: \n%s\n"
+		"expected string \"%s\"\n",__FUNCTION__, 
+		info->lineno, info->filename, info->orig_line, assert_str);
+
+		return SEPOL_ERR;
+	}
+
+	info->ptr += strlen(assert_str);
+	return SEPOL_SUCCESS;
+}
+
+int record_skip_space(parse_info_t* info) {
+	unsigned int len = 0;
+	int lineno = info->lineno;
+	char* buffer = NULL;
+	char* ptr;
+
+	if (info->ptr) { 
+		while (*(info->ptr) && isspace(*(info->ptr)))
+			info->ptr++;
+		
+		if (*(info->ptr))
+			return SEPOL_SUCCESS;
+	}
+
+	record_dispose_line(info);
+
+	while (getline(&buffer, &len, info->file_stream) >= 0) {
+		lineno++;
+
+		/* Empty line */
+		if (len == 0) {
+			if (info->copy_stream)
+				fprintf(info->copy_stream, "\n"); 
+			goto next;
+		}
+
+		/* Eat newline, preceding whitespace */
+		if (buffer[len - 1] == '\n')
+			buffer[len - 1] = '\0';
+
+		ptr = buffer;
+		while (*ptr && isspace(*ptr))
+			ptr++;
+
+		/* Skip comments and blank lines */
+		if (!(*ptr) || *ptr == '#') {
+			if (info->copy_stream)			
+				fprintf(info->copy_stream, "%s", buffer);
+			goto next;
+		}
+
+		else {
+			char* tmp = strdup(buffer);
+			if (!tmp) {
+				__sepol_debug_printf("%s: out of memory\n", 
+					__FUNCTION__);
+				goto err;
+			}
+
+			info -> lineno = lineno;
+			info -> working_copy = buffer;
+			info -> len = len;
+			info -> orig_line = tmp;
+			info -> ptr = ptr;
+
+			return SEPOL_SUCCESS;
+		}
+	
+		next:	
+		free(buffer);
+		buffer = 0;
+	}
+
+	return SEPOL_SUCCESS;
+		
+	err:
+	if (buffer)
+		free(buffer);
+
+	return SEPOL_ERR;
+}
+
+static int process_records (
+	record_table_t* rtable, 
+	parse_info_t* info,
+	int (*handler) (record_t record, void* arg),
+	void* arg) {
+
+	record_t* record = NULL;
+	int status = 0;
+
+	while(!(status & RECORD_HANDLER_SIGEXIT)) { 
+
+		/* Create a record config structure */
+		record = rtable->create();
+		if (!record) {
+			__sepol_debug_printf("%s: out of memory\n", __FUNCTION__);
+			goto err;
+		}
+
+		status = rtable->parse(info, record);
+		if (status < 0) 
+			goto err;
+		else if (status == SEPOL_EXIT)
+			goto out;
+	
+		status = handler(record, arg); 
+
+		if (status & RECORD_HANDLER_SIGMATCH)
+			info -> match_found = 1;
+
+		if (status & RECORD_HANDLER_SIGERR) 
+			goto err;
+
+		if (info->copy_stream && ! (status & RECORD_HANDLER_SIGDEL))
+			rtable->print(record, info->copy_stream);
+
+		rtable->destroy(record);
+		record = NULL;
+	}
+
+	out:
+	if (record)
+		rtable->destroy(record);
+	return SEPOL_SUCCESS;
+
+	err:
+	if (record)
+		rtable->destroy(record);
+	return SEPOL_ERR;
+}
+
+static int open_file(parse_info_t* info, int copy_stream) {
+
+	info->file_stream = fopen(info->filename, "r");
+	if (!info->file_stream) {
+		 __sepol_debug_printf("%s: unable to open %s for reading: %s\n",
+			__FUNCTION__, info->filename, strerror(errno));
+		return SEPOL_ERR;
+	}
+	__fsetlocking(info->file_stream, FSETLOCKING_BYCALLER);
+
+	if (copy_stream) {
+		char tmp_file[PATH_MAX];   
+		snprintf(tmp_file, sizeof tmp_file, "%s.bak", info->filename);
+		
+		info->copy_stream = fopen(tmp_file, "a");
+		if (!info->copy_stream) {
+			__sepol_debug_printf("%s: unable to open %s for append: %s\n",
+				__FUNCTION__, tmp_file, strerror(errno));
+			fclose(info->file_stream);
+                	return SEPOL_ERR;
+        	}
+    	    __fsetlocking(info->copy_stream, FSETLOCKING_BYCALLER);
+	}
+
+	return SEPOL_SUCCESS;
+}
+
+static int close_file(parse_info_t* info, int err) {
+	fclose(info->file_stream);
+
+	if (info->copy_stream) {
+		char tmp_file[PATH_MAX];
+		snprintf(tmp_file, sizeof tmp_file, "%s.bak", info->filename);
+
+		fclose(info->copy_stream);
+		if (!info->match_found) {
+			remove(tmp_file);
+			__sepol_debug_printf("%s: unable to match record\n",
+         			__FUNCTION__);
+			errno = EIO;
+			return SEPOL_SUCCESS;
+		}
+		else if (err) { 
+			remove(tmp_file);
+			return SEPOL_SUCCESS;
+		}
+		else
+			return rename(tmp_file, info->filename);
+	}
+
+	return SEPOL_SUCCESS;
+}
+
+int record_iterate_file(
+	const char* filename,
+	record_table_t* rtable,
+	int (*handler) (record_t record, void* arg),
+	void* arg) { 
+
+	parse_info_t info;
+	info.filename = filename;
+	info.lineno = 0;
+	info.working_copy = NULL;
+	info.orig_line = NULL;
+	info.file_stream = NULL;
+	info.copy_stream = NULL;
+	info.len = 0;
+	info.match_found = 0;
+	info.ptr = NULL;
+
+	if (open_file(&info, 0) < 0)
+		goto err;
+
+	if (process_records(rtable, &info, handler, arg) < 0)
+		goto err;	
+
+	close_file(&info, 0);
+	return SEPOL_SUCCESS;
+
+err:
+	close_file(&info, 1);
+	return SEPOL_ERR;
+}
+
+int record_modify_file(
+	const char* filename, 
+	record_table_t* rtable,
+	int (*handler) (record_t record, void* arg),
+	void* arg) {
+
+	parse_info_t info;
+	info.filename = filename;
+	info.lineno = 0;
+	info.working_copy = NULL;
+	info.orig_line = NULL;
+	info.file_stream = NULL;
+	info.copy_stream = NULL;
+	info.len = 0;
+	info.match_found = 0;
+	info.ptr = NULL;
+
+	if (open_file(&info, 1) < 0)
+		goto err;
+
+	if (process_records(rtable, &info, handler, arg) < 0)
+		goto err;
+
+	return close_file(&info, 0);
+err:
+	close_file(&info, 1);
+        return SEPOL_ERR;
+}
+
+int record_addto_file(
+	const char* filename,
+	record_table_t* rtable,
+	record_t record) {
+
+	FILE* fp;
+
+	fp = fopen(filename, "a");
+	if (!fp) {
+		__sepol_debug_printf("%s: can't open %s for append: %s\n", 
+			__FUNCTION__, filename, strerror(errno));
+		return SEPOL_ERR;
+	}
+
+	fseek(fp, 0, SEEK_END);
+
+	rtable->print(record, fp);
+	fclose(fp);
+	return SEPOL_SUCCESS;
+}
diff -Naur libsepol-1.5.9.orig/src/record_file.h libsepol-1.5.9.new/src/record_file.h
--- libsepol-1.5.9.orig/src/record_file.h	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/src/record_file.h	2005-06-19 22:06:00.000000000 -0400
@@ -0,0 +1,73 @@
+#ifndef _SEPOL_RECORD_FILE_H
+#define _SEPOL_RECORD_FILE_H
+
+#ifndef RECORD_DEFINED
+typedef void* record_t;
+#define RECORD_DEFINED
+#endif
+
+#define RECORD_HANDLER_SIGOK 	0x0001
+#define RECORD_HANDLER_SIGERR	0x0002
+#define RECORD_HANDLER_SIGMATCH 0x0004
+#define RECORD_HANDLER_SIGDEL	0x0008
+#define RECORD_HANDLER_SIGEXIT  0x0010
+
+typedef struct parse_info {
+	unsigned int lineno;
+	char* orig_line;
+	char* working_copy;
+	char* ptr;
+	unsigned int len;
+	const char* filename;
+	FILE* file_stream;
+	FILE* copy_stream;
+	int match_found;
+} parse_info_t;
+
+typedef struct record_table {
+	record_t (*create) (void);
+	void (*destroy) (record_t record);
+	int (*parse) (parse_info_t* info, record_t record);
+	void (*print) (record_t record, FILE* str);
+} record_table_t;
+
+/*
+ * Iterate over all records in the given file,
+ * and invoke the handler with its given argument on each record.
+ * The handler is supplied a record_t structure containing
+ * the parsed data.
+ */
+
+int record_iterate_file(
+	const char* filename,
+	record_table_t* rtable,
+	int (*handler) (record_t record, void* arg), void* arg);
+
+/*
+ * Copy filename to filename.tmp, updating a particular record.
+ * Invoke the handler, which may update the record, or issue a
+ * delete signal. On failure, the tmp file is erased.
+ * On success, the tmp file replaces the old file.
+ */
+int record_modify_file(
+        const char* filename,
+        record_table_t* rtable,
+	int (*handler) (record_t record, void* arg), void* arg);
+
+/*
+ * Add a record to the config file (local) and to policy.
+ */
+int record_addto_file(
+	const char* filename,
+	record_table_t* rtable,
+	record_t record);
+
+void record_dispose_line(parse_info_t* info);
+int record_skip_space(parse_info_t* info);
+char* record_fetch_string(parse_info_t* info);
+int record_assert_noeof(parse_info_t* info);
+int record_assert_space(parse_info_t* info);
+int record_assert_ch(parse_info_t* info, const char ch);
+int record_assert_str(parse_info_t* info, const char* assert_str);
+
+#endif
diff -Naur libsepol-1.5.9.orig/src/user_config.c libsepol-1.5.9.new/src/user_config.c
--- libsepol-1.5.9.orig/src/user_config.c	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/src/user_config.c	2005-06-19 21:50:29.000000000 -0400
@@ -0,0 +1,157 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <sepol/user_config.h>
+
+#include "private.h"
+
+/* Most functions are inlined in user_config.h */
+
+int uc_add_role(user_config_t user, const char* role) {
+        struct role* r = (struct role*) malloc(sizeof(struct role));
+	if (!r) {
+		__sepol_debug_printf("%s: out of memory\n", 
+			__FUNCTION__);
+		return SEPOL_ERR;
+	}
+
+	r->role = strdup(role);
+	if (!role) {
+		__sepol_debug_printf("%s: out of memory\n", 
+			__FUNCTION__);
+		return SEPOL_ERR;
+	}
+
+        r->next = user->roles;
+        user->roles = r;
+        if (!user->def_role)
+                user->def_role = r;
+        user->num_roles++;
+
+        return SEPOL_SUCCESS;
+}
+
+const char* uc_next_role(user_config_t user) {
+	struct role* r = user->next_role;
+	if (r == NULL)
+		return NULL;
+	else {
+		user->next_role = r->next;
+		return r->role;
+	}
+}
+
+int uc_has_role(user_config_t user, const char* role) {
+	struct role* ptr;
+	
+	for (ptr = user->roles; ptr != NULL; ptr = ptr->next)
+		if (!strcmp(ptr->role, role)) 
+			return 1;
+	return 0;
+}
+
+int uc_del_role(user_config_t user, const char* role) {
+	struct role *ptr, *prev = NULL;
+
+	for (ptr = user->roles; ptr != NULL; ptr=ptr -> next) {
+		if (!strcmp(ptr->role, role)) {
+
+			if (user->num_roles == 1) {
+				__sepol_debug_printf("%s: unable to delete"
+					"the last role for user %s\n", 
+					__FUNCTION__, uc_get_name(user));
+
+				return SEPOL_ERR;
+			}
+
+			if (prev)
+				prev->next = ptr->next;
+			else 
+				user->roles = ptr->next;
+			
+			if (user->def_role == ptr) 
+				user->def_role = user->roles;
+
+			prev = ptr;
+			free(ptr->role);
+			free(ptr);
+			return SEPOL_SUCCESS;
+		} 
+		else 
+			prev = ptr;
+	}
+
+	return SEPOL_SUCCESS;
+}
+
+int uc_reset_roles(user_config_t user) {
+	struct role *ptr, *prev = NULL;
+	for (ptr = user->roles; ptr != NULL; ptr = ptr->next) {
+		if (prev != NULL) {
+			free(prev->role);
+			free(prev);
+		}
+		prev = ptr;
+	}
+	if (prev != NULL) {
+		free(prev->role);
+		free(prev);
+	}
+
+	user->roles = NULL;
+	user->def_role = NULL;
+
+	return SEPOL_SUCCESS;
+}
+
+int uc_set_def_role(user_config_t user, const char* role) {
+	struct role* ptr;
+	int status;
+
+	for (ptr = user->roles; ptr != NULL; ptr=ptr->next)
+		if (!strcmp(ptr->role, role)) {
+			user->def_role = ptr;
+			return SEPOL_SUCCESS;
+		}
+
+	status = uc_add_role(user, role);
+	user->def_role = user->roles;
+	return status;
+}
+
+user_config_t uc_create() {
+        struct user_config* user = 
+		(struct user_config*) malloc(sizeof(struct user_config));
+
+        if (!user) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+        user->roles = NULL;
+        user->def_role = NULL;
+        user->num_roles = 0;
+        user->name = NULL;
+	user->mls_level = NULL;
+	user->mls_range = NULL;
+
+        return user;
+}
+
+void uc_destroy(user_config_t user) {
+	struct role* ptr;
+	
+	free(user->name);
+
+	while (user->roles) {
+		ptr = user->roles;
+		user->roles = user->roles->next;
+		free(ptr->role);
+		free(ptr);
+        }
+	if (user->mls_level)
+		free(user->mls_level);
+	if (user->mls_range)
+		free(user->mls_range);
+
+	free(user);
+}
diff -Naur libsepol-1.5.9.orig/src/users_file.c libsepol-1.5.9.new/src/users_file.c
--- libsepol-1.5.9.orig/src/users_file.c	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/src/users_file.c	2005-06-19 23:10:39.000000000 -0400
@@ -0,0 +1,480 @@
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include <sepol/policydb.h>
+#include <sepol/users_file.h>
+#include <sepol/user_config.h>
+#include <sepol/users_policy.h>
+
+#include "private.h"
+
+typedef user_config_t record_t;
+#define RECORD_DEFINED
+#include "record_file.h"
+
+#define MLS_MAX 40
+/* FIXME: what's the correct value */
+
+/*
+ * Print user record to the given stream 
+ */
+static void print_user(user_config_t user, FILE* str) {
+	const char *mls_level, *mls_range, *role, *def_role;
+
+	/* Interpret NULL name as deletion signal */
+	if (uc_get_name(user) == NULL) 
+		return;
+
+	fprintf(str, "user %s roles { ", uc_get_name(user));
+
+	/* Default role is first */
+	def_role = uc_get_def_role(user);
+		fprintf(str, "%s ", def_role);
+
+	/* Then we print the rest of them */
+        uc_iter_init(user);
+        while((role = uc_next_role(user)))
+		if (strcmp(role, def_role))
+			fprintf(str, "%s ", role);
+
+        fprintf(str, "}");
+	
+	/* MLS */
+	mls_level = uc_get_mls_level(user);
+	mls_range = uc_get_mls_range(user);
+
+	if (mls_level != NULL && mls_range != NULL) 
+		fprintf(str, "level %s range %s", mls_level, mls_range);
+
+	fprintf(str, ";\n");
+}
+
+/*
+ * Parse a configuration line in the users file,
+ * and construct a user_config_t structure from it
+ */
+
+static int parse_user(parse_info_t* info, user_config_t user) {
+
+	int islist = 0;
+	char mls[MLS_MAX];
+	int i;
+	
+	char* start;
+	
+	if (record_skip_space(info) < 0)
+		goto err;
+	if (!info->ptr)
+		goto last;
+	
+	/* Parse user name */
+	if (record_assert_str(info, "user") < 0)
+		goto err;
+	
+	if (record_assert_space(info) < 0)
+		goto err;
+
+	if (record_skip_space(info) < 0)
+		goto err;
+
+	if (record_assert_noeof(info) < 0)
+		goto err;
+
+	if (uc_set_name(user, record_fetch_string(info)) < 0)
+		goto err;
+
+	/* Parse roles header */
+	if (record_skip_space(info) < 0)
+		goto err;
+
+	if (record_assert_str(info,"roles") < 0)
+		goto err;
+
+	if (record_assert_space(info) < 0)
+		goto err;
+	
+	if (record_skip_space(info) < 0)
+		goto err;
+
+	if (record_assert_noeof(info) < 0)
+		goto err;
+
+	if (*(info->ptr) == '{') {
+		islist = 1;
+		info->ptr++;
+	} else
+		islist = 0;
+
+	/* For each role, loop */
+	do { 
+		if (record_skip_space(info) < 0)
+			goto err;
+		if (record_assert_noeof(info) < 0)
+			goto err;
+
+		start = info->ptr;
+		while (*(info->ptr) && *(info->ptr) != ';' 
+			&& *(info->ptr) != '}' && !isspace(*(info->ptr))) 
+			info->ptr++;
+		*(info->ptr)++ = '\0';
+	
+		if (uc_add_role(user, start) < 0)
+			goto err;
+
+		if (record_skip_space(info) < 0)
+			goto err;
+		if (record_assert_noeof(info) < 0)	
+			goto err;
+
+		if (*(info->ptr) == '}') 
+			islist = 0;
+
+	} while (islist);
+
+	/* Handle mls */
+	if (mls_enabled) {
+
+		/* Parse level header */
+		if (record_skip_space(info) < 0)
+			goto err;
+		if (record_assert_noeof(info) < 0)
+			goto err;
+
+		if (*(info->ptr) == ';')
+			goto out;
+
+		if (record_assert_str(info, "level") < 0)
+			goto err;
+
+		if (record_assert_space(info) < 0)
+			goto err;
+
+		if (record_skip_space(info) < 0)
+			goto err;
+		if (record_assert_noeof(info) < 0)
+			goto err;
+
+		/* Parse level, spaces are allowed */
+		do {
+			if (!isspace(info->ptr)) { 
+				if (i > (MLS_MAX - 2)) 
+					goto context_toobig;
+				mls[i++] = *(info->ptr);
+			}
+			info->ptr++;
+	
+			if (record_skip_space(info) < 0)
+				goto err;
+			if (record_assert_noeof(info) < 0)
+				goto err;
+
+		} while(!strncasecmp(info->ptr, "range", 5));
+
+		mls[i] = '\0';
+		i = 0;
+		if (uc_set_mls_level(user, mls) < 0)
+			goto err;
+
+		/* Parse range header */
+		if (record_assert_str(info, "range") < 0)
+			goto err;
+
+		if (record_assert_space(info) < 0)
+			goto err;
+
+		if (record_skip_space(info) < 0)
+			goto err;
+		if (record_assert_noeof(info) < 0)
+			goto err;
+
+		/* Parse range, spaces are allowed */
+                do {
+			if (!isspace(info->ptr)) {
+				if (i > (MLS_MAX - 2))
+					goto context_toobig;
+				mls[i++] = *(info->ptr);
+			}
+			(info->ptr)++;
+
+			if (record_skip_space(info) < 0)
+				goto err;
+			if (record_assert_noeof(info) < 0)
+				goto err;
+
+		} while(*(info->ptr) != ';');
+
+		mls[i] = '\0';
+		if (uc_set_mls_range(user, mls) < 0)
+			goto err;
+	}
+
+	out:
+	record_dispose_line(info);
+	return SEPOL_SUCCESS;
+
+	last:
+	return SEPOL_EXIT;
+
+	context_toobig:
+	__sepol_debug_printf("%s: MLS context is too long\n", 
+		__FUNCTION__);
+	record_dispose_line(info);
+	return SEPOL_ERR;
+
+	err:
+	record_dispose_line(info);
+	return SEPOL_ERR;
+}
+
+static record_table_t USER_RTABLE = {
+	.create  = uc_create,
+	.destroy = uc_destroy,
+	.parse   = parse_user,
+	.print   = print_user
+};
+
+typedef struct user_query {
+	const char* name;
+	policydb_t* policydb;
+} user_query_t;
+
+typedef struct role_query {
+	const char* name;
+	const char* role;
+	policydb_t* policydb;
+} role_query_t;
+
+typedef struct roles_query {
+	const char* name;
+	const char** roles;
+	policydb_t* policydb;
+} roles_query_t;
+
+static int user_load(user_config_t user, void* policydb_arg) {
+	policydb_t* policydb = (policydb_t*) policydb_arg;
+
+	if (sepol_load_user_policy(policydb, user) < 0)
+		return RECORD_HANDLER_SIGERR;
+	else
+		return RECORD_HANDLER_SIGOK;	
+}
+
+static int user_del(user_config_t user, void* query_arg) {	
+	int status = 0;
+	
+	user_query_t* query = (user_query_t*) query_arg;
+
+	if (!strcmp(uc_get_name(user), query->name))
+		status |= RECORD_HANDLER_SIGMATCH;
+
+	if (sepol_del_user_policy(query->policydb, query->name) < 0) {
+		status |= RECORD_HANDLER_SIGERR;
+		goto exit;
+	}
+	else
+		status |= RECORD_HANDLER_SIGDEL;
+
+	status |= RECORD_HANDLER_SIGOK;
+	exit:
+	return status;
+}
+
+static int user_add_role(user_config_t user, void* query_arg) {
+	int status = 0;
+
+	role_query_t* query = (role_query_t*) query_arg;
+
+	if (!strcmp(uc_get_name(user), query->name))
+		status |= RECORD_HANDLER_SIGMATCH;
+
+	if (uc_has_role(user, query->role))
+		goto exit;
+	
+	else if (uc_add_role(user, query->role) < 0) {
+		status |= RECORD_HANDLER_SIGERR;
+		goto exit;
+	}
+	
+	if (sepol_load_user_policy(query->policydb, user) < 0) {
+		status |= RECORD_HANDLER_SIGERR;
+		goto exit;
+	}
+
+	status |= RECORD_HANDLER_SIGOK;
+	exit:
+	return status;
+}
+
+static int user_del_role(user_config_t user, void* query_arg) {
+	int status = 0;
+	
+	role_query_t* query = (role_query_t*) query_arg;
+
+	if (!strcmp(uc_get_name(user), query->name))
+		status |= RECORD_HANDLER_SIGMATCH;
+
+	if (uc_del_role(user, query->role) < 0) {
+		status |= RECORD_HANDLER_SIGERR;
+		goto exit;
+	}
+
+	if (sepol_load_user_policy(query->policydb, user) < 0) {
+		status |= RECORD_HANDLER_SIGERR;
+		goto exit;
+	}
+	
+	status |= RECORD_HANDLER_SIGOK;
+	exit:	
+	return status;
+}
+
+static int user_set_roles(user_config_t user, void* query_arg) {
+	int status = 0;
+	const char** ptr;
+
+	roles_query_t* query = (roles_query_t*) query_arg;
+
+	if (!strcmp(uc_get_name(user), query->name))
+		status |= RECORD_HANDLER_SIGMATCH;
+
+	if (uc_reset_roles(user) < 0) {
+		status |= RECORD_HANDLER_SIGERR;
+		goto exit;
+	}
+		
+	ptr = query->roles;
+	while(ptr) {
+		if (uc_add_role(user, *ptr) < 0) {
+			status |= RECORD_HANDLER_SIGERR;
+			goto exit;
+		}
+		ptr++;
+	}
+
+	if (sepol_load_user_policy(query->policydb, user) < 0) {
+		status |= RECORD_HANDLER_SIGERR;
+		goto exit;
+	}
+
+	status |= RECORD_HANDLER_SIGOK;
+	exit:
+	return status;
+}
+
+int sepol_load_users_file( 
+	policydb_t* policydb, 
+	const char* usersdir) {
+
+	char path[PATH_MAX];
+
+	/* Clear unused users */
+	sepol_clear_users_policy(policydb);
+
+	/* Load base set of system users from the policy package. */
+	snprintf(path, sizeof path, "%s/system.users", usersdir);
+	if (record_iterate_file(path, &USER_RTABLE, 
+		user_load, (void*) policydb) < 0) {
+		return SEPOL_ERR;
+	}
+
+	/* Load local users */
+	snprintf(path, sizeof path, "%s/local.users", usersdir);
+	if (record_iterate_file(path, &USER_RTABLE,
+		user_load, (void*) policydb) < 0) {
+		return SEPOL_ERR;
+	}
+
+        return SEPOL_SUCCESS;
+}
+
+/* Add/delete users */
+
+int sepol_add_user_file(
+	policydb_t* policydb, 
+	const char* usersdir,
+	user_config_t user) {
+
+	char path[PATH_MAX];
+	snprintf(path, sizeof path, "%s/local.users", usersdir);
+
+	if (!(user_load(user, (void*) policydb) & RECORD_HANDLER_SIGOK)) 
+		return SEPOL_ERR; 
+
+	return record_addto_file(path, &USER_RTABLE, user);
+}
+
+int sepol_del_user_file(
+	policydb_t* policydb,
+        const char* usersdir, 
+	const char* username) {
+
+	user_query_t query;
+	char path[PATH_MAX];
+	snprintf(path, sizeof path, "%s/local.users", usersdir);
+
+	query.name = username;
+	query.policydb = policydb;
+
+	return record_modify_file(path, &USER_RTABLE,
+		user_del, (void*) &query);		
+}
+
+/* Role manipulation */
+int sepol_set_roles_file(
+	policydb_t* policydb, 
+	const char* usersdir,
+	const char* username, 
+	const char** roles) {
+
+	roles_query_t query;
+	char path[PATH_MAX];
+	snprintf(path, sizeof path, "%s/local.users", usersdir);
+
+	query.name = username;
+	query.policydb = policydb;
+	query.roles = roles;
+
+	return record_modify_file(path, &USER_RTABLE,
+		user_set_roles, (void*) &query);		
+}
+
+int sepol_add_role_file(
+	policydb_t* policydb, 
+	const char* usersdir,
+	const char* username, 
+	const char* role) {
+	
+	role_query_t query;
+	char path[PATH_MAX];
+
+	query.name = username;
+	query.policydb = policydb;
+	query.role = role;
+
+	snprintf(path, sizeof path, "%s/local.users", usersdir);
+	return record_modify_file(path, &USER_RTABLE,
+		user_add_role, (void*) &query);
+}
+
+int sepol_del_role_file(
+	policydb_t* policydb, 
+	const char* usersdir,
+	const char* username, 
+	const char* role) {
+
+	role_query_t query;
+	char path[PATH_MAX];
+	snprintf(path, sizeof path, "%s/local.users", usersdir);
+
+	query.name = username;
+	query.policydb = policydb;
+	query.role = role;
+
+	return record_modify_file(path, &USER_RTABLE,
+		user_del_role, (void*) &query);
+}
+
diff -Naur libsepol-1.5.9.orig/src/users_policy.c libsepol-1.5.9.new/src/users_policy.c
--- libsepol-1.5.9.orig/src/users_policy.c	1969-12-31 19:00:00.000000000 -0500
+++ libsepol-1.5.9.new/src/users_policy.c	2005-06-19 18:43:00.000000000 -0400
@@ -0,0 +1,345 @@
+#include <stdlib.h>
+#include <sepol/policydb.h>
+#include <sepol/mls.h>
+
+#include <sepol/user_config.h>
+#include <sepol/users_policy.h>
+
+#include "private.h"
+
+static int delusers;
+
+struct kill_user_data {
+        struct policydb *policydb;
+        ebitmap_t *free_users;
+};
+
+/* Select users for removal based on whether they were defined in the
+   new users configuration. */
+static int select_user(
+	hashtab_key_t key, hashtab_datum_t datum, void *datap) {
+	user_datum_t *usrdatum = datum;
+
+	if (!usrdatum->defined)
+		return 1;
+	return 0;
+}
+
+/* Fold user values down to avoid holes generated by removal.
+   As the SID table is remapped by the kernel upon a policy reload,
+   this is safe for existing SIDs.  But it could be a problem for
+   constraints if they refer to the particular user.  */
+static int remap_users(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+	user_datum_t *usrdatum = datum;
+	struct kill_user_data *kud = p;
+	struct policydb *pol = kud->policydb;
+	ebitmap_t *free_users = kud->free_users;
+	int i;
+
+	if (usrdatum->value > pol->p_users.nprim) {
+		for (i = ebitmap_startbit(free_users); 
+		     i < ebitmap_length(free_users); i++) {
+
+			if (ebitmap_get_bit(free_users, i)) {
+				usrdatum->value = i+1;
+				ebitmap_set_bit(free_users, i, 0);
+				return 0;
+			}
+		}
+	}
+	return 0;
+}
+
+/* Kill the user entries selected by select_user, and
+   record that their slots are free. */
+static void kill_user(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+	user_datum_t *usrdatum;
+	struct kill_user_data *kud = p;
+	struct policydb *pol = kud->policydb;
+	ebitmap_t *free_users = kud->free_users;
+
+	if (key)
+		free(key);
+	
+	usrdatum = (user_datum_t *) datum;
+	
+	if (free_users != NULL) 
+		ebitmap_set_bit(free_users, usrdatum->value - 1, 1);
+
+	ebitmap_destroy(&usrdatum->roles);
+	free(datum);
+	pol->p_users.nprim--;
+}
+
+void sepol_clear_users_policy(policydb_t* policydb) {
+	struct ebitmap free_users;
+	struct kill_user_data kud;
+
+	if (delusers) {
+		/* Kill unused users and remap to avoid holes. */
+		ebitmap_init(&free_users);
+		kud.policydb = policydb;
+		kud.free_users = &free_users;
+		hashtab_map_remove_on_error(
+			policydb->p_users.table,
+			&select_user,
+			&kill_user, &kud);
+
+		hashtab_map(
+			policydb->p_users.table,
+			&remap_users, &kud);
+			ebitmap_destroy(&free_users);
+        }
+}
+
+
+/* Add a user to the given policydb. The user may not exist already */
+
+int sepol_add_user_policy(policydb_t* policydb, user_config_t user) {
+	char* name;
+	user_datum_t* usrdatum;
+
+	/* See if a user exists */
+	name = strdup(uc_get_name(user));
+	if (!name) {
+		__sepol_debug_printf("%s: out of memory for %s\n", 
+			__FUNCTION__, uc_get_name(user));
+		return SEPOL_ERR;
+	}
+
+        usrdatum = hashtab_search(policydb->p_users.table, name);
+
+	/* If it does, fail */
+	if (usrdatum) {
+		__sepol_debug_printf("%s: %s is already in the policy\n", 
+			__FUNCTION__, name);
+		free(name);
+		return SEPOL_ERR;	
+	}
+	
+	else {
+		free(name);
+		return sepol_load_user_policy(policydb, user);
+	}
+}
+
+/* Delete a user from the given policydb. This function will
+ * fail if the user does not exist. */
+
+int sepol_del_user_policy(policydb_t* policydb, const char* username) {
+	user_datum_t* usrdatum;
+	struct kill_user_data kud;
+
+	char* name = strdup(username);
+	if (!name) {
+		__sepol_debug_printf("%s: out of memory for %s\n", 
+			__FUNCTION__, username);
+		return SEPOL_ERR;
+	}
+	
+	/* See if such a user exists */
+	usrdatum = hashtab_search(policydb->p_users.table, name);
+
+	/* If not, fail */
+	if (usrdatum == NULL) {
+		__sepol_debug_printf("%s: %s does not exist in the policy\n", 
+			__FUNCTION__, name);
+		errno = EIO;
+		goto err;
+	}
+	else {
+		kud.policydb = policydb;
+		kud.free_users = NULL; /* FIXME? */
+
+		hashtab_remove(
+			policydb->p_users.table, name, 
+			&kill_user, &kud);
+
+	}
+
+	free(name);
+	return SEPOL_SUCCESS;
+err:
+
+	free(name);
+	return SEPOL_ERR;
+}
+
+/* Load a user into policydb. The user may exist already, in
+ * which case the supplied data replaces the existing data. Alternatively,
+ * the user could be new. */
+
+int sepol_load_user_policy(policydb_t* policydb, user_config_t user) {
+
+	/* For user data */
+	const char* tmp;
+	char *name, *role, *mls_level, *mls_range;
+	user_datum_t* usrdatum = NULL;
+	role_datum_t* roldatum;
+	context_struct_t context;
+	unsigned bit;
+	int new = 0;
+
+	/* See if a user exists */
+	name = strdup(uc_get_name(user));
+	if (!name) {
+		__sepol_debug_printf("%s: out of memory for %s\n", 
+			__FUNCTION__, uc_get_name(user));
+		return SEPOL_ERR;
+	}
+
+	usrdatum = hashtab_search(policydb->p_users.table, name);
+
+	/* If it does, we will modify it */
+	if (usrdatum) {
+		ebitmap_init(&usrdatum->roles);
+		usrdatum->defined = 1;
+
+	/* Otherwise, create a new one */
+	} else {
+		usrdatum = (user_datum_t *) malloc(sizeof(user_datum_t));
+		if (!usrdatum) {
+			__sepol_debug_printf("%s:  out of memory for %s\n",
+				 __FUNCTION__, name);
+			free(name);
+			errno = ENOMEM;
+			return SEPOL_ERR;
+		}
+		memset(usrdatum, 0, sizeof(user_datum_t));
+		ebitmap_init(&usrdatum->roles);
+		usrdatum->defined = 1;
+		new = 1;
+	}
+
+	uc_iter_init(user);
+
+	/* For every role */
+	while ((tmp = uc_next_role(user))) {
+		role = strdup(tmp);
+		if (!role) {
+			__sepol_debug_printf("%s: out of memory for %s\n", 
+				__FUNCTION__, name);
+			goto err;
+		}
+
+		/* Search for the role */
+		roldatum = hashtab_search(policydb->p_roles.table, role);
+		if (!roldatum) {
+			__sepol_debug_printf("%s: undefined role "
+				"%s for user %s\n", 
+				__FUNCTION__, role, name);
+
+			errno = EIO;
+			free(role);
+			goto err;	
+		}
+
+		/* Set the role and every role it dominates */
+		for (bit = ebitmap_startbit(&roldatum->dominates); 
+		     bit < ebitmap_length(&roldatum->dominates); bit++) {
+
+			if (ebitmap_get_bit(&roldatum->dominates, bit)) {
+				if (ebitmap_set_bit(&usrdatum->roles, bit, 1)) {
+					__sepol_debug_printf("%s:"
+					"  out of memory for %s\n", 
+					__FUNCTION__, name);
+
+					errno = ENOMEM;
+					free(role);
+					goto err;
+				}
+			}
+		}
+		
+		free(role);
+	}
+
+	/* MLS level */
+	if (mls_enabled) {
+		context_init(&context);
+
+		if (uc_get_mls_level(user) == NULL) {
+			__sepol_debug_printf("%s: no mls level for user %s\n", 
+				__FUNCTION__, name);
+			errno = EIO;
+			goto err;
+		}
+
+		mls_level = strdup(uc_get_mls_level(user));
+		if (!mls_level) {
+			__sepol_debug_printf("%s: out of memory for %s\n", 
+				__FUNCTION__, name);
+			goto err;
+		}
+
+		if (mls_context_to_sid(policydb, '$', &mls_level, &context)) {
+			__sepol_debug_printf("%s:  invalid level %s for user %s\n", 
+				__FUNCTION__, mls_level, name);
+			errno = EIO;
+			free(mls_level);
+			goto err;
+		}
+		free(mls_level);
+		memcpy(&usrdatum->dfltlevel, 
+		       &context.range.level[0], 
+		        sizeof(usrdatum->dfltlevel));
+		
+		/* MLS range */
+		context_init(&context);
+		if (uc_get_mls_range(user) == NULL) {
+			__sepol_debug_printf("%s: no mls range for user %s\n", 
+				__FUNCTION__, name);
+			errno = EIO;
+			goto err;
+		}	
+
+		mls_range = strdup(uc_get_mls_level(user));
+		if (!mls_range) {
+			__sepol_debug_printf("%s: out of memory for %s\n", 
+				__FUNCTION__, name);
+			goto err;
+		}
+
+		if (mls_context_to_sid(policydb, '$', &mls_range, &context)) {
+			__sepol_debug_printf("%s: invalid range %s for user %s\n", 
+				__FUNCTION__, mls_range, name);
+			errno = EIO;
+			free(mls_range);
+			goto err;
+		}
+		free(mls_range);
+		memcpy(&usrdatum->range, &context.range, sizeof(usrdatum->range));
+	}
+
+	/* If there are no errors, and this is a new user, add the user to policy */
+	if (new) {
+		char *id = strdup(name);
+		if (!id) {
+			__sepol_debug_printf("%s: out of memory for %s\n", 
+				__FUNCTION__, name); 
+			goto err;
+		}
+
+		usrdatum->value = ++policydb->p_users.nprim;
+		if (hashtab_insert(policydb->p_users.table, 
+			id, (hashtab_datum_t) usrdatum)) {
+
+			__sepol_debug_printf("%s: out of memory for %s\n", 
+				__FUNCTION__, name);
+
+			errno = ENOMEM;
+			free(id);
+			goto err;
+		}
+	}
+
+	free(name);
+	return SEPOL_SUCCESS;
+
+	err:
+		free(name);
+		free(usrdatum);
+		return SEPOL_ERR;
+}


This mailing list archive is a service of Copilot Consulting.