--- /dev/null
+--- checkpolicy-1.4/policy_parse.y.excludetypes 2004-01-20 18:11:12.024833429 -0500
++++ checkpolicy-1.4/policy_parse.y 2004-01-20 18:11:12.044834543 -0500
+@@ -520,6 +520,8 @@
+ | tilde nested_id_set
+ { if (insert_id("~", 0)) return -1;
+ if (insert_separator(0)) return -1; }
++ | identifier '-' { if (insert_id("-", 0)) return -1; } identifier
++ { if (insert_separator(0)) return -1; }
+ ;
+ tilde_push : tilde
+ { if (insert_id("~", 1)) return -1; }
+@@ -546,7 +548,7 @@
+ ;
+ nested_id_list : nested_id_element | nested_id_list nested_id_element
+ ;
+-nested_id_element : identifier | nested_id_set
++nested_id_element : identifier | '-' { if (insert_id("-", 0)) return -1; } identifier | nested_id_set
+ ;
+ identifier : IDENTIFIER
+ { if (insert_id(yytext,0)) return -1; }
+@@ -1661,15 +1663,19 @@
+
+
+ static int set_types(ebitmap_t *set,
+- char *id)
++ ebitmap_t *negset,
++ char *id,
++ int *add)
+ {
+ type_datum_t *t;
+ unsigned int i;
+
+ if (strcmp(id, "*") == 0) {
+- /* set all types */
+- for (i = 0; i < policydbp->p_types.nprim; i++)
+- ebitmap_set_bit(set, i, TRUE);
++ /* set all types not in negset */
++ for (i = 0; i < policydbp->p_types.nprim; i++) {
++ if (!ebitmap_get_bit(negset, i))
++ ebitmap_set_bit(set, i, TRUE);
++ }
+ free(id);
+ return 0;
+ }
+@@ -1686,6 +1692,12 @@
+ return 0;
+ }
+
++ if (strcmp(id, "-") == 0) {
++ *add = 0;
++ free(id);
++ return 0;
++ }
++
+ t = hashtab_search(policydbp->p_types.table, id);
+ if (!t) {
+ sprintf(errormsg, "unknown type %s", id);
+@@ -1695,18 +1707,42 @@
+ }
+
+ if (t->isattr) {
+- /* set all types with this attribute */
++ /* set or clear all types with this attribute,
++ but do not set anything explicitly cleared previously */
+ for (i = ebitmap_startbit(&t->types); i < ebitmap_length(&t->types); i++) {
+ if (!ebitmap_get_bit(&t->types, i))
+ continue;
+- ebitmap_set_bit(set, i, TRUE);
++ if (!(*add)) {
++ ebitmap_set_bit(set, i, FALSE);
++ ebitmap_set_bit(negset, i, TRUE);
++ } else if (!ebitmap_get_bit(negset, i)) {
++ ebitmap_set_bit(set, i, TRUE);
++#if VERBOSE
++ } else {
++ char *name = type_val_to_name(i+1);
++ sprintf(errormsg, "ignoring %s due to prior -%s", name, name);
++ yywarn(errormsg);
++#endif
++ }
+ }
+ } else {
+- /* set one type */
+- ebitmap_set_bit(set, t->value - 1, TRUE);
++ /* set or clear one type, but do not set anything
++ explicitly cleared previously */
++ if (!(*add)) {
++ ebitmap_set_bit(set, t->value - 1, FALSE);
++ ebitmap_set_bit(negset, t->value - 1, TRUE);
++ } else if (!ebitmap_get_bit(negset, t->value - 1)) {
++ ebitmap_set_bit(set, t->value - 1, TRUE);
++#if VERBOSE
++ } else {
++ sprintf(errormsg, "ignoring %s due to prior -%s", id, id);
++ yywarn(errormsg);
++#endif
++ }
+ }
+
+ free(id);
++ *add = 1;
+ return 0;
+ }
+
+@@ -1718,9 +1754,9 @@
+ avtab_datum_t avdatum, *avdatump;
+ type_datum_t *datum;
+ class_datum_t *cladatum;
+- ebitmap_t stypes, ttypes, tclasses;
++ ebitmap_t stypes, ttypes, tclasses, negset;
+ __u32 newtype = 0;
+- int ret;
++ int ret, add = 1;
+ unsigned int i, j, k;
+
+ if (pass == 1) {
+@@ -1739,15 +1775,19 @@
+ ebitmap_init(&ttypes);
+ ebitmap_init(&tclasses);
+
++ ebitmap_init(&negset);
+ while ((id = queue_remove(id_queue))) {
+- if (set_types(&stypes, id))
++ if (set_types(&stypes, &negset, id, &add))
+ return -1;
+ }
++ ebitmap_destroy(&negset);
+
++ ebitmap_init(&negset);
+ while ((id = queue_remove(id_queue))) {
+- if (set_types(&ttypes, id))
++ if (set_types(&ttypes, &negset, id, &add))
+ return -1;
+ }
++ ebitmap_destroy(&negset);
+
+ while ((id = queue_remove(id_queue))) {
+ cladatum = hashtab_search(policydbp->p_classes.table, id);
+@@ -1964,10 +2004,10 @@
+ char *id;
+ class_datum_t *cladatum;
+ perm_datum_t *perdatum;
+- ebitmap_t stypes, ttypes, tclasses;
++ ebitmap_t stypes, ttypes, tclasses, negset;
+ access_vector_t *avp;
+ unsigned int i, j, hiclass;
+- int self = 0;
++ int self = 0, add = 1;
+ te_assert_t *newassert;
+
+ if (pass == 1) {
+@@ -1986,19 +2026,23 @@
+ ebitmap_init(&ttypes);
+ ebitmap_init(&tclasses);
+
++ ebitmap_init(&negset);
+ while ((id = queue_remove(id_queue))) {
+- if (set_types(&stypes, id))
++ if (set_types(&stypes, &negset, id, &add))
+ return -1;
+ }
++ ebitmap_destroy(&negset);
+
++ ebitmap_init(&negset);
+ while ((id = queue_remove(id_queue))) {
+ if (strcmp(id, "self") == 0) {
+ self = 1;
+ continue;
+ }
+- if (set_types(&ttypes, id))
++ if (set_types(&ttypes, &negset, id, &add))
+ return -1;
+ }
++ ebitmap_destroy(&negset);
+
+ hiclass = 0;
+ while ((id = queue_remove(id_queue))) {
+@@ -2139,7 +2183,8 @@
+ {
+ role_datum_t *role;
+ char *role_id, *id;
+- int ret;
++ int ret, add = 1;
++ ebitmap_t negset;
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+@@ -2173,10 +2218,12 @@
+ } else
+ free(role_id);
+
++ ebitmap_init(&negset);
+ while ((id = queue_remove(id_queue))) {
+- if (set_types(&role->types, id))
++ if (set_types(&role->types, &negset, id, &add))
+ return -1;
+ }
++ ebitmap_destroy(&negset);
+
+ return 0;
+ }
+@@ -2325,9 +2372,10 @@
+ {
+ char *id;
+ role_datum_t *role;
+- ebitmap_t roles, types;
++ ebitmap_t roles, types, negset;
+ struct role_trans *tr = 0;
+ unsigned int i, j;
++ int add = 1;
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+@@ -2347,10 +2395,12 @@
+ return -1;
+ }
+
++ ebitmap_init(&negset);
+ while ((id = queue_remove(id_queue))) {
+- if (set_types(&types, id))
++ if (set_types(&types, &negset, id, &add))
+ return -1;
+ }
++ ebitmap_destroy(&negset);
+
+ id = (char *) queue_remove(id_queue);
+ if (!id) {
+@@ -2587,8 +2637,10 @@
+ struct constraint_expr *expr, *e1 = NULL, *e2;
+ user_datum_t *user;
+ role_datum_t *role;
++ ebitmap_t negset;
+ char *id;
+ __u32 val;
++ int add = 1;
+
+ if (pass == 1) {
+ if (expr_type == CEXPR_NAMES) {
+@@ -2656,6 +2708,7 @@
+ case CEXPR_NAMES:
+ expr->attr = arg1;
+ expr->op = arg2;
++ ebitmap_init(&negset);
+ while ((id = (char *) queue_remove(id_queue))) {
+ if (expr->attr & CEXPR_USER) {
+ user = (user_datum_t *) hashtab_search(policydbp->p_users.table,
+@@ -2678,7 +2731,7 @@
+ }
+ val = role->value;
+ } else if (expr->attr & CEXPR_TYPE) {
+- if (set_types(&expr->names, id)) {
++ if (set_types(&expr->names, &negset, id, &add)) {
+ free(expr);
+ return 0;
+ }
+@@ -2696,6 +2749,7 @@
+ }
+ free(id);
+ }
++ ebitmap_destroy(&negset);
+ return (uintptr_t)expr;
+ default:
+ yyerror("invalid constraint expression");
--- /dev/null
+diff -ur checkpolicy-1.4.orig/checkpolicy.c checkpolicy-1.4/checkpolicy.c
+--- checkpolicy-1.4.orig/checkpolicy.c 2003-12-01 14:24:57.000000000 -0500
++++ checkpolicy-1.4/checkpolicy.c 2003-12-15 02:50:48.000000000 -0500
+@@ -45,6 +45,8 @@
+ extern queue_t id_queue;
+ extern unsigned int policydb_errors;
+ extern unsigned long policydb_lineno;
++extern unsigned long source_lineno;
++extern char source_file[];
+ extern unsigned int pass;
+ extern unsigned int ss_initialized;
+
+@@ -400,6 +402,8 @@
+ }
+ rewind(yyin);
+ policydb_lineno = 1;
++ source_file[0] = '\0';
++ source_lineno = 1;
+ yyrestart(yyin);
+ pass = 2;
+ if (yyparse() || policydb_errors) {
+diff -ur checkpolicy-1.4.orig/policy_parse.y checkpolicy-1.4/policy_parse.y
+--- checkpolicy-1.4.orig/policy_parse.y 2003-10-24 10:23:09.000000000 -0400
++++ checkpolicy-1.4/policy_parse.y 2003-12-15 02:30:59.000000000 -0500
+@@ -18,6 +18,8 @@
+ policydb_t *policydbp;
+ queue_t id_queue = 0;
+ unsigned int pass;
++char *curfile = 0;
++unsigned int curline;
+
+ extern unsigned long policydb_lineno;
+
+diff -ur checkpolicy-1.4.orig/policy_scan.l checkpolicy-1.4/policy_scan.l
+--- checkpolicy-1.4.orig/policy_scan.l 2003-06-26 13:23:12.000000000 -0400
++++ checkpolicy-1.4/policy_scan.l 2003-12-15 02:51:18.000000000 -0500
+@@ -11,6 +11,9 @@
+ static char linebuf[2][255];
+ static unsigned int lno = 0;
+
++char source_file[255];
++unsigned long source_lineno = 1;
++
+ unsigned long policydb_lineno = 1;
+
+ unsigned int policydb_errors = 0;
+@@ -23,6 +26,7 @@
+ linebuf[lno][254] = 0;
+ lno = 1 - lno;
+ policydb_lineno++;
++ source_lineno++;
+ yyless(1); }
+ CLONE |
+ clone { return(CLONE); }
+@@ -130,6 +134,8 @@
+ {letter}({letter}|{digit}|_)* { return(IDENTIFIER); }
+ {letter}({letter}|{digit}|_|"."|"-")* { return(USER_IDENTIFIER); }
+ {digit}{digit}* { return(NUMBER); }
++#line[ ]1[ ]\"[^\n]*\" { source_lineno = 1; strncpy(source_file, yytext+9, 255); source_file[strlen(source_file)-1] = '\0'; }
++#line[ ]{digit}{digit}* { source_lineno = atoi(yytext+6)-1; }
+ #[^\n]* { /* delete comments */ }
+ [ \t\f]+ { /* delete whitespace */ }
+ "==" { return(EQUALS); }
+@@ -154,6 +160,11 @@
+ %%
+ int yyerror(char *msg)
+ {
++ if (source_file[0])
++ fprintf(stderr, "%s:%ld:",
++ source_file, source_lineno);
++ else
++ fprintf(stderr, "(unknown source)::");
+ fprintf(stderr, "ERROR '%s' at token '%s' on line %ld:\n%s\n%s\n",
+ msg,
+ yytext,
+@@ -165,6 +176,11 @@
+
+ int yywarn(char *msg)
+ {
++ if (source_file[0])
++ fprintf(stderr, "%s:%ld:",
++ source_file, source_lineno);
++ else
++ fprintf(stderr, "(unknown source)::");
+ fprintf(stderr, "WARNING '%s' at token '%s' on line %ld:\n%s\n%s\n",
+ msg,
+ yytext,
+@@ -172,5 +188,3 @@
+ linebuf[0], linebuf[1]);
+ return 0;
+ }
+-
+-
--- /dev/null
+Index: checkpolicy/policy_parse.y
+===================================================================
+RCS file: /nfshome/pal/CVS/selinux-usr/checkpolicy/policy_parse.y,v
+retrieving revision 1.11
+diff -u -r1.11 policy_parse.y
+--- checkpolicy/policy_parse.y 15 Jan 2004 14:23:02 -0000 1.11
++++ checkpolicy/policy_parse.y 15 Jan 2004 17:48:45 -0000
+@@ -42,6 +42,7 @@
+ static int define_common_base(void);
+ static int define_av_base(void);
+ static int define_attrib(void);
++static int define_typealias(void);
+ static int define_type(int alias);
+ static int define_compute_type(int which);
+ static int define_te_avtab(int which);
+@@ -82,6 +83,7 @@
+ %token SID
+ %token ROLE
+ %token ROLES
++%token TYPEALIAS
+ %token TYPE
+ %token TYPES
+ %token ALIAS
+@@ -240,6 +242,7 @@
+ ;
+ te_decl : attribute_def
+ | type_def
++ | typealias_def
+ | transition_def
+ | te_avtab_def
+ ;
+@@ -251,6 +254,9 @@
+ | TYPE identifier opt_attr_list ';'
+ {if (define_type(0)) return -1;}
+ ;
++typealias_def : TYPEALIAS identifier alias_def
++ {if (define_typealias()) return -1;}
++ ;
+ opt_attr_list : ',' id_comma_list
+ |
+ ;
+@@ -1479,6 +1485,61 @@
+ return 0;
+ }
+
++static int define_typealias(void)
++{
++ char *id;
++ type_datum_t *t, *aliasdatum;;
++ int ret;
++
++
++ if (pass == 2) {
++ while ((id = queue_remove(id_queue)))
++ free(id);
++ return 0;
++ }
++
++ id = (char *) queue_remove(id_queue);
++ if (!id) {
++ yyerror("no type name for typealias definition?");
++ return -1;
++ }
++
++ t = hashtab_search(policydbp->p_types.table, id);
++ if (!t || t->isattr) {
++ sprintf(errormsg, "unknown type %s", id);
++ yyerror(errormsg);
++ free(id);
++ return -1;
++ }
++
++ while ((id = queue_remove(id_queue))) {
++ aliasdatum = (type_datum_t *) malloc(sizeof(type_datum_t));
++ if (!aliasdatum) {
++ yyerror("out of memory");
++ return -1;
++ }
++ memset(aliasdatum, 0, sizeof(type_datum_t));
++ aliasdatum->value = t->value;
++
++ ret = hashtab_insert(policydbp->p_types.table,
++ (hashtab_key_t) id, (hashtab_datum_t) aliasdatum);
++
++ if (ret == HASHTAB_PRESENT) {
++ sprintf(errormsg, "name conflict for type alias %s", id);
++ yyerror(errormsg);
++ free(aliasdatum);
++ free(id);
++ return -1;
++ }
++ if (ret == HASHTAB_OVERFLOW) {
++ yyerror("hash table overflow");
++ free(aliasdatum);
++ free(id);
++ return -1;
++ }
++ }
++ return 0;
++}
+
+ static int define_type(int alias)
+ {
+Index: checkpolicy/policy_scan.l
+===================================================================
+RCS file: /nfshome/pal/CVS/selinux-usr/checkpolicy/policy_scan.l,v
+retrieving revision 1.3
+diff -u -r1.3 policy_scan.l
+--- checkpolicy/policy_scan.l 17 Dec 2003 16:52:20 -0000 1.3
++++ checkpolicy/policy_scan.l 15 Jan 2004 17:33:23 -0000
+@@ -46,6 +46,8 @@
+ roles { return(ROLES); }
+ TYPES |
+ types { return(TYPES); }
++TYPEALIAS |
++typealias { return(TYPEALIAS); }
+ TYPE |
+ type { return(TYPE); }
+ ALIAS |