Project import
diff --git a/checkpolicy/Android.mk b/checkpolicy/Android.mk
new file mode 100644
index 0000000..ee2f158
--- /dev/null
+++ b/checkpolicy/Android.mk
@@ -0,0 +1,66 @@
+LOCAL_PATH:= $(call my-dir)
+
+common_src_files := \
+	policy_parse.y \
+	policy_scan.l \
+	queue.c \
+	module_compiler.c \
+	parse_util.c \
+	policy_define.c
+
+common_cflags := \
+	-Wall -Wshadow -O2 \
+	-pipe -fno-strict-aliasing \
+
+common_includes := \
+	$(LOCAL_PATH)/ \
+	$(LOCAL_PATH)/../libsepol/include/ \
+	$(LOCAL_PATH)/../libsepol/src/ \
+
+##
+# checkpolicy
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := checkpolicy
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) 
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES := $(common_src_files) checkpolicy.c
+LOCAL_STATIC_LIBRARIES := libsepol
+LOCAL_YACCFLAGS := -v
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+include $(BUILD_HOST_EXECUTABLE)
+
+
+##
+# checkmodule
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := checkmodule
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) 
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES := $(common_src_files) checkmodule.c
+LOCAL_STATIC_LIBRARIES := libsepol
+LOCAL_YACCFLAGS := -v
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+include $(BUILD_HOST_EXECUTABLE)
+
+##
+# dispol
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := dispol
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes)
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES := test/dispol.c
+LOCAL_STATIC_LIBRARIES := libsepol
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/checkpolicy/COPYING b/checkpolicy/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/checkpolicy/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/checkpolicy/ChangeLog b/checkpolicy/ChangeLog
new file mode 100644
index 0000000..429a163
--- /dev/null
+++ b/checkpolicy/ChangeLog
@@ -0,0 +1,488 @@
+	* Set flex as default lexer, from Julien Pivotto.
+	* Fix checkmodule output message, from Petr Lautrbach.
+	* Build policy on systems not supporting DCCP protocol, from Richard Haines.
+	* Fail if module name different than output base filename, from James Carter
+	* Add support for portcon dccp protocol, from Richard Haines
+
+2.5 2016-02-23
+	* Add neverallow support for ioctl extended permissions, from Jeff Vander Stoep.
+	* fix double free on name-based type transitions, from Stephen Smalley.
+	* switch operations to extended perms, from Jeff Vander Stoep.
+	* policy_define.c: fix compiler warnings, from Nick Kralevich.
+	* Remove uses of -Wno-return-type, from Dan Albert.
+	* Fix -Wreturn-type issues, from Dan Albert.
+	* dispol: display operations as ranges, from Jeff Vander Stoep.
+	* dispol: Extend to display operations, from Stephen Smalley.
+	* Add support for ioctl command whitelisting, from Jeff Vander Stoep.
+	* Add option to write CIL policy, from James Carter
+	* Add device tree ocontext nodes to Xen policy, from Daniel De Graaf.
+	* Widen Xen IOMEM context entries, from Daniel De Graaf.
+	* Expand allowed character set in paths, from Daniel De Graaf.
+	* Fix precedence between number and filesystem tokens, from Stephen Smalley.
+	* dispol/dismod fgets function warnings fix, from Emre Can Kucukoglu.
+
+2.4 2015-02-02
+	* Fix bugs found by hardened gcc flags, from Nicolas Iooss.
+	* Add missing semicolon in cond_else parser rule, from Steven Capelli.
+	* Clear errno before call to strtol(3) from Dan Albert.
+	* Global C++11 compatibility from Dan Albert.
+	* Allow libsepol C++ static library on device from Daniel Cashman.
+
+2.3 2014-05-06
+	* Add Android support for building dispol.
+	* Report source file and line information for neverallow failures.
+	* Prevent incompatible option combinations for checkmodule.
+	* Drop -lselinux from LDLIBS for test programs; not used.
+	* Add debug feature to display constraints/validatetrans from Richard Haines.
+
+2.2 2013-10-30
+	* Fix hyphen usage in man pages from Laurent Bigonville.
+	* handle-unknown / -U required argument fix from Laurent Bigonville.
+	* Support overriding Makefile PATH and LIBDIR from Laurent Bigonville.
+	* Support space and : in filenames from Dan Walsh.
+
+2.1.12 2013-02-01
+	* Fix errors found by coverity
+	* implement default type policy syntax
+	* Free allocated memory when clean up / exit.
+
+2.1.11 2012-09-13
+	* fd leak reading policy
+	* check return code on ebitmap_set_bit
+
+2.1.10 2012-06-28
+	* sepolgen: We need to support files that have a + in them
+	* Android/MacOS X build support
+
+2.1.9 2012-03-28
+	* implement new default labeling behaviors for usr, role, range
+	* Fix dead links to www.nsa.gov/selinux
+
+2.1.8 2011-12-21
+	* add new helper to translate class sets into bitmaps
+
+2.1.7 2011-12-05
+	* dis* fixed signed vs unsigned errors
+	* dismod: fix unused parameter errors
+	* test: Makefile: include -W and -Werror
+	* allow ~ in filename transition rules
+
+2.1.6 2011-11-03
+	* Revert "checkpolicy: Redo filename/filesystem syntax to support filename trans rules"
+	* drop libsepol dynamic link in checkpolicy
+
+2.1.5 2011-09-15
+	* Separate tunable from boolean during compile.
+
+2.1.4 2011-08-26
+	* checkpolicy: fix spacing in output message
+
+2.1.3 2011-08-17
+	* add missing ; to attribute_role_def
+	*Redo filename/filesystem syntax to support filename trans
+
+2.1.2 2011-08-02
+	* .gitignore changes
+	* dispol output of role trans
+	* man page update: build a module with an older policy version
+
+2.1.1 2011-08-01
+	* Minor updates to filename trans rule output in dis{mod,pol}
+
+2.1.0 2011-07-27
+	* Release, minor version bump
+
+2.0.27 2011-07-25
+	* Add role attribute support by Harry Ciao
+
+2.0.26 2011-05-16
+	* Wrap file names in filename transitions with quotes by Steve Lawrence.
+	* Allow filesystem names to start with a digit by James Carter.
+
+2.0.25 2011-05-02
+	* Add support for using the last path compnent in type transitions by Eric
+	Paris.
+	* Allow single digit module versions by Daniel Walsh.
+	* Use better filename identifier for filenames by Daniel Walsh.
+	* Use #defines for dismod selections by Eric Paris.
+
+2.0.24 2011-04-11
+	* Add new class field in role_transition by Harry Ciao.
+
+2.0.23 2010-12-16
+	* Remove unused variables to fix compliation under GCC 4.6 by Justin Mattock
+
+2.0.22 2010-06-14
+	* Update checkmodule man page and usage by Daniel Walsh and Steve Lawrence
+
+2.0.21 2009-11-27
+	* Add long options to checkpolicy and checkmodule by Guido
+	  Trentalancia <guido@trentalancia.com>
+
+2.0.20 2009-10-14
+	* Add support for building Xen policies from Paul Nuzzi.
+
+2.0.19 2009-02-18
+	* Fix alias field in module format, caused by boundary format change
+	  from Caleb Case.
+
+2.0.18 2008-10-14
+	* Properly escape regex symbols in the lexer from Stephen Smalley.
+
+2.0.17 2008-10-09
+	* Add bounds support from KaiGai Kohei.
+
+2.0.16 2008-05-27
+	* Update checkpolicy for user and role mapping support from Joshua Brindle.
+
+2.0.15 2008-05-05
+	* Fix for policy module versions that look like IPv4 addresses from Jim Carter.
+	  Resolves bug 444451.
+
+2.0.14 2008-03-24
+	* Add permissive domain support from Eric Paris.
+
+2.0.13 2008-03-05
+	* Split out non-grammar parts of policy_parse.yacc into
+	  policy_define.c and policy_define.h from Todd C. Miller.
+
+2.0.12 2008-03-04
+	* Initialize struct policy_file before using it, from Todd C. Miller.
+
+2.0.11 2008-03-03
+	* Remove unused define, move variable out of .y file, simplify COND_ERR, from Todd C. Miller.
+
+2.0.10 2008-02-28
+	* Use yyerror2() where appropriate from Todd C. Miller.
+
+2.0.9 2008-02-04
+	* Update dispol for libsepol avtab changes from Stephen Smalley.
+
+2.0.8 2008-01-24
+	* Deprecate role dominance in parser.
+
+2.0.7 2008-01-02
+	* Added support for policy capabilities from Todd Miller.
+
+2.0.6 2007-11-15
+	* Initialize the source file name from the command line argument so that checkpolicy/checkmodule report something more useful than "unknown source".
+
+2.0.5 2007-11-01
+	* Merged remove use of REJECT and trailing context in lex rules; make ipv4 address parsing like ipv6 from James Carter.
+
+2.0.4 2007-09-18
+	* Merged handle unknown policydb flag support from Eric Paris.
+	  Adds new command line options -U {allow, reject, deny} for selecting
+	  the flag when a base module or kernel policy is built.
+
+2.0.3 2007-05-31
+	* Merged fix for segfault on duplicate require of sensitivity from Caleb Case.
+	* Merged fix for dead URLs in checkpolicy man pages from Dan Walsh.
+
+2.0.2 2007-04-12
+	* Merged checkmodule man page fix from Dan Walsh.
+
+2.0.1 2007-02-20
+	* Merged patch to allow dots in class identifiers from Caleb Case.
+
+2.0.0 2007-02-01
+	* Merged patch to use new libsepol error codes by Karl MacMillan.
+
+1.34.0 2007-01-18
+	* Updated version for stable branch.
+
+1.33.1 2006-11-13
+	* Collapse user identifiers and identifiers together.
+
+1.32 2006-10-17
+	* Updated version for release.
+
+1.30.12 2006-09-28
+	* Merged user and range_transition support for modules from 
+	  Darrel Goeddel
+
+1.30.11 2006-09-05
+	* merged range_transition enhancements and user module format
+	  changes from Darrel Goeddel
+
+1.30.10 2006-08-03
+	* Merged symtab datum patch from Karl MacMillan.
+
+1.30.9 2006-06-29
+	* Lindent.
+
+1.30.8 2006-06-29
+	* Merged patch to remove TE rule conflict checking from the parser
+	  from Joshua Brindle.  This can only be done properly by the 
+	  expander.
+
+1.30.7 2006-06-27
+	* Merged patch to make checkpolicy/checkmodule handling of
+	  duplicate/conflicting TE rules the same as the expander 
+	  from Joshua Brindle.
+
+1.30.6 2006-06-26
+	* Merged optionals in base take 2 patch set from Joshua Brindle.
+
+1.30.5 2006-05-05
+	* Merged compiler cleanup patch from Karl MacMillan.
+	* Merged fix warnings patch from Karl MacMillan.	
+
+1.30.4 2006-04-05
+	* Changed require_class to reject permissions that have not been
+	  declared if building a base module.
+
+1.30.3 2006-03-28
+	* Fixed checkmodule to call link_modules prior to expand_module
+	  to handle optionals.
+
+1.30.2 2006-03-28
+	* Fixed require_class to avoid shadowing permissions already defined
+	  in an inherited common definition.
+
+1.30.1 2006-03-22
+	* Moved processing of role and user require statements to 2nd pass.
+
+1.30 2006-03-14
+	* Updated version for release.
+
+1.29.5 2006-03-09
+	* Fixed bug in role dominance (define_role_dom).
+
+1.29.4 2006-02-14
+	* Added a check for failure to declare each sensitivity in
+	  a level definition.
+
+1.29.3 2006-02-13
+	* Changed to clone level data for aliased sensitivities to
+	  avoid double free upon sens_destroy.  Bug reported by Kevin
+	  Carr of Tresys Technology.
+
+1.29.2 2006-02-13
+	* Merged optionals in base patch from Joshua Brindle.
+
+1.29.1 2006-02-01
+	* Merged sepol_av_to_string patch from Joshua Brindle.
+
+1.28 2005-12-07
+	* Updated version for release.
+
+1.27.20 2005-12-02
+	* Merged checkmodule man page from Dan Walsh, and edited it.
+
+1.27.19 2005-12-01
+	* Added error checking of all ebitmap_set_bit calls for out of
+	  memory conditions.
+
+1.27.18 2005-12-01
+	* Merged removal of compatibility handling of netlink classes
+	  (requirement that policies with newer versions include the
+	   netlink class definitions, remapping of fine-grained netlink
+	   classes in newer source policies to single netlink class when
+	   generating older policies) from George Coker.
+
+1.27.17 2005-10-25
+	* Merged dismod fix from Joshua Brindle.
+
+1.27.16 2005-10-20
+	* Removed obsolete cond_check_type_rules() function and call and 
+	  cond_optimize_lists() call from checkpolicy.c; these are handled
+	  during parsing and expansion now.
+
+1.27.15 2005-10-19
+	* Updated calls to expand_module for interface change.
+
+1.27.14 2005-10-19
+	* Changed checkmodule to verify that expand_module succeeds 
+	  when building base modules.
+
+1.27.13 2005-10-19
+	* Merged module compiler fixes from Joshua Brindle.
+
+1.27.12 2005-10-19
+	* Removed direct calls to hierarchy_check_constraints() and 
+	  check_assertions() from checkpolicy since they are now called 
+	  internally by expand_module().
+
+1.27.11 2005-10-18
+	* Updated for changes to sepol policydb_index_others interface.
+
+1.27.10 2005-10-17
+	* Updated for changes to sepol expand_module and link_modules interfaces.
+
+1.27.9 2005-10-13
+	* Merged support for require blocks inside conditionals from
+	Joshua Brindle (Tresys).
+
+1.27.8 2005-10-06
+	* Updated for changes to libsepol.
+
+1.27.7 2005-10-05
+	* Merged several bug fixes from Joshua Brindle (Tresys).
+
+1.27.6 2005-10-03
+	* Merged MLS in modules patch from Joshua Brindle (Tresys).
+
+1.27.5 2005-09-28
+	* Merged error handling improvement in checkmodule from Karl MacMillan (Tresys).
+
+1.27.4 2005-09-26
+	* Merged bugfix for dup role transition error messages from
+	Karl MacMillan (Tresys).
+
+1.27.3 2005-09-23
+	* Merged policyver/modulever patches from Joshua Brindle (Tresys).
+	
+1.27.2 2005-09-20
+	* Fixed parse_categories handling of undefined category.
+
+1.27.1 2005-09-16
+	* Merged bug fix for role dominance handling from Darrel Goeddel (TCS). 
+
+1.26 2005-09-06
+	* Updated version for release.
+
+1.25.12 2005-08-22
+	* Fixed handling of validatetrans constraint expressions.
+	Bug reported by Dan Walsh for checkpolicy -M.
+
+1.25.11 2005-08-18
+	* Merged use-after-free fix from Serge Hallyn (IBM).  
+	  Bug found by Coverity.
+
+1.25.10 2005-08-15
+	* Fixed further memory leaks found by valgrind.
+
+1.25.9 2005-08-15
+	* Changed checkpolicy to destroy the policydbs prior to exit
+	  to allow leak detection.
+	* Fixed several memory leaks found by valgrind.
+
+1.25.8 2005-08-11
+	* Updated checkpolicy and dispol for the new avtab format.
+	  Converted users of ebitmaps to new inline operators.
+  	  Note:  The binary policy format version has been incremented to 
+	  version 20 as a result of these changes.  To build a policy
+	  for a kernel that does not yet include these changes, use
+	  the -c 19 option to checkpolicy.
+
+1.25.7 2005-08-11
+	* Merged patch to prohibit use of "self" as a type name from Jason Tang (Tresys).
+
+1.25.6 2005-08-10
+	* Merged patch to fix dismod compilation from Joshua Brindle (Tresys).
+
+1.25.5 2005-08-09
+	* Fixed call to hierarchy checking code to pass the right policydb.
+
+1.25.4 2005-08-02
+	* Merged patch to update dismod for the relocation of the
+	  module read/write code from libsemanage to libsepol, and
+	  to enable build of test subdirectory from Jason Tang (Tresys).
+
+1.25.3 2005-07-18
+	* Merged hierarchy check fix from Joshua Brindle (Tresys).
+
+1.25.2 2005-07-06
+	* Merged loadable module support from Tresys Technology.
+
+1.25.1 2005-06-24
+	* Merged patch to prohibit the use of * and ~ in type sets 
+	  (other than in neverallow statements) and in role sets
+	  from Joshua Brindle (Tresys).
+
+1.24 2005-06-20
+	* Updated version for release.
+
+1.23.4 2005-05-19
+	* Merged cleanup patch from Dan Walsh.
+
+1.23.3 2005-05-13
+	* Added sepol_ prefix to Flask types to avoid namespace
+	  collision with libselinux.
+
+1.23.2 2005-04-29
+	* Merged identifier fix from Joshua Brindle (Tresys).
+	
+1.23.1 2005-04-13
+	* Merged hierarchical type/role patch from Tresys Technology.
+	* Merged MLS fixes from Darrel Goeddel of TCS.
+
+1.22 2005-03-09
+	* Updated version for release.
+
+1.21.4 2005-02-17
+	* Moved genpolusers utility to libsepol.
+	* Merged range_transition support from Darrel Goeddel (TCS).
+
+1.21.3 2005-02-16
+	* Merged define_user() cleanup patch from Darrel Goeddel (TCS).
+
+1.21.2 2005-02-09
+	* Changed relabel Makefile target to use restorecon.
+
+1.21.1 2005-01-26
+	* Merged enhanced MLS support from Darrel Goeddel (TCS).
+
+1.20 2005-01-04
+	* Merged typeattribute statement patch from Darrel Goeddel of TCS.
+	* Changed genpolusers to handle multiple user config files.
+	* Merged nodecon ordering patch from Chad Hanson of TCS.
+
+1.18 2004-10-07
+	* MLS build fix.
+	* Fixed Makefile dependencies (Chris PeBenito).
+	* Merged fix for role dominance ordering issue from Chad Hanson of TCS.
+	* Preserve portcon ordering and apply more checking.
+
+1.16 2004-08-13
+	* Allow empty conditional clauses.
+	* Moved genpolbools utility to libsepol.
+	* Updated for libsepol set functions. 
+	* Changed to link with libsepol.a.
+	* Moved core functionality into libsepol.
+	* Merged bug fix for conditional self handling from Karl MacMillan, Dave Caplan, and Joshua Brindle of Tresys.
+	* Added genpolusers program.
+	* Fixed bug in checkpolicy conditional code.
+
+1.14 2004-06-28
+	* Merged fix for MLS logic from Daniel Thayer of TCS. 
+	* Require semicolon terminator for typealias statement.
+
+1.12 2004-06-16
+	* Merged fine-grained netlink class support.
+
+1.10 2004-04-07
+	* Merged ipv6 support from James Morris of RedHat.
+	* Fixed compute_av bug discovered by Chad Hanson of TCS.
+
+1.8 2004-03-09
+	* Merged policydb MLS patch from Chad Hanson of TCS.
+	* Fixed mmap of policy file.
+
+1.6 2004-02-18
+	* Merged conditional policy extensions from Tresys Technology.
+	* Added typealias declaration support per Russell Coker's request.
+	* Added support for excluding types from type sets based on
+	  a patch by David Caplan, but reimplemented as a change to the
+	  policy grammar.
+	* Merged patch from Colin Walters to report source file name and line
+	  number for errors when available.
+	* Un-deprecated role transitions.
+
+1.4 2003-12-01
+	* Regenerated headers.
+	* Merged patches from Bastian Blank and Joerg Hoh.
+
+1.2 2003-09-30
+	* Merged MLS build patch from Karl MacMillan of Tresys. 
+	* Merged checkpolicy man page from Magosanyi Arpad.
+
+1.1 2003-08-13
+	* Fixed endian bug in policydb_write for behavior value. 
+	* License -> GPL.
+        * Merged coding style cleanups from James Morris. 
+
+1.0 2003-07-11
+	* Initial public release.
+
diff --git a/checkpolicy/Makefile b/checkpolicy/Makefile
new file mode 100644
index 0000000..53a3074
--- /dev/null
+++ b/checkpolicy/Makefile
@@ -0,0 +1,65 @@
+#
+# Makefile for building the checkpolicy program
+#
+PREFIX ?= $(DESTDIR)/usr
+BINDIR ?= $(PREFIX)/bin
+MANDIR ?= $(PREFIX)/share/man
+LIBDIR ?= $(PREFIX)/lib
+INCLUDEDIR ?= $(PREFIX)/include
+TARGETS = checkpolicy checkmodule
+
+LEX = flex
+YACC = bison -y
+
+CFLAGS ?= -g -Wall -Werror -Wshadow -O2 -pipe -fno-strict-aliasing
+
+override CFLAGS += -I. -I${INCLUDEDIR}
+
+CHECKOBJS = y.tab.o lex.yy.o queue.o module_compiler.o parse_util.o \
+	    policy_define.o
+CHECKPOLOBJS = $(CHECKOBJS) checkpolicy.o
+CHECKMODOBJS = $(CHECKOBJS) checkmodule.o
+
+LDLIBS=$(LIBDIR)/libsepol.a -lfl
+
+GENERATED=lex.yy.c y.tab.c y.tab.h
+
+all:  $(TARGETS)
+	$(MAKE) -C test
+
+checkpolicy: $(CHECKPOLOBJS)
+
+checkmodule: $(CHECKMODOBJS)
+
+%.o: %.c 
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+y.tab.o: y.tab.c
+	$(CC) $(filter-out -Werror, $(CFLAGS)) -o $@ -c $<
+
+lex.yy.o: lex.yy.c
+	$(CC) $(filter-out -Werror, $(CFLAGS)) -o $@ -c $<
+
+y.tab.c: policy_parse.y
+	$(YACC) -d policy_parse.y
+
+lex.yy.c: policy_scan.l y.tab.c
+	$(LEX) policy_scan.l
+
+install: all
+	-mkdir -p $(BINDIR)
+	-mkdir -p $(MANDIR)/man8
+	install -m 755 $(TARGETS) $(BINDIR)	
+	install -m 644 checkpolicy.8 $(MANDIR)/man8
+	install -m 644 checkmodule.8 $(MANDIR)/man8
+
+relabel: install
+	/sbin/restorecon $(BINDIR)/checkpolicy
+	/sbin/restorecon $(BINDIR)/checkmodule
+
+clean:
+	-rm -f $(TARGETS) $(CHECKPOLOBJS) $(CHECKMODOBJS) y.tab.c y.tab.h lex.yy.c
+	$(MAKE) -C test clean
+
+indent:
+	../scripts/Lindent $(filter-out $(GENERATED),$(wildcard *.[ch]))
diff --git a/checkpolicy/VERSION b/checkpolicy/VERSION
new file mode 100644
index 0000000..95e3ba8
--- /dev/null
+++ b/checkpolicy/VERSION
@@ -0,0 +1 @@
+2.5
diff --git a/checkpolicy/checkmodule.8 b/checkpolicy/checkmodule.8
new file mode 100644
index 0000000..ee95882
--- /dev/null
+++ b/checkpolicy/checkmodule.8
@@ -0,0 +1,67 @@
+.TH CHECKMODULE 8
+.SH NAME
+checkmodule \- SELinux policy module compiler
+.SH SYNOPSIS
+.B checkmodule
+.I "[\-h] [\-b] [\-C] [\-m] [\-M] [\-U handle_unknown ] [\-V] [\-o output_file] [input_file]"
+.SH "DESCRIPTION"
+This manual page describes the
+.BR checkmodule
+command.
+.PP
+.B checkmodule
+is a program that checks and compiles a SELinux security policy module
+into a binary representation.  It can generate either a base policy
+module (default) or a non-base policy module (\-m option); typically,
+you would build a non-base policy module to add to an existing module
+store that already has a base module provided by the base policy.  Use
+semodule_package to combine this module with its optional file
+contexts to create a policy package, and then use semodule to install
+the module package into the module store and load the resulting policy.
+
+.SH OPTIONS
+.TP
+.B \-b,\-\-binary
+Read an existing binary policy module file rather than a source policy
+module file.  This option is a development/debugging aid.
+.TP
+.B \-C,\-\-cil
+Write CIL policy file rather than binary policy file.
+.TP
+.B \-h,\-\-help
+Print usage.
+.TP
+.B \-m
+Generate a non-base policy module.
+.TP
+.B \-M,\-\-mls
+Enable the MLS/MCS support when checking and compiling the policy module.
+.TP
+.B \-V,\-\-version
+ Show policy versions created by this program.  Note that you cannot currently build older versions.
+.TP
+.B \-o,\-\-output filename
+Write a binary policy module file to the specified filename.
+Otherwise, checkmodule will only check the syntax of the module source file
+and will not generate a binary module at all.
+.TP
+.B \-U,\-\-handle-unknown <action>
+Specify how the kernel should handle unknown classes or permissions (deny, allow or reject).
+
+.SH EXAMPLE
+.nf
+# Build a MLS/MCS-enabled non-base policy module.
+$ checkmodule \-M \-m httpd.te \-o httpd.mod
+.fi
+
+.SH "SEE ALSO"
+.B semodule(8), semodule_package(8)
+SELinux documentation at http://www.nsa.gov/research/selinux,
+especially "Configuring the SELinux Policy".
+
+
+.SH AUTHOR
+This manual page was copied from the checkpolicy man page 
+written by Arpad Magosanyi <mag@bunuel.tii.matav.hu>, 
+and edited by Dan Walsh <dwalsh@redhat.com>.
+The program was written by Stephen Smalley <sds@epoch.ncsc.mil>.
diff --git a/checkpolicy/checkmodule.c b/checkpolicy/checkmodule.c
new file mode 100644
index 0000000..53cc5a0
--- /dev/null
+++ b/checkpolicy/checkmodule.c
@@ -0,0 +1,343 @@
+/*
+ * Authors: Joshua Brindle <jbrindle@tresys.com>
+ *	    Karl MacMillan <kmacmillan@tresys.com>
+ *          Jason Tang     <jtang@tresys.com>
+ *
+ *
+ * Copyright (C) 2004-5 Tresys Technology, LLC
+ *	This program is free software; you can redistribute it and/or modify
+ *  	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, version 2.
+ */
+
+#include <getopt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <libgen.h>
+
+#include <sepol/module_to_cil.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/sidtab.h>
+
+#include "queue.h"
+#include "checkpolicy.h"
+#include "parse_util.h"
+
+extern char *optarg;
+extern int optind;
+
+static sidtab_t sidtab;
+
+extern int mlspol;
+
+static int handle_unknown = SEPOL_DENY_UNKNOWN;
+static const char *txtfile = "policy.conf";
+static const char *binfile = "policy";
+
+unsigned int policy_type = POLICY_BASE;
+unsigned int policyvers = MOD_POLICYDB_VERSION_MAX;
+
+static int read_binary_policy(policydb_t * p, const char *file, const char *progname)
+{
+	int fd;
+	struct stat sb;
+	void *map;
+	struct policy_file f, *fp;
+
+	fd = open(file, O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Can't open '%s':  %s\n",
+			file, strerror(errno));
+		return -1;
+	}
+	if (fstat(fd, &sb) < 0) {
+		fprintf(stderr, "Can't stat '%s':  %s\n",
+			file, strerror(errno));
+		close(fd);
+		return -1;
+	}
+	map =
+	    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+	close(fd);
+	if (map == MAP_FAILED) {
+		fprintf(stderr, "Can't map '%s':  %s\n", file, strerror(errno));
+		return -1;
+	}
+	policy_file_init(&f);
+	f.type = PF_USE_MEMORY;
+	f.data = map;
+	f.len = sb.st_size;
+	fp = &f;
+
+	if (policydb_init(p)) {
+		fprintf(stderr, "%s:  policydb_init:  Out of memory!\n",
+			progname);
+		return -1;
+	}
+	if (policydb_read(p, fp, 1)) {
+		fprintf(stderr,
+			"%s:  error(s) encountered while parsing configuration\n",
+			progname);
+		return -1;
+	}
+
+	/* Check Policy Consistency */
+	if (p->mls) {
+		if (!mlspol) {
+			fprintf(stderr, "%s:  MLS policy, but non-MLS"
+				" is specified\n", progname);
+			return -1;
+		}
+	} else {
+		if (mlspol) {
+			fprintf(stderr, "%s:  non-MLS policy, but MLS"
+				" is specified\n", progname);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int write_binary_policy(policydb_t * p, FILE *outfp)
+{
+	struct policy_file pf;
+
+	p->policy_type = policy_type;
+	p->policyvers = policyvers;
+	p->handle_unknown = handle_unknown;
+
+	policy_file_init(&pf);
+	pf.type = PF_USE_STDIO;
+	pf.fp = outfp;
+	return policydb_write(p, &pf);
+}
+
+static void usage(char *progname)
+{
+	printf("usage:  %s [-h] [-V] [-b] [-C] [-U handle_unknown] [-m] [-M] [-o FILE] [INPUT]\n", progname);
+	printf("Build base and policy modules.\n");
+	printf("Options:\n");
+	printf("  INPUT      build module from INPUT (else read from \"%s\")\n",
+	       txtfile);
+	printf("  -V         show policy versions created by this program\n");
+	printf("  -b         treat input as a binary policy file\n");
+	printf("  -C         output CIL policy instead of binary policy\n");
+	printf("  -h         print usage\n");
+	printf("  -U OPTION  How to handle unknown classes and permissions\n");
+	printf("               deny: Deny unknown kernel checks\n");
+	printf("               reject: Reject loading of policy with unknowns\n");
+	printf("               allow: Allow unknown kernel checks\n");
+	printf("  -m         build a policy module instead of a base module\n");
+	printf("  -M         enable MLS policy\n");
+	printf("  -o FILE    write module to FILE (else just check syntax)\n");
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	const char *file = txtfile, *outfile = NULL;
+	unsigned int binary = 0, cil = 0;
+	int ch;
+	int show_version = 0;
+	policydb_t modpolicydb;
+	struct option long_options[] = {
+		{"help", no_argument, NULL, 'h'},
+		{"output", required_argument, NULL, 'o'},
+		{"binary", no_argument, NULL, 'b'},
+		{"version", no_argument, NULL, 'V'},
+		{"handle-unknown", required_argument, NULL, 'U'},
+		{"mls", no_argument, NULL, 'M'},
+		{"cil", no_argument, NULL, 'C'},
+		{NULL, 0, NULL, 0}
+	};
+
+	while ((ch = getopt_long(argc, argv, "ho:bVU:mMC", long_options, NULL)) != -1) {
+		switch (ch) {
+		case 'h':
+			usage(argv[0]);
+			break;
+		case 'o':
+			outfile = optarg;
+			break;
+		case 'b':
+			binary = 1;
+			file = binfile;
+			break;
+		case 'V':
+			show_version = 1;
+			break;
+		case 'U':
+			if (!strcasecmp(optarg, "deny")) {
+				handle_unknown = DENY_UNKNOWN;
+				break;
+			}
+			if (!strcasecmp(optarg, "reject")) {
+				handle_unknown = REJECT_UNKNOWN;
+				break;
+			}
+			if (!strcasecmp(optarg, "allow")) {
+				handle_unknown = ALLOW_UNKNOWN;
+				break;
+			}
+			usage(argv[0]);
+		case 'm':
+			policy_type = POLICY_MOD;
+			policyvers = MOD_POLICYDB_VERSION_MAX;
+			break;
+		case 'M':
+			mlspol = 1;
+			break;
+		case 'C':
+			cil = 1;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	if (show_version) {
+		printf("Module versions %d-%d\n",
+		       MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX);
+		exit(0);
+	}
+
+	if (handle_unknown && (policy_type != POLICY_BASE)) {
+		fprintf(stderr, "%s:  Handling of unknown classes and permissions is only valid in the base module.\n", argv[0]);
+		exit(1);
+	}
+
+	if (binary && (policy_type != POLICY_BASE)) {
+		fprintf(stderr, "%s:  -b and -m are incompatible with each other.\n", argv[0]);
+		exit(1);
+	}
+
+	if (optind != argc) {
+		file = argv[optind++];
+		if (optind != argc)
+			usage(argv[0]);
+	}
+	printf("%s:  loading policy configuration from %s\n", argv[0], file);
+
+	/* Set policydb and sidtab used by libsepol service functions
+	   to my structures, so that I can directly populate and
+	   manipulate them. */
+	sepol_set_policydb(&modpolicydb);
+	sepol_set_sidtab(&sidtab);
+
+	if (binary) {
+		if (read_binary_policy(&modpolicydb, file, argv[0]) == -1) {
+			exit(1);
+		}
+	} else {
+		if (policydb_init(&modpolicydb)) {
+			fprintf(stderr, "%s: out of memory!\n", argv[0]);
+			return -1;
+		}
+
+		modpolicydb.policy_type = policy_type;
+		modpolicydb.mls = mlspol;
+		modpolicydb.handle_unknown = handle_unknown;
+
+		if (read_source_policy(&modpolicydb, file, argv[0]) == -1) {
+			exit(1);
+		}
+
+		if (hierarchy_check_constraints(NULL, &modpolicydb)) {
+			return -1;
+		}
+	}
+
+	if (policy_type != POLICY_BASE && outfile) {
+		char *mod_name = modpolicydb.name;
+		char *out_path = strdup(outfile);
+		if (out_path == NULL) {
+			fprintf(stderr, "%s:  out of memory\n", argv[0]);
+			exit(1);
+		}
+		char *out_name = basename(out_path);
+		char *separator = strrchr(out_name, '.');
+		if (separator) {
+			*separator = '\0';
+		}
+		if (strcmp(mod_name, out_name) != 0) {
+			fprintf(stderr,	"%s:  Module name %s is different than the output base filename %s\n", argv[0], mod_name, out_name);
+			exit(1);
+		}
+		free(out_path);
+	}
+
+	if (modpolicydb.policy_type == POLICY_BASE && !cil) {
+		/* Verify that we can successfully expand the base module. */
+		policydb_t kernpolicydb;
+
+		if (policydb_init(&kernpolicydb)) {
+			fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
+			exit(1);
+		}
+		if (link_modules(NULL, &modpolicydb, NULL, 0, 0)) {
+			fprintf(stderr, "%s:  link modules failed\n", argv[0]);
+			exit(1);
+		}
+		if (expand_module(NULL, &modpolicydb, &kernpolicydb, 0, 1)) {
+			fprintf(stderr, "%s:  expand module failed\n", argv[0]);
+			exit(1);
+		}
+		policydb_destroy(&kernpolicydb);
+	}
+
+	if (policydb_load_isids(&modpolicydb, &sidtab))
+		exit(1);
+
+	sepol_sidtab_destroy(&sidtab);
+
+	printf("%s:  policy configuration loaded\n", argv[0]);
+
+	if (outfile) {
+		FILE *outfp = fopen(outfile, "w");
+
+		if (!outfp) {
+			perror(outfile);
+			exit(1);
+		}
+
+		if (!cil) {
+			printf("%s:  writing binary representation (version %d) to %s\n",
+				   argv[0], policyvers, outfile);
+
+			if (write_binary_policy(&modpolicydb, outfp) != 0) {
+				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
+				exit(1);
+			}
+		} else {
+			printf("%s:  writing CIL to %s\n",argv[0], outfile);
+
+			if (sepol_module_policydb_to_cil(outfp, &modpolicydb, 0) != 0) {
+				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
+				exit(1);
+			}
+		}
+
+		fclose(outfp);
+	} else if (cil) {
+		fprintf(stderr, "%s:  No file to write CIL was specified\n", argv[0]);
+		exit(1);
+	}
+
+	policydb_destroy(&modpolicydb);
+
+	return 0;
+}
+
+/* FLASK */
diff --git a/checkpolicy/checkpolicy.8 b/checkpolicy/checkpolicy.8
new file mode 100644
index 0000000..600d5cd
--- /dev/null
+++ b/checkpolicy/checkpolicy.8
@@ -0,0 +1,59 @@
+.TH CHECKPOLICY 8
+.SH NAME
+checkpolicy \- SELinux policy compiler
+.SH SYNOPSIS
+.B checkpolicy
+.I "[\-b] [\-C] [\-d] [\-M] [\-c policyvers] [\-o output_file] [input_file]"
+.br
+.SH "DESCRIPTION"
+This manual page describes the
+.BR checkpolicy
+command.
+.PP
+.B checkpolicy
+is a program that checks and compiles a SELinux security policy configuration
+into a binary representation that can be loaded into the kernel.  If no 
+input file name is specified, checkpolicy will attempt to read from
+policy.conf or policy, depending on whether the \-b flag is specified.
+
+.SH OPTIONS
+.TP
+.B \-b,\-\-binary
+Read an existing binary policy file rather than a source policy.conf file.
+.TP
+.B \-C,\-\-cil
+Write CIL policy file rather than binary policy file.
+.TP
+.B \-d,\-\-debug
+Enter debug mode after loading the policy.
+.TP
+.B \-M,\-\-mls
+Enable the MLS policy when checking and compiling the policy.
+.TP
+.B \-o,\-\-output filename
+Write a binary policy file to the specified filename.
+.TP
+.B \-c policyvers
+Specify the policy version, defaults to the latest.
+.TP
+.B \-t,\-\-target
+Specify the target platform (selinux or xen).
+.TP
+.B \-U,\-\-handle-unknown <action>
+Specify how the kernel should handle unknown classes or permissions (deny, allow or reject).
+.TP
+.B \-V,\-\-version
+Show version information.
+.TP
+.B \-h,\-\-help
+Show usage information.
+
+.SH "SEE ALSO"
+SELinux documentation at http://www.nsa.gov/research/selinux,
+especially "Configuring the SELinux Policy".
+
+
+.SH AUTHOR
+This manual page was written by Arpad Magosanyi <mag@bunuel.tii.matav.hu>,
+and edited by Stephen Smalley <sds@epoch.ncsc.mil>.
+The program was written by Stephen Smalley <sds@epoch.ncsc.mil>.
diff --git a/checkpolicy/checkpolicy.c b/checkpolicy/checkpolicy.c
new file mode 100644
index 0000000..2d68316
--- /dev/null
+++ b/checkpolicy/checkpolicy.c
@@ -0,0 +1,1224 @@
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Updated: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Updated: James Morris <jmorris@intercode.com.au>
+ *
+ *	Added IPv6 support.
+ *
+ * Updated: Joshua Brindle <jbrindle@tresys.com>
+ *	    Karl MacMillan <kmacmillan@tresys.com>
+ *          Jason Tang     <jtang@tresys.com>
+ *
+ *	Policy Module support.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2005 Tresys Technology, LLC
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *	This program is free software; you can redistribute it and/or modify
+ *  	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, version 2.
+ */
+
+/* FLASK */
+
+/* 
+ * checkpolicy
+ *
+ * Load and check a policy configuration.
+ *
+ * A policy configuration is created in a text format,
+ * and then compiled into a binary format for use by
+ * the security server.  By default, checkpolicy reads
+ * the text format.   If '-b' is specified, then checkpolicy
+ * reads the binary format instead.
+ * 
+ * If '-o output_file' is specified, then checkpolicy 
+ * writes the binary format version of the configuration
+ * to the specified output file.  
+ * 
+ * If '-d' is specified, then checkpolicy permits the user 
+ * to interactively test the security server functions with 
+ * the loaded policy configuration.
+ *
+ * If '-c' is specified, then the supplied parameter is used to
+ * determine which policy version to use for generating binary
+ * policy.  This is for compatibility with older kernels. If any
+ * booleans or conditional rules are thrown away a warning is printed.
+ */
+
+#include <getopt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#ifdef __APPLE__
+#include <ctype.h>
+#endif
+
+#include <sepol/module_to_cil.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/link.h>
+
+#include "queue.h"
+#include "checkpolicy.h"
+#include "parse_util.h"
+
+extern char *optarg;
+extern int optind;
+
+static policydb_t policydb;
+static sidtab_t sidtab;
+
+extern policydb_t *policydbp;
+extern int mlspol;
+
+static int handle_unknown = SEPOL_DENY_UNKNOWN;
+static const char *txtfile = "policy.conf";
+static const char *binfile = "policy";
+
+unsigned int policyvers = POLICYDB_VERSION_MAX;
+
+void usage(char *progname)
+{
+	printf
+	    ("usage:  %s [-b] [-C] [-d] [-U handle_unknown (allow,deny,reject)] [-M]"
+	     "[-c policyvers (%d-%d)] [-o output_file] [-t target_platform (selinux,xen)]"
+	     "[input_file]\n",
+	     progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+	exit(1);
+}
+
+#define FGETS(out, size, in) \
+if (fgets(out,size,in)==NULL) {	\
+		fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,\
+				strerror(errno)); \
+			exit(1);\
+}
+static int print_sid(sepol_security_id_t sid,
+		     context_struct_t * context
+		     __attribute__ ((unused)), void *data
+		     __attribute__ ((unused)))
+{
+	sepol_security_context_t scontext;
+	size_t scontext_len;
+	int rc;
+
+	rc = sepol_sid_to_context(sid, &scontext, &scontext_len);
+	if (rc)
+		printf("sid %d -> error %d\n", sid, rc);
+	else {
+		printf("sid %d -> scontext %s\n", sid, scontext);
+		free(scontext);
+	}
+	return 0;
+}
+
+struct val_to_name {
+	unsigned int val;
+	char *name;
+};
+
+static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+	struct val_to_name *v = p;
+	perm_datum_t *perdatum;
+
+	perdatum = (perm_datum_t *) datum;
+
+	if (v->val == perdatum->s.value) {
+		v->name = key;
+		return 1;
+	}
+
+	return 0;
+}
+
+#ifdef EQUIVTYPES
+static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
+			    struct avtab_node *type_rules)
+{
+	struct avtab_node *p, *c, *n;
+
+	for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
+		/* 
+		 * Find the insertion point, keeping the list
+		 * ordered by source type, then target type, then
+		 * target class.
+		 */
+		if (k->source_type < c->key.source_type)
+			break;
+		if (k->source_type == c->key.source_type &&
+		    k->target_type < c->key.target_type)
+			break;
+		if (k->source_type == c->key.source_type &&
+		    k->target_type == c->key.target_type &&
+		    k->target_class < c->key.target_class)
+			break;
+	}
+
+	/* Insert the rule */
+	n = malloc(sizeof(struct avtab_node));
+	if (!n) {
+		fprintf(stderr, "out of memory\n");
+		exit(1);
+	}
+
+	n->key = *k;
+	n->datum = *d;
+	n->next = p->next;
+	p->next = n;
+	return 0;
+}
+
+static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
+{
+	struct avtab_node *type_rules = args;
+
+	if (d->specified & AVTAB_ALLOWED) {
+		/* 
+		 * Insert the rule into the lists for both 
+		 * the source type and the target type.
+		 */
+		if (insert_type_rule(k, d, &type_rules[k->source_type - 1]))
+			return -1;
+		if (insert_type_rule(k, d, &type_rules[k->target_type - 1]))
+			return -1;
+	}
+
+	return 0;
+}
+
+static void free_type_rules(struct avtab_node *l)
+{
+	struct avtab_node *tmp;
+
+	while (l) {
+		tmp = l;
+		l = l->next;
+		free(tmp);
+	}
+}
+
+static int identify_equiv_types(void)
+{
+	struct avtab_node *type_rules, *l1, *l2;
+	int i, j;
+
+	/*
+	 * Create a list of access vector rules for each type
+	 * from the access vector table.
+	 */
+	type_rules = malloc(sizeof(struct avtab_node) * policydb.p_types.nprim);
+	if (!type_rules) {
+		fprintf(stderr, "out of memory\n");
+		exit(1);
+	}
+	memset(type_rules, 0,
+	       sizeof(struct avtab_node) * policydb.p_types.nprim);
+	if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules))
+		exit(1);
+
+	/*
+	 * Compare the type lists and identify equivalent types.
+	 */
+	for (i = 0; i < policydb.p_types.nprim - 1; i++) {
+		if (!type_rules[i].next)
+			continue;
+		for (j = i + 1; j < policydb.p_types.nprim; j++) {
+			for (l1 = type_rules[i].next, l2 = type_rules[j].next;
+			     l1 && l2; l1 = l1->next, l2 = l2->next) {
+				if (l2->key.source_type == (j + 1)) {
+					if (l1->key.source_type != (i + 1))
+						break;
+				} else {
+					if (l1->key.source_type !=
+					    l2->key.source_type)
+						break;
+				}
+				if (l2->key.target_type == (j + 1)) {
+					if (l1->key.target_type != (i + 1))
+						break;
+				} else {
+					if (l1->key.target_type !=
+					    l2->key.target_type)
+						break;
+				}
+				if (l1->key.target_class != l2->key.target_class
+				    || l1->datum.allowed != l2->datum.allowed)
+					break;
+			}
+			if (l1 || l2)
+				continue;
+			free_type_rules(type_rules[j].next);
+			type_rules[j].next = NULL;
+			printf("Types %s and %s are equivalent.\n",
+			       policydb.p_type_val_to_name[i],
+			       policydb.p_type_val_to_name[j]);
+		}
+		free_type_rules(type_rules[i].next);
+		type_rules[i].next = NULL;
+	}
+
+	free(type_rules);
+	return 0;
+}
+#endif
+
+extern char *av_to_string(uint32_t tclass, sepol_access_vector_t av);
+
+int display_bools(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < policydbp->p_bools.nprim; i++) {
+		printf("%s : %d\n", policydbp->p_bool_val_to_name[i],
+		       policydbp->bool_val_to_struct[i]->state);
+	}
+	return 0;
+}
+
+void display_expr(cond_expr_t * exp)
+{
+
+	cond_expr_t *cur;
+	for (cur = exp; cur != NULL; cur = cur->next) {
+		switch (cur->expr_type) {
+		case COND_BOOL:
+			printf("%s ",
+			       policydbp->p_bool_val_to_name[cur->bool - 1]);
+			break;
+		case COND_NOT:
+			printf("! ");
+			break;
+		case COND_OR:
+			printf("|| ");
+			break;
+		case COND_AND:
+			printf("&& ");
+			break;
+		case COND_XOR:
+			printf("^ ");
+			break;
+		case COND_EQ:
+			printf("== ");
+			break;
+		case COND_NEQ:
+			printf("!= ");
+			break;
+		default:
+			printf("error!");
+			break;
+		}
+	}
+}
+
+int display_cond_expressions(void)
+{
+	cond_node_t *cur;
+
+	for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) {
+		printf("expression: ");
+		display_expr(cur->expr);
+		printf("current state: %d\n", cur->cur_state);
+	}
+	return 0;
+}
+
+int change_bool(char *name, int state)
+{
+	cond_bool_datum_t *bool;
+
+	bool = hashtab_search(policydbp->p_bools.table, name);
+	if (bool == NULL) {
+		printf("Could not find bool %s\n", name);
+		return -1;
+	}
+	bool->state = state;
+	evaluate_conds(policydbp);
+	return 0;
+}
+
+static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused)))
+{
+	level_datum_t *levdatum = (level_datum_t *) datum;
+
+	if (!levdatum->isalias && !levdatum->defined) {
+		fprintf(stderr,
+			"Error:  sensitivity %s was not used in a level definition!\n",
+			key);
+		return -1;
+	}
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	policydb_t parse_policy;
+	sepol_security_class_t tclass;
+	sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid;
+	sepol_security_context_t scontext;
+	struct sepol_av_decision avd;
+	class_datum_t *cladatum;
+	const char *file = txtfile;
+	char ans[80 + 1], *outfile = NULL, *path, *fstype;
+	size_t scontext_len, pathlen;
+	unsigned int i;
+	unsigned int protocol, port;
+	unsigned int binary = 0, debug = 0, cil = 0;
+	struct val_to_name v;
+	int ret, ch, fd, target = SEPOL_TARGET_SELINUX;
+	unsigned int nel, uret;
+	struct stat sb;
+	void *map;
+	FILE *outfp = NULL;
+	char *name;
+	int state;
+	int show_version = 0;
+	char *reason_buf = NULL;
+	unsigned int reason;
+	int flags;
+	struct policy_file pf;
+	struct option long_options[] = {
+		{"output", required_argument, NULL, 'o'},
+		{"target", required_argument, NULL, 't'},
+		{"binary", no_argument, NULL, 'b'},
+		{"debug", no_argument, NULL, 'd'},
+		{"version", no_argument, NULL, 'V'},
+		{"handle-unknown", required_argument, NULL, 'U'},
+		{"mls", no_argument, NULL, 'M'},
+		{"cil", no_argument, NULL, 'C'},
+		{"help", no_argument, NULL, 'h'},
+		{NULL, 0, NULL, 0}
+	};
+
+	while ((ch = getopt_long(argc, argv, "o:t:dbU:MCVc:h", long_options, NULL)) != -1) {
+		switch (ch) {
+		case 'o':
+			outfile = optarg;
+			break;
+		case 't':
+			if (!strcasecmp(optarg, "Xen"))
+				target = SEPOL_TARGET_XEN;
+			else if (!strcasecmp(optarg, "SELinux"))
+				target = SEPOL_TARGET_SELINUX;
+			else{
+				fprintf(stderr, "%s:  Unknown target platform:"
+					"%s\n", argv[0], optarg);
+				exit(1);
+			}
+			break;
+		case 'b':
+			binary = 1;
+			file = binfile;
+			break;
+		case 'd':
+			debug = 1;
+			break;
+		case 'V':
+			show_version = 1;
+			break;
+		case 'U':
+			if (!strcasecmp(optarg, "deny")) {
+				handle_unknown = DENY_UNKNOWN;
+				break;
+			}
+			if (!strcasecmp(optarg, "allow")) {
+				handle_unknown = ALLOW_UNKNOWN;
+				break;
+			}
+			if (!strcasecmp(optarg, "reject")) {
+				handle_unknown = REJECT_UNKNOWN;
+				break;
+			}
+			usage(argv[0]);
+		case 'M':
+			mlspol = 1;
+			break;
+		case 'C':
+			cil = 1;
+			break;
+		case 'c':{
+				long int n;
+				errno = 0;
+				n = strtol(optarg, NULL, 10);
+				if (errno) {
+					fprintf(stderr,
+						"Invalid policyvers specified: %s\n",
+						optarg);
+					usage(argv[0]);
+					exit(1);
+				}
+				if (n < POLICYDB_VERSION_MIN
+				    || n > POLICYDB_VERSION_MAX) {
+					fprintf(stderr,
+						"policyvers value %ld not in range %d-%d\n",
+						n, POLICYDB_VERSION_MIN,
+						POLICYDB_VERSION_MAX);
+					usage(argv[0]);
+					exit(1);
+				}
+				if (policyvers != n)
+					policyvers = n;
+				break;
+			}
+		case 'h':
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	if (show_version) {
+		printf("%d (compatibility range %d-%d)\n", policyvers,
+		       POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
+		exit(0);
+	}
+
+	if (optind != argc) {
+		file = argv[optind++];
+		if (optind != argc)
+			usage(argv[0]);
+	}
+	printf("%s:  loading policy configuration from %s\n", argv[0], file);
+
+	/* Set policydb and sidtab used by libsepol service functions
+	   to my structures, so that I can directly populate and
+	   manipulate them. */
+	sepol_set_policydb(&policydb);
+	sepol_set_sidtab(&sidtab);
+
+	if (binary) {
+		if (cil) {
+			fprintf(stderr,	"%s:  Converting kernel policy to CIL is not supported\n",
+				argv[0]);
+			exit(1);
+		}
+		fd = open(file, O_RDONLY);
+		if (fd < 0) {
+			fprintf(stderr, "Can't open '%s':  %s\n",
+				file, strerror(errno));
+			exit(1);
+		}
+		if (fstat(fd, &sb) < 0) {
+			fprintf(stderr, "Can't stat '%s':  %s\n",
+				file, strerror(errno));
+			exit(1);
+		}
+		map =
+		    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
+			 fd, 0);
+		if (map == MAP_FAILED) {
+			fprintf(stderr, "Can't map '%s':  %s\n",
+				file, strerror(errno));
+			exit(1);
+		}
+		policy_file_init(&pf);
+		pf.type = PF_USE_MEMORY;
+		pf.data = map;
+		pf.len = sb.st_size;
+		if (policydb_init(&policydb)) {
+			fprintf(stderr, "%s:  policydb_init:  Out of memory!\n",
+				argv[0]);
+			exit(1);
+		}
+		ret = policydb_read(&policydb, &pf, 1);
+		if (ret) {
+			fprintf(stderr,
+				"%s:  error(s) encountered while parsing configuration\n",
+				argv[0]);
+			exit(1);
+		}
+		policydbp = &policydb;
+
+		/* Check Policy Consistency */
+		if (policydbp->mls) {
+			if (!mlspol) {
+				fprintf(stderr, "%s:  MLS policy, but non-MLS"
+					" is specified\n", argv[0]);
+				exit(1);
+			}
+		} else {
+			if (mlspol) {
+				fprintf(stderr, "%s:  non-MLS policy, but MLS"
+					" is specified\n", argv[0]);
+				exit(1);
+			}
+		}
+	} else {
+		if (policydb_init(&parse_policy))
+			exit(1);
+		/* We build this as a base policy first since that is all the parser understands */
+		parse_policy.policy_type = POLICY_BASE;
+		policydb_set_target_platform(&parse_policy, target);
+
+		/* Let sepol know if we are dealing with MLS support */
+		parse_policy.mls = mlspol;
+		parse_policy.handle_unknown = handle_unknown;
+
+		policydbp = &parse_policy;
+
+		if (read_source_policy(policydbp, file, "checkpolicy") < 0)
+			exit(1);
+
+		if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
+			exit(1);
+
+		/* Linking takes care of optional avrule blocks */
+		if (link_modules(NULL, policydbp, NULL, 0, 0)) {
+			fprintf(stderr, "Error while resolving optionals\n");
+			exit(1);
+		}
+
+		if (!cil) {
+			if (policydb_init(&policydb)) {
+				fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
+				exit(1);
+			}
+			if (expand_module(NULL, policydbp, &policydb, 0, 1)) {
+				fprintf(stderr, "Error while expanding policy\n");
+				exit(1);
+			}
+			policydb_destroy(policydbp);
+			policydbp = &policydb;
+		}
+	}
+
+	if (policydb_load_isids(&policydb, &sidtab))
+		exit(1);
+
+	printf("%s:  policy configuration loaded\n", argv[0]);
+
+	if (outfile) {
+		outfp = fopen(outfile, "w");
+		if (!outfp) {
+			perror(outfile);
+			exit(1);
+		}
+
+		policydb.policyvers = policyvers;
+
+		if (!cil) {
+			printf
+				("%s:  writing binary representation (version %d) to %s\n",
+				 argv[0], policyvers, outfile);
+			policydb.policy_type = POLICY_KERN;
+
+			policy_file_init(&pf);
+			pf.type = PF_USE_STDIO;
+			pf.fp = outfp;
+			ret = policydb_write(&policydb, &pf);
+			if (ret) {
+				fprintf(stderr, "%s:  error writing %s\n",
+						argv[0], outfile);
+				exit(1);
+			}
+		} else {
+			printf("%s:  writing CIL to %s\n",argv[0], outfile);
+			ret = sepol_module_policydb_to_cil(outfp, policydbp, 1);
+			if (ret) {
+				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
+				exit(1);
+			}
+		}
+
+		if (outfile) {
+			fclose(outfp);
+		}
+	} else if (cil) {
+		fprintf(stderr, "%s:  No file to write CIL was specified\n", argv[0]);
+		exit(1);
+	}
+
+	if (!debug) {
+		policydb_destroy(&policydb);
+		exit(0);
+	}
+
+      menu:
+	printf("\nSelect an option:\n");
+	printf("0)  Call compute_access_vector\n");
+	printf("1)  Call sid_to_context\n");
+	printf("2)  Call context_to_sid\n");
+	printf("3)  Call transition_sid\n");
+	printf("4)  Call member_sid\n");
+	printf("5)  Call change_sid\n");
+	printf("6)  Call list_sids\n");
+	printf("7)  Call load_policy\n");
+	printf("8)  Call fs_sid\n");
+	printf("9)  Call port_sid\n");
+	printf("a)  Call netif_sid\n");
+	printf("b)  Call node_sid\n");
+	printf("c)  Call fs_use\n");
+	printf("d)  Call genfs_sid\n");
+	printf("e)  Call get_user_sids\n");
+	printf("f)  display conditional bools\n");
+	printf("g)  display conditional expressions\n");
+	printf("h)  change a boolean value\n");
+	printf("i)  display constraint expressions\n");
+	printf("j)  display validatetrans expressions\n");
+#ifdef EQUIVTYPES
+	printf("z)  Show equivalent types\n");
+#endif
+	printf("m)  Show menu again\n");
+	printf("q)  Exit\n");
+	while (1) {
+		printf("\nChoose:  ");
+		FGETS(ans, sizeof(ans), stdin);
+		switch (ans[0]) {
+		case '0':
+			printf("source sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ssid = atoi(ans);
+
+			printf("target sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			tsid = atoi(ans);
+
+			printf("target class?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			if (isdigit(ans[0])) {
+				tclass = atoi(ans);
+				if (!tclass
+				    || tclass > policydb.p_classes.nprim) {
+					printf("\nNo such class.\n");
+					break;
+				}
+				cladatum =
+				    policydb.class_val_to_struct[tclass - 1];
+			} else {
+				ans[strlen(ans) - 1] = 0;
+				cladatum =
+				    (class_datum_t *) hashtab_search(policydb.
+								     p_classes.
+								     table,
+								     ans);
+				if (!cladatum) {
+					printf("\nNo such class\n");
+					break;
+				}
+				tclass = cladatum->s.value;
+			}
+
+			if (!cladatum->comdatum && !cladatum->permissions.nprim) {
+				printf
+				    ("\nNo access vector definition for that class\n");
+				break;
+			}
+			ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
+			switch (ret) {
+			case 0:
+				printf("\nallowed {");
+				for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
+					if (avd.allowed & (1 << (i - 1))) {
+						v.val = i;
+						ret =
+						    hashtab_map(cladatum->
+								permissions.
+								table,
+								find_perm, &v);
+						if (!ret && cladatum->comdatum) {
+							ret =
+							    hashtab_map
+							    (cladatum->
+							     comdatum->
+							     permissions.table,
+							     find_perm, &v);
+						}
+						if (ret)
+							printf(" %s", v.name);
+					}
+				}
+				printf(" }\n");
+				break;
+			case -EINVAL:
+				printf("\ninvalid sid\n");
+				break;
+			default:
+				printf("return code 0x%x\n", ret);
+			}
+			break;
+		case '1':
+			printf("sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ssid = atoi(ans);
+			ret = sepol_sid_to_context(ssid,
+						   &scontext, &scontext_len);
+			switch (ret) {
+			case 0:
+				printf("\nscontext %s\n", scontext);
+				free(scontext);
+				break;
+			case -EINVAL:
+				printf("\ninvalid sid\n");
+				break;
+			case -ENOMEM:
+				printf("\nout of memory\n");
+				break;
+			default:
+				printf("return code 0x%x\n", ret);
+			}
+			break;
+		case '2':
+			printf("scontext?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			scontext_len = strlen(ans);
+			ans[scontext_len - 1] = 0;
+			ret = sepol_context_to_sid(ans, scontext_len, &ssid);
+			switch (ret) {
+			case 0:
+				printf("\nsid %d\n", ssid);
+				break;
+			case -EINVAL:
+				printf("\ninvalid context\n");
+				break;
+			case -ENOMEM:
+				printf("\nout of memory\n");
+				break;
+			default:
+				printf("return code 0x%x\n", ret);
+			}
+			break;
+		case '3':
+		case '4':
+		case '5':
+			ch = ans[0];
+
+			printf("source sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ssid = atoi(ans);
+			printf("target sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			tsid = atoi(ans);
+
+			printf("object class?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			if (isdigit(ans[0])) {
+				tclass = atoi(ans);
+				if (!tclass
+				    || tclass > policydb.p_classes.nprim) {
+					printf("\nNo such class.\n");
+					break;
+				}
+			} else {
+				ans[strlen(ans) - 1] = 0;
+				cladatum =
+				    (class_datum_t *) hashtab_search(policydb.
+								     p_classes.
+								     table,
+								     ans);
+				if (!cladatum) {
+					printf("\nNo such class\n");
+					break;
+				}
+				tclass = cladatum->s.value;
+			}
+
+			if (ch == '3')
+				ret =
+				    sepol_transition_sid(ssid, tsid, tclass,
+							 &ssid);
+			else if (ch == '4')
+				ret =
+				    sepol_member_sid(ssid, tsid, tclass, &ssid);
+			else
+				ret =
+				    sepol_change_sid(ssid, tsid, tclass, &ssid);
+			switch (ret) {
+			case 0:
+				printf("\nsid %d\n", ssid);
+				break;
+			case -EINVAL:
+				printf("\ninvalid sid\n");
+				break;
+			case -ENOMEM:
+				printf("\nout of memory\n");
+				break;
+			default:
+				printf("return code 0x%x\n", ret);
+			}
+			break;
+		case '6':
+			sepol_sidtab_map(&sidtab, print_sid, 0);
+			break;
+		case '7':
+			printf("pathname?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			pathlen = strlen(ans);
+			ans[pathlen - 1] = 0;
+			printf("%s:  loading policy configuration from %s\n",
+			       argv[0], ans);
+			fd = open(ans, O_RDONLY);
+			if (fd < 0) {
+				fprintf(stderr, "Can't open '%s':  %s\n",
+					ans, strerror(errno));
+				break;
+			}
+			if (fstat(fd, &sb) < 0) {
+				fprintf(stderr, "Can't stat '%s':  %s\n",
+					ans, strerror(errno));
+				break;
+			}
+			map =
+			    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
+				 MAP_PRIVATE, fd, 0);
+			if (map == MAP_FAILED) {
+				fprintf(stderr, "Can't map '%s':  %s\n",
+					ans, strerror(errno));
+				break;
+			}
+			ret = sepol_load_policy(map, sb.st_size);
+			switch (ret) {
+			case 0:
+				printf("\nsuccess\n");
+				break;
+			case -EINVAL:
+				printf("\ninvalid policy\n");
+				break;
+			case -ENOMEM:
+				printf("\nout of memory\n");
+				break;
+			default:
+				printf("return code 0x%x\n", ret);
+			}
+			break;
+		case '8':
+			printf("fs kdevname?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+			sepol_fs_sid(ans, &ssid, &tsid);
+			printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
+			break;
+		case '9':
+			printf("protocol?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+			if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
+				protocol = IPPROTO_TCP;
+			else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
+				protocol = IPPROTO_UDP;
+			else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
+				protocol = IPPROTO_DCCP;
+			else {
+				printf("unknown protocol\n");
+				break;
+			}
+			printf("port? ");
+			FGETS(ans, sizeof(ans), stdin);
+			port = atoi(ans);
+			sepol_port_sid(0, 0, protocol, port, &ssid);
+			printf("sid %d\n", ssid);
+			break;
+		case 'a':
+			printf("netif name?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+			sepol_netif_sid(ans, &ssid, &tsid);
+			printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
+			break;
+		case 'b':{
+				char *p;
+				int family, len;
+				struct in_addr addr4;
+				struct in6_addr addr6;
+
+				printf("protocol family? ");
+				FGETS(ans, sizeof(ans), stdin);
+				ans[strlen(ans) - 1] = 0;
+				if (!strcasecmp(ans, "ipv4"))
+					family = AF_INET;
+				else if (!strcasecmp(ans, "ipv6"))
+					family = AF_INET6;
+				else {
+					printf("unknown protocol family\n");
+					break;
+				}
+
+				printf("node address?  ");
+				FGETS(ans, sizeof(ans), stdin);
+				ans[strlen(ans) - 1] = 0;
+
+				if (family == AF_INET) {
+					p = (char *)&addr4;
+					len = sizeof(addr4);
+				} else {
+					p = (char *)&addr6;
+					len = sizeof(addr6);
+				}
+
+				if (inet_pton(family, ans, p) < 1) {
+					printf("error parsing address\n");
+					break;
+				}
+
+				sepol_node_sid(family, p, len, &ssid);
+				printf("sid %d\n", ssid);
+				break;
+			}
+		case 'c':
+			printf("fstype?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+			sepol_fs_use(ans, &uret, &ssid);
+			switch (uret) {
+			case SECURITY_FS_USE_XATTR:
+				printf("use xattr\n");
+				break;
+			case SECURITY_FS_USE_TRANS:
+				printf("use transition SIDs\n");
+				break;
+			case SECURITY_FS_USE_TASK:
+				printf("use task SIDs\n");
+				break;
+			case SECURITY_FS_USE_GENFS:
+				printf("use genfs\n");
+				break;
+			case SECURITY_FS_USE_NONE:
+				printf("no labeling support\n");
+				break;
+			}
+			printf("sid %d\n", ssid);
+			break;
+		case 'd':
+			printf("fstype?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+			fstype = strdup(ans);
+			printf("path?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+			path = strdup(ans);
+			printf("object class?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			if (isdigit(ans[0])) {
+				tclass = atoi(ans);
+				if (!tclass
+				    || tclass > policydb.p_classes.nprim) {
+					printf("\nNo such class.\n");
+					break;
+				}
+			} else {
+				ans[strlen(ans) - 1] = 0;
+				cladatum =
+				    (class_datum_t *) hashtab_search(policydb.
+								     p_classes.
+								     table,
+								     ans);
+				if (!cladatum) {
+					printf("\nNo such class\n");
+					break;
+				}
+				tclass = cladatum->s.value;
+			}
+			sepol_genfs_sid(fstype, path, tclass, &ssid);
+			printf("sid %d\n", ssid);
+			free(fstype);
+			free(path);
+			break;
+		case 'e':
+			printf("from SID?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+			ssid = atoi(ans);
+
+			printf("username?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+
+			ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
+			switch (ret) {
+			case 0:
+				if (!nel)
+					printf("\nnone\n");
+				for (i = 0; i < nel; i++)
+					print_sid(sids[i], NULL, NULL);
+				free(sids);
+				break;
+			case -ENOMEM:
+				printf("\nout of memory\n");
+				break;
+			case -EINVAL:
+				printf("\ninvalid argument\n");
+				break;
+			default:
+				printf("\nerror\n");
+				break;
+			}
+			break;
+		case 'f':
+			display_bools();
+			break;
+		case 'g':
+			display_cond_expressions();
+			break;
+		case 'h':
+			printf("name? ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+
+			name = malloc((strlen(ans) + 1) * sizeof(char));
+			if (name == NULL) {
+				fprintf(stderr, "couldn't malloc string.\n");
+				break;
+			}
+			strcpy(name, ans);
+
+			printf("state? ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+
+			if (atoi(ans))
+				state = 1;
+			else
+				state = 0;
+
+			change_bool(name, state);
+			free(name);
+			break;
+		case 'i':
+			printf("source sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ssid = atoi(ans);
+
+			printf("target sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			tsid = atoi(ans);
+
+			printf("target class?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			if (isdigit(ans[0])) {
+				tclass = atoi(ans);
+				if (!tclass
+				    || tclass > policydb.p_classes.nprim) {
+					printf("\nNo such class.\n");
+					break;
+				}
+				cladatum =
+				    policydb.class_val_to_struct[tclass - 1];
+			} else {
+				ans[strlen(ans) - 1] = 0;
+				cladatum =
+				    (class_datum_t *) hashtab_search(policydb.
+								     p_classes.
+								     table,
+								     ans);
+				if (!cladatum) {
+					printf("\nNo such class\n");
+					break;
+				}
+				tclass = cladatum->s.value;
+			}
+
+			flags = SHOW_GRANTED;
+			if (sepol_compute_av_reason_buffer(ssid, tsid,
+					tclass, 0, &avd, &reason,
+					&reason_buf, flags)) {
+				printf("\nconstraint error\n");
+				break;
+			}
+			if (reason_buf) {
+				printf("\nConstraint expressions:\n%s",
+						reason_buf);
+				free(reason_buf);
+			} else {
+				printf("\nNo constraints found.\n");
+			}
+			break;
+		case 'j':
+			printf("old sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			oldsid = atoi(ans);
+
+			printf("new sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			newsid = atoi(ans);
+
+			printf("task sid?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			tasksid = atoi(ans);
+
+			printf("target class?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			if (isdigit(ans[0])) {
+				tclass = atoi(ans);
+				if (!tclass
+				    || tclass > policydb.p_classes.nprim) {
+					printf("\nNo such class.\n");
+					break;
+				}
+				cladatum =
+				    policydb.class_val_to_struct[tclass - 1];
+			} else {
+				ans[strlen(ans) - 1] = 0;
+				cladatum =
+				    (class_datum_t *) hashtab_search(policydb.
+								     p_classes.
+								     table,
+								     ans);
+				if (!cladatum) {
+					printf("\nNo such class\n");
+					break;
+				}
+				tclass = cladatum->s.value;
+			}
+
+			flags = SHOW_GRANTED;
+			if (sepol_validate_transition_reason_buffer(oldsid,
+						newsid, tasksid, tclass,
+						&reason_buf, flags)) {
+				printf("\nvalidatetrans error\n");
+				break;
+			}
+			if (reason_buf) {
+				printf("\nValidatetrans expressions:\n%s",
+						reason_buf);
+				free(reason_buf);
+			} else {
+				printf(
+				    "\nNo validatetrans expressions found.\n");
+			}
+			break;
+#ifdef EQUIVTYPES
+		case 'z':
+			identify_equiv_types();
+			break;
+#endif
+		case 'm':
+			goto menu;
+		case 'q':
+			exit(0);
+			break;
+		default:
+			printf("\nUnknown option %s.\n", ans);
+		}
+	}
+
+	return 0;
+}
+
+/* FLASK */
diff --git a/checkpolicy/checkpolicy.h b/checkpolicy/checkpolicy.h
new file mode 100644
index 0000000..3868f1f
--- /dev/null
+++ b/checkpolicy/checkpolicy.h
@@ -0,0 +1,20 @@
+#ifndef _CHECKPOLICY_H_
+#define _CHECKPOLICY_H_
+
+#include <sepol/policydb/ebitmap.h>
+
+typedef struct te_assert {
+	ebitmap_t stypes;
+	ebitmap_t ttypes;
+	ebitmap_t tclasses;
+	int self;
+	sepol_access_vector_t *avp;
+	unsigned long line;
+	struct te_assert *next;
+} te_assert_t;
+
+te_assert_t *te_assertions;
+
+extern unsigned int policyvers;
+
+#endif
diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
new file mode 100644
index 0000000..6e5483c
--- /dev/null
+++ b/checkpolicy/module_compiler.c
@@ -0,0 +1,1604 @@
+/* Author : Joshua Brindle <jbrindle@tresys.com>
+ *	    Karl MacMillan <kmacmillan@tresys.com>
+ *          Jason Tang     <jtang@tresys.com>
+ *	Added support for binary policy modules
+ *
+ * Copyright (C) 2004 - 2005 Tresys Technology, LLC
+ *	This program is free software; you can redistribute it and/or modify
+ *  	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, version 2.
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/avrule_block.h>
+#include <sepol/policydb/conditional.h>
+
+#include "queue.h"
+#include "module_compiler.h"
+
+union stack_item_u {
+	avrule_block_t *avrule;
+	cond_list_t *cond_list;
+};
+
+typedef struct scope_stack {
+	union stack_item_u u;
+	int type;		/* for above union: 1 = avrule block, 2 = conditional */
+	avrule_decl_t *decl;	/* if in an avrule block, which
+				 * declaration is current */
+	avrule_t *last_avrule;
+	int in_else;		/* if in an avrule block, within ELSE branch */
+	int require_given;	/* 1 if this block had at least one require */
+	struct scope_stack *parent, *child;
+} scope_stack_t;
+
+extern policydb_t *policydbp;
+extern queue_t id_queue;
+extern int yyerror(const char *msg);
+__attribute__ ((format(printf, 1, 2)))
+extern void yyerror2(const char *fmt, ...);
+
+static int push_stack(int stack_type, ...);
+static void pop_stack(void);
+
+/* keep track of the last item added to the stack */
+static scope_stack_t *stack_top = NULL;
+static avrule_block_t *last_block;
+static uint32_t next_decl_id = 1;
+
+int define_policy(int pass, int module_header_given)
+{
+	char *id;
+
+	if (module_header_given) {
+		if (policydbp->policy_type != POLICY_MOD) {
+			yyerror
+			    ("Module specification found while not building a policy module.\n");
+			return -1;
+		}
+
+		if (pass == 2) {
+			while ((id = queue_remove(id_queue)) != NULL)
+				free(id);
+		} else {
+			id = (char *)queue_remove(id_queue);
+			if (!id) {
+				yyerror("no module name");
+				return -1;
+			}
+			policydbp->name = id;
+			if ((policydbp->version =
+			     queue_remove(id_queue)) == NULL) {
+				yyerror
+				    ("Expected a module version but none was found.");
+				return -1;
+			}
+		}
+	} else {
+		if (policydbp->policy_type == POLICY_MOD) {
+			yyerror
+			    ("Building a policy module, but no module specification found.\n");
+			return -1;
+		}
+	}
+	/* the first declaration within the global avrule
+	   block will always have an id of 1 */
+	next_decl_id = 2;
+
+	/* reset the scoping stack */
+	while (stack_top != NULL) {
+		pop_stack();
+	}
+	if (push_stack(1, policydbp->global, policydbp->global->branch_list) ==
+	    -1) {
+		return -1;
+	}
+	last_block = policydbp->global;
+	return 0;
+}
+
+/* Given the current parse stack, returns 1 if a declaration would be
+ * allowed here or 0 if not.  For example, declarations are not
+ * allowed in conditionals, so if there are any conditionals in the
+ * current scope stack then this would return a 0.
+ */
+static int is_declaration_allowed(void)
+{
+	if (stack_top->type != 1 || stack_top->in_else) {
+		return 0;
+	}
+	return 1;
+}
+
+/* Attempt to declare a symbol within the current declaration.  If
+ * currently within a non-conditional and in a non-else branch then
+ * insert the symbol, return 0 on success if symbol was undeclared.
+ * For roles and users, it is legal to have multiple declarations; as
+ * such return 1 to indicate that caller must free() the datum because
+ * it was not added.  If symbols may not be declared here return -1.
+ * For duplicate declarations return -2.  For all else, including out
+ * of memory, return -3.  Note that dest_value and datum_value might
+ * not be restricted pointers. */
+int declare_symbol(uint32_t symbol_type,
+		   hashtab_key_t key, hashtab_datum_t datum,
+		   uint32_t * dest_value, uint32_t * datum_value)
+{
+	avrule_decl_t *decl = stack_top->decl;
+	int retval;
+
+	/* first check that symbols may be declared here */
+	if (!is_declaration_allowed()) {
+		return -1;
+	}
+	retval = symtab_insert(policydbp, symbol_type, key, datum,
+			       SCOPE_DECL, decl->decl_id, dest_value);
+	if (retval == 1 && dest_value) {
+		symtab_datum_t *s =
+		    (symtab_datum_t *) hashtab_search(policydbp->
+						      symtab[symbol_type].table,
+						      key);
+		assert(s != NULL);
+		
+		if (symbol_type == SYM_LEVELS) {
+			*dest_value = ((level_datum_t *)s)->level->sens;
+		} else {
+			*dest_value = s->value;
+		}
+	} else if (retval == -2) {
+		return -2;
+	} else if (retval < 0) {
+		return -3;
+	} else {		/* fall through possible if retval is 0 */
+	}
+	if (datum_value != NULL) {
+		if (ebitmap_set_bit(decl->declared.scope + symbol_type,
+				    *datum_value - 1, 1)) {
+			return -3;
+		}
+	}
+	return retval;
+}
+
+static int role_implicit_bounds(hashtab_t roles_tab,
+				char *role_id, role_datum_t *role)
+{
+	role_datum_t *bounds;
+	char *bounds_id, *delim;
+
+	delim = strrchr(role_id, '.');
+	if (!delim)
+		return 0;	/* no implicit boundary */
+
+	bounds_id = strdup(role_id);
+	if (!bounds_id) {
+		yyerror("out of memory");
+		return -1;
+	}
+	bounds_id[(size_t)(delim - role_id)] = '\0';
+
+	bounds = hashtab_search(roles_tab, bounds_id);
+	if (!bounds) {
+		yyerror2("role %s doesn't exist, is implicit bounds of %s",
+			 bounds_id, role_id);
+		return -1;
+	}
+
+	if (!role->bounds)
+		role->bounds = bounds->s.value;
+	else if (role->bounds != bounds->s.value) {
+		yyerror2("role %s has inconsistent bounds %s/%s",
+			 role_id, bounds_id,
+			 policydbp->p_role_val_to_name[role->bounds - 1]);
+		return -1;
+	}
+	free(bounds_id);
+
+	return 0;
+}
+
+role_datum_t *declare_role(unsigned char isattr)
+{
+	char *id = queue_remove(id_queue), *dest_id = NULL;
+	role_datum_t *role = NULL, *dest_role = NULL;
+	int retval;
+	uint32_t value;
+
+	if (id == NULL) {
+		yyerror("no role name");
+		return NULL;
+	}
+	if ((role = (role_datum_t *) malloc(sizeof(*role))) == NULL) {
+		yyerror("Out of memory!");
+		free(id);
+		return NULL;
+	}
+	role_datum_init(role);
+	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
+	retval =
+	    declare_symbol(SYM_ROLES, id, (hashtab_datum_t *) role, &value,
+			   &value);
+	if (retval == 0) {
+		role->s.value = value;
+		if ((dest_id = strdup(id)) == NULL) {
+			yyerror("Out of memory!");
+			return NULL;
+		}
+	} else {
+		/* this role was already declared in this module, or error */
+		dest_id = id;
+		role_datum_destroy(role);
+		free(role);
+	}
+	if (retval == 0 || retval == 1) {
+		/* create a new role_datum_t for this decl, if necessary */
+		hashtab_t roles_tab;
+		assert(stack_top->type == 1);
+		if (stack_top->parent == NULL) {
+			/* in parent, so use global symbol table */
+			roles_tab = policydbp->p_roles.table;
+		} else {
+			roles_tab = stack_top->decl->p_roles.table;
+		}
+		dest_role = (role_datum_t *) hashtab_search(roles_tab, dest_id);
+		if (dest_role == NULL) {
+			if ((dest_role =
+			     (role_datum_t *) malloc(sizeof(*dest_role))) ==
+			    NULL) {
+				yyerror("Out of memory!");
+				free(dest_id);
+				return NULL;
+			}
+			role_datum_init(dest_role);
+			dest_role->s.value = value;
+			dest_role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
+			if (role_implicit_bounds(roles_tab, dest_id, dest_role)) {
+				free(dest_id);
+				role_datum_destroy(dest_role);
+				free(dest_role);
+				return NULL;
+			}
+			if (hashtab_insert(roles_tab, dest_id, dest_role)) {
+				yyerror("Out of memory!");
+				free(dest_id);
+				role_datum_destroy(dest_role);
+				free(dest_role);
+				return NULL;
+			}
+		} else {
+			free(dest_id);
+		}
+	} else {
+		free(dest_id);
+	}
+	switch (retval) {
+	case -3:{
+			yyerror("Out of memory!");
+			return NULL;
+		}
+	case -2:{
+			yyerror("duplicate declaration of role");
+			return NULL;
+		}
+	case -1:{
+			yyerror("could not declare role here");
+			return NULL;
+		}
+	case 0:{
+			if (ebitmap_set_bit
+			    (&dest_role->dominates, role->s.value - 1, 1)) {
+				yyerror("out of memory");
+				return NULL;
+			}
+			return dest_role;
+		}
+	case 1:{
+			return dest_role;	/* role already declared for this block */
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+}
+
+type_datum_t *declare_type(unsigned char primary, unsigned char isattr)
+{
+	char *id;
+	type_datum_t *typdatum;
+	int retval;
+	uint32_t value = 0;
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no type/attribute name?");
+		return NULL;
+	}
+	if (strcmp(id, "self") == 0) {
+		yyerror
+		    ("'self' is a reserved type name and may not be declared.");
+		free(id);
+		return NULL;
+	}
+
+	typdatum = (type_datum_t *) malloc(sizeof(type_datum_t));
+	if (!typdatum) {
+		yyerror("Out of memory!");
+		free(id);
+		return NULL;
+	}
+	type_datum_init(typdatum);
+	typdatum->primary = primary;
+	typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
+
+	retval = declare_symbol(SYM_TYPES, id, typdatum, &value, &value);
+	if (retval == 0 || retval == 1) {
+		if (typdatum->primary) {
+			typdatum->s.value = value;
+		}
+	} else {
+		/* error occurred (can't have duplicate type declarations) */
+		free(id);
+		type_datum_destroy(typdatum);
+		free(typdatum);
+	}
+	switch (retval) {
+	case -3:{
+			yyerror("Out of memory!");
+			return NULL;
+		}
+	case -2:{
+			yyerror2("duplicate declaration of type/attribute");
+			return NULL;
+		}
+	case -1:{
+			yyerror("could not declare type/attribute here");
+			return NULL;
+		}
+	case 0:
+	case 1:{
+			return typdatum;
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+}
+
+static int user_implicit_bounds(hashtab_t users_tab,
+				char *user_id, user_datum_t *user)
+{
+	user_datum_t *bounds;
+	char *bounds_id, *delim;
+
+	delim = strrchr(user_id, '.');
+	if (!delim)
+		return 0;	/* no implicit boundary */
+
+	bounds_id = strdup(user_id);
+	if (!bounds_id) {
+		yyerror("out of memory");
+		return -1;
+	}
+	bounds_id[(size_t)(delim - user_id)] = '\0';
+
+	bounds = hashtab_search(users_tab, bounds_id);
+	if (!bounds) {
+		yyerror2("user %s doesn't exist, is implicit bounds of %s",
+			 bounds_id, user_id);
+		return -1;
+	}
+
+	if (!user->bounds)
+		user->bounds = bounds->s.value;
+	else if (user->bounds != bounds->s.value) {
+		yyerror2("user %s has inconsistent bounds %s/%s",
+			 user_id, bounds_id,
+			 policydbp->p_role_val_to_name[user->bounds - 1]);
+		return -1;
+	}
+	free(bounds_id);
+
+	return 0;
+}
+
+user_datum_t *declare_user(void)
+{
+	char *id = queue_remove(id_queue), *dest_id = NULL;
+	user_datum_t *user = NULL, *dest_user = NULL;
+	int retval;
+	uint32_t value = 0;
+
+	if (id == NULL) {
+		yyerror("no user name");
+		return NULL;
+	}
+	if ((user = (user_datum_t *) malloc(sizeof(*user))) == NULL) {
+		yyerror("Out of memory!");
+		free(id);
+		return NULL;
+	}
+	user_datum_init(user);
+
+	retval =
+	    declare_symbol(SYM_USERS, id, (hashtab_datum_t *) user, &value,
+			   &value);
+
+	if (retval == 0) {
+		user->s.value = value;
+		if ((dest_id = strdup(id)) == NULL) {
+			yyerror("Out of memory!");
+			return NULL;
+		}
+	} else {
+		/* this user was already declared in this module, or error */
+		dest_id = id;
+		user_datum_destroy(user);
+		free(user);
+	}
+	if (retval == 0 || retval == 1) {
+		/* create a new user_datum_t for this decl, if necessary */
+		hashtab_t users_tab;
+		assert(stack_top->type == 1);
+		if (stack_top->parent == NULL) {
+			/* in parent, so use global symbol table */
+			users_tab = policydbp->p_users.table;
+		} else {
+			users_tab = stack_top->decl->p_users.table;
+		}
+		dest_user = (user_datum_t *) hashtab_search(users_tab, dest_id);
+		if (dest_user == NULL) {
+			if ((dest_user =
+			     (user_datum_t *) malloc(sizeof(*dest_user))) ==
+			    NULL) {
+				yyerror("Out of memory!");
+				free(dest_id);
+				return NULL;
+			}
+			user_datum_init(dest_user);
+			dest_user->s.value = value;
+			if (user_implicit_bounds(users_tab, dest_id, dest_user)) {
+				free(dest_id);
+				user_datum_destroy(dest_user);
+				free(dest_user);
+				return NULL;
+			}
+			if (hashtab_insert(users_tab, dest_id, dest_user)) {
+				yyerror("Out of memory!");
+				free(dest_id);
+				user_datum_destroy(dest_user);
+				free(dest_user);
+				return NULL;
+			}
+		} else {
+			free(dest_id);
+		}
+	} else {
+		free(dest_id);
+	}
+	switch (retval) {
+	case -3:{
+			yyerror("Out of memory!");
+			return NULL;
+		}
+	case -2:{
+			yyerror("duplicate declaration of user");
+			return NULL;
+		}
+	case -1:{
+			yyerror("could not declare user here");
+			return NULL;
+		}
+	case 0:{
+			return dest_user;
+		}
+	case 1:{
+			return dest_user;	/* user already declared for this block */
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+}
+
+/* Return a type_datum_t for the local avrule_decl with the given ID.
+ * If it does not exist, create one with the same value as 'value'.
+ * This function assumes that the ID is within scope.  c.f.,
+ * is_id_in_scope().
+ *
+ * NOTE: this function usurps ownership of id afterwards.  The caller
+ * shall not reference it nor free() it afterwards.
+ */
+type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr)
+{
+	type_datum_t *dest_typdatum;
+	hashtab_t types_tab;
+	assert(stack_top->type == 1);
+	if (stack_top->parent == NULL) {
+		/* in global, so use global symbol table */
+		types_tab = policydbp->p_types.table;
+	} else {
+		types_tab = stack_top->decl->p_types.table;
+	}
+	dest_typdatum = hashtab_search(types_tab, id);
+	if (!dest_typdatum) {
+		dest_typdatum = (type_datum_t *) malloc(sizeof(type_datum_t));
+		if (dest_typdatum == NULL) {
+			free(id);
+			return NULL;
+		}
+		type_datum_init(dest_typdatum);
+		dest_typdatum->s.value = value;
+		dest_typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
+		dest_typdatum->primary = 1;
+		if (hashtab_insert(types_tab, id, dest_typdatum)) {
+			free(id);
+			type_datum_destroy(dest_typdatum);
+			free(dest_typdatum);
+			return NULL;
+		}
+
+	} else {
+		free(id);
+		if (dest_typdatum->flavor != isattr ? TYPE_ATTRIB : TYPE_TYPE) {
+			return NULL;
+		}
+	}
+	return dest_typdatum;
+}
+
+/* Return a role_datum_t for the local avrule_decl with the given ID.
+ * If it does not exist, create one with the same value as 'value'.
+ * This function assumes that the ID is within scope.  c.f.,
+ * is_id_in_scope().
+ *
+ * NOTE: this function usurps ownership of id afterwards.  The caller
+ * shall not reference it nor free() it afterwards.
+ */
+role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr)
+{
+	role_datum_t *dest_roledatum;
+	hashtab_t roles_tab;
+
+	assert(stack_top->type == 1);
+
+	if (stack_top->parent == NULL) {
+		/* in global, so use global symbol table */
+		roles_tab = policydbp->p_roles.table;
+	} else {
+		roles_tab = stack_top->decl->p_roles.table;
+	}
+
+	dest_roledatum = hashtab_search(roles_tab, id);
+	if (!dest_roledatum) {
+		dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t));
+		if (dest_roledatum == NULL) {
+			free(id);
+			return NULL;
+		}
+
+		role_datum_init(dest_roledatum);
+		dest_roledatum->s.value = value;
+		dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
+
+		if (hashtab_insert(roles_tab, id, dest_roledatum)) {
+			free(id);
+			role_datum_destroy(dest_roledatum);
+			free(dest_roledatum);
+			return NULL;
+		}
+	} else {
+		free(id);
+		if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE)
+			return NULL;
+	}
+	
+	return dest_roledatum;
+}
+
+/* Given the current parse stack, returns 1 if a requirement would be
+ * allowed here or 0 if not.  For example, the ELSE branch may never
+ * have its own requirements.
+ */
+static int is_require_allowed(void)
+{
+	if (stack_top->type == 1 && !stack_top->in_else) {
+		return 1;
+	}
+	return 0;
+}
+
+/* Attempt to require a symbol within the current scope.  If currently
+ * within an optional (and not its else branch), add the symbol to the
+ * required list.  Return 0 on success, 1 if caller needs to free()
+ * datum.  If symbols may not be declared here return -1.  For duplicate
+ * declarations return -2.  For all else, including out of memory,
+ * return -3..  Note that dest_value and datum_value might not be
+ * restricted pointers.
+ */
+int require_symbol(uint32_t symbol_type,
+		   hashtab_key_t key, hashtab_datum_t datum,
+		   uint32_t * dest_value, uint32_t * datum_value)
+{
+	avrule_decl_t *decl = stack_top->decl;
+	int retval;
+
+	/* first check that symbols may be required here */
+	if (!is_require_allowed()) {
+		return -1;
+	}
+	retval = symtab_insert(policydbp, symbol_type, key, datum,
+			       SCOPE_REQ, decl->decl_id, dest_value);
+	if (retval == 1) {
+		symtab_datum_t *s =
+		    (symtab_datum_t *) hashtab_search(policydbp->
+						      symtab[symbol_type].table,
+						      key);
+		assert(s != NULL);
+		
+		if (symbol_type == SYM_LEVELS) {
+			*dest_value = ((level_datum_t *)s)->level->sens;
+		} else {
+			*dest_value = s->value;
+		}
+	} else if (retval == -2) {
+		/* ignore require statements if that symbol was
+		 * previously declared and is in current scope */
+		int prev_declaration_ok = 0;
+		if (is_id_in_scope(symbol_type, key)) {
+			if (symbol_type == SYM_TYPES) {
+				/* check that previous symbol has same
+				 * type/attribute-ness */
+				unsigned char new_isattr =
+				    ((type_datum_t *) datum)->flavor;
+				type_datum_t *old_datum =
+				    (type_datum_t *) hashtab_search(policydbp->
+								    symtab
+								    [SYM_TYPES].
+								    table, key);
+				assert(old_datum != NULL);
+				unsigned char old_isattr = old_datum->flavor;
+				prev_declaration_ok =
+				    (old_isattr == new_isattr ? 1 : 0);
+			} else {
+				prev_declaration_ok = 1;
+			}
+		}
+		if (prev_declaration_ok) {
+			/* ignore this require statement because it
+			 * was already declared within my scope */
+			stack_top->require_given = 1;
+			return 1;
+		} else {
+			/* previous declaration was not in scope or
+			 * had a mismatched type/attribute, so
+			 * generate an error */
+			return -2;
+		}
+	} else if (retval < 0) {
+		return -3;
+	} else {		/* fall through possible if retval is 0 or 1 */
+	}
+	if (datum_value != NULL) {
+		if (ebitmap_set_bit(decl->required.scope + symbol_type,
+				    *datum_value - 1, 1)) {
+			return -3;
+		}
+	}
+	stack_top->require_given = 1;
+	return retval;
+}
+
+int add_perm_to_class(uint32_t perm_value, uint32_t class_value)
+{
+	avrule_decl_t *decl = stack_top->decl;
+	scope_index_t *scope;
+
+	assert(perm_value >= 1);
+	assert(class_value >= 1);
+	scope = &decl->required;
+	if (class_value > scope->class_perms_len) {
+		uint32_t i;
+		ebitmap_t *new_map = realloc(scope->class_perms_map,
+					     class_value * sizeof(*new_map));
+		if (new_map == NULL) {
+			return -1;
+		}
+		scope->class_perms_map = new_map;
+		for (i = scope->class_perms_len; i < class_value; i++) {
+			ebitmap_init(scope->class_perms_map + i);
+		}
+		scope->class_perms_len = class_value;
+	}
+	if (ebitmap_set_bit(scope->class_perms_map + class_value - 1,
+			    perm_value - 1, 1)) {
+		return -1;
+	}
+	return 0;
+}
+
+static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+			__attribute__ ((unused)))
+{
+	if (key)
+		free(key);
+	free(datum);
+	return 0;
+}
+
+static void class_datum_destroy(class_datum_t * cladatum)
+{
+	if (cladatum != NULL) {
+		hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
+		hashtab_destroy(cladatum->permissions.table);
+		free(cladatum);
+	}
+}
+
+int require_class(int pass)
+{
+	char *class_id = queue_remove(id_queue);
+	char *perm_id = NULL;
+	class_datum_t *datum = NULL;
+	perm_datum_t *perm = NULL;
+	int ret;
+
+	if (pass == 2) {
+		free(class_id);
+		while ((perm_id = queue_remove(id_queue)) != NULL)
+			free(perm_id);
+		return 0;
+	}
+
+	/* first add the class if it is not already there */
+	if (class_id == NULL) {
+		yyerror("no class name for class definition?");
+		return -1;
+	}
+
+	if ((datum = calloc(1, sizeof(*datum))) == NULL ||
+	    symtab_init(&datum->permissions, PERM_SYMTAB_SIZE)) {
+		yyerror("Out of memory!");
+		goto cleanup;
+	}
+	ret =
+	    require_symbol(SYM_CLASSES, class_id, datum, &datum->s.value,
+			   &datum->s.value);
+	switch (ret) {
+	case -3:{
+			yyerror("Out of memory!");
+			free(class_id);
+			class_datum_destroy(datum);
+			goto cleanup;
+		}
+	case -2:{
+			yyerror("duplicate declaration of class");
+			free(class_id);
+			class_datum_destroy(datum);
+			goto cleanup;
+		}
+	case -1:{
+			yyerror("could not require class here");
+			free(class_id);
+			class_datum_destroy(datum);
+			goto cleanup;
+		}
+	case 0:{
+			/* a new class was added; reindex everything */
+			if (policydb_index_classes(policydbp)) {
+				yyerror("Out of memory!");
+				goto cleanup;
+			}
+			break;
+		}
+	case 1:{
+			class_datum_destroy(datum);
+			datum =
+			    hashtab_search(policydbp->p_classes.table,
+					   class_id);
+			assert(datum);	/* the class datum should have existed */
+			free(class_id);
+			break;
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+
+	/* now add each of the permissions to this class's requirements */
+	while ((perm_id = queue_remove(id_queue)) != NULL) {
+		int allocated = 0;
+
+		/* Is the permission already in the table? */
+		perm = hashtab_search(datum->permissions.table, perm_id);
+		if (!perm && datum->comdatum)
+			perm =
+			    hashtab_search(datum->comdatum->permissions.table,
+					   perm_id);
+		if (perm) {
+			/* Yes, drop the name. */
+			free(perm_id);
+		} else {
+			/* No - allocate and insert an entry for it. */
+			if (policydbp->policy_type == POLICY_BASE) {
+				yyerror2
+				    ("Base policy - require of permission %s without prior declaration.",
+				     perm_id);
+				free(perm_id);
+				goto cleanup;
+			}
+			allocated = 1;
+			if ((perm = malloc(sizeof(*perm))) == NULL) {
+				yyerror("Out of memory!");
+				free(perm_id);
+				goto cleanup;
+			}
+			memset(perm, 0, sizeof(*perm));
+			ret =
+			    hashtab_insert(datum->permissions.table, perm_id,
+					   perm);
+			if (ret) {
+				yyerror("Out of memory!");
+				free(perm_id);
+				free(perm);
+				goto cleanup;
+			}
+			perm->s.value = datum->permissions.nprim + 1;
+		}
+
+		if (add_perm_to_class(perm->s.value, datum->s.value) == -1) {
+			yyerror("Out of memory!");
+			goto cleanup;
+		}
+
+		/* Update number of primitives if we allocated one. */
+		if (allocated)
+			datum->permissions.nprim++;
+	}
+	return 0;
+      cleanup:
+	return -1;
+}
+
+static int require_role_or_attribute(int pass, unsigned char isattr)
+{
+	char *id = queue_remove(id_queue);
+	role_datum_t *role = NULL;
+	int retval;
+	if (pass == 2) {
+		free(id);
+		return 0;
+	}
+	if (id == NULL) {
+		yyerror("no role name");
+		return -1;
+	}
+	if ((role = malloc(sizeof(*role))) == NULL) {
+		free(id);
+		yyerror("Out of memory!");
+		return -1;
+	}
+	role_datum_init(role);
+	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
+	retval =
+	    require_symbol(SYM_ROLES, id, (hashtab_datum_t *) role,
+			   &role->s.value, &role->s.value);
+	if (retval != 0) {
+		free(id);
+		role_datum_destroy(role);
+		free(role);
+	}
+	switch (retval) {
+	case -3:{
+			yyerror("Out of memory!");
+			return -1;
+		}
+	case -2:{
+			yyerror("duplicate declaration of role");
+			return -1;
+		}
+	case -1:{
+			yyerror("could not require role here");
+			return -1;
+		}
+	case 0:{
+			/* all roles dominate themselves */
+			if (ebitmap_set_bit
+			    (&role->dominates, role->s.value - 1, 1)) {
+				yyerror("Out of memory");
+				return -1;
+			}
+			return 0;
+		}
+	case 1:{
+			return 0;	/* role already required */
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+}
+
+int require_role(int pass)
+{
+	return require_role_or_attribute(pass, 0);
+}
+
+int require_attribute_role(int pass)
+{
+	return require_role_or_attribute(pass, 1);
+}
+
+static int require_type_or_attribute(int pass, unsigned char isattr)
+{
+	char *id = queue_remove(id_queue);
+	type_datum_t *type = NULL;
+	int retval;
+	if (pass == 2) {
+		free(id);
+		return 0;
+	}
+	if (id == NULL) {
+		yyerror("no type name");
+		return -1;
+	}
+	if ((type = malloc(sizeof(*type))) == NULL) {
+		free(id);
+		yyerror("Out of memory!");
+		return -1;
+	}
+	type_datum_init(type);
+	type->primary = 1;
+	type->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
+	retval =
+	    require_symbol(SYM_TYPES, id, (hashtab_datum_t *) type,
+			   &type->s.value, &type->s.value);
+	if (retval != 0) {
+		free(id);
+		free(type);
+	}
+	switch (retval) {
+	case -3:{
+			yyerror("Out of memory!");
+			return -1;
+		}
+	case -2:{
+			yyerror("duplicate declaration of type/attribute");
+			return -1;
+		}
+	case -1:{
+			yyerror("could not require type/attribute here");
+			return -1;
+		}
+	case 0:{
+			return 0;
+		}
+	case 1:{
+			return 0;	/* type already required */
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+}
+
+int require_type(int pass)
+{
+	return require_type_or_attribute(pass, 0);
+}
+
+int require_attribute(int pass)
+{
+	return require_type_or_attribute(pass, 1);
+}
+
+int require_user(int pass)
+{
+	char *id = queue_remove(id_queue);
+	user_datum_t *user = NULL;
+	int retval;
+	if (pass == 1) {
+		free(id);
+		return 0;
+	}
+	if (id == NULL) {
+		yyerror("no user name");
+		return -1;
+	}
+	if ((user = malloc(sizeof(*user))) == NULL) {
+		free(id);
+		yyerror("Out of memory!");
+		return -1;
+	}
+	user_datum_init(user);
+	retval =
+	    require_symbol(SYM_USERS, id, (hashtab_datum_t *) user,
+			   &user->s.value, &user->s.value);
+	if (retval != 0) {
+		free(id);
+		user_datum_destroy(user);
+	}
+	switch (retval) {
+	case -3:{
+			yyerror("Out of memory!");
+			return -1;
+		}
+	case -2:{
+			yyerror("duplicate declaration of user");
+			return -1;
+		}
+	case -1:{
+			yyerror("could not require user here");
+			return -1;
+		}
+	case 0:{
+			return 0;
+		}
+	case 1:{
+			return 0;	/* user already required */
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+}
+
+static int require_bool_tunable(int pass, int is_tunable)
+{
+	char *id = queue_remove(id_queue);
+	cond_bool_datum_t *booldatum = NULL;
+	int retval;
+	if (pass == 2) {
+		free(id);
+		return 0;
+	}
+	if (id == NULL) {
+		yyerror("no boolean name");
+		return -1;
+	}
+	if ((booldatum = calloc(1, sizeof(*booldatum))) == NULL) {
+		cond_destroy_bool(id, booldatum, NULL);
+		yyerror("Out of memory!");
+		return -1;
+	}
+	if (is_tunable)
+		booldatum->flags |= COND_BOOL_FLAGS_TUNABLE;
+	retval =
+	    require_symbol(SYM_BOOLS, id, (hashtab_datum_t *) booldatum,
+			   &booldatum->s.value, &booldatum->s.value);
+	if (retval != 0) {
+		cond_destroy_bool(id, booldatum, NULL);
+	}
+	switch (retval) {
+	case -3:{
+			yyerror("Out of memory!");
+			return -1;
+		}
+	case -2:{
+			yyerror("duplicate declaration of boolean");
+			return -1;
+		}
+	case -1:{
+			yyerror("could not require boolean here");
+			return -1;
+		}
+	case 0:{
+			return 0;
+		}
+	case 1:{
+			return 0;	/* boolean already required */
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+}
+
+int require_bool(int pass)
+{
+	return require_bool_tunable(pass, 0);
+}
+
+int require_tunable(int pass)
+{
+	return require_bool_tunable(pass, 1);
+}
+
+int require_sens(int pass)
+{
+	char *id = queue_remove(id_queue);
+	level_datum_t *level = NULL;
+	int retval;
+	if (pass == 2) {
+		free(id);
+		return 0;
+	}
+	if (!id) {
+		yyerror("no sensitivity name");
+		return -1;
+	}
+	level = malloc(sizeof(level_datum_t));
+	if (!level) {
+		free(id);
+		yyerror("Out of memory!");
+		return -1;
+	}
+	level_datum_init(level);
+	level->level = malloc(sizeof(mls_level_t));
+	if (!level->level) {
+		free(id);
+		level_datum_destroy(level);
+		free(level);
+		yyerror("Out of memory!");
+		return -1;
+	}
+	mls_level_init(level->level);
+	retval = require_symbol(SYM_LEVELS, id, (hashtab_datum_t *) level,
+				&level->level->sens, &level->level->sens);
+	if (retval != 0) {
+		free(id);
+		mls_level_destroy(level->level);
+		free(level->level);
+		level_datum_destroy(level);
+		free(level);
+	}
+	switch (retval) {
+	case -3:{
+			yyerror("Out of memory!");
+			return -1;
+		}
+	case -2:{
+			yyerror("duplicate declaration of sensitivity");
+			return -1;
+		}
+	case -1:{
+			yyerror("could not require sensitivity here");
+			return -1;
+		}
+	case 0:{
+			return 0;
+		}
+	case 1:{
+			return 0;	/* sensitivity already required */
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+}
+
+int require_cat(int pass)
+{
+	char *id = queue_remove(id_queue);
+	cat_datum_t *cat = NULL;
+	int retval;
+	if (pass == 2) {
+		free(id);
+		return 0;
+	}
+	if (!id) {
+		yyerror("no category name");
+		return -1;
+	}
+	cat = malloc(sizeof(cat_datum_t));
+	if (!cat) {
+		free(id);
+		yyerror("Out of memory!");
+		return -1;
+	}
+	cat_datum_init(cat);
+
+	retval = require_symbol(SYM_CATS, id, (hashtab_datum_t *) cat,
+				&cat->s.value, &cat->s.value);
+	if (retval != 0) {
+		free(id);
+		cat_datum_destroy(cat);
+		free(cat);
+	}
+	switch (retval) {
+	case -3:{
+			yyerror("Out of memory!");
+			return -1;
+		}
+	case -2:{
+			yyerror("duplicate declaration of category");
+			return -1;
+		}
+	case -1:{
+			yyerror("could not require category here");
+			return -1;
+		}
+	case 0:{
+			return 0;
+		}
+	case 1:{
+			return 0;	/* category already required */
+		}
+	default:{
+			abort();	/* should never get here */
+		}
+	}
+}
+
+static int is_scope_in_stack(scope_datum_t * scope, scope_stack_t * stack)
+{
+	uint32_t i;
+	if (stack == NULL) {
+		return 0;	/* no matching scope found */
+	}
+	if (stack->type == 1) {
+		avrule_decl_t *decl = stack->decl;
+		for (i = 0; i < scope->decl_ids_len; i++) {
+			if (scope->decl_ids[i] == decl->decl_id) {
+				return 1;
+			}
+		}
+	} else {
+		/* note that conditionals can't declare or require
+		 * symbols, so skip this level */
+	}
+
+	/* not within scope of this stack, so try its parent */
+	return is_scope_in_stack(scope, stack->parent);
+}
+
+int is_id_in_scope(uint32_t symbol_type, hashtab_key_t id)
+{
+	scope_datum_t *scope =
+	    (scope_datum_t *) hashtab_search(policydbp->scope[symbol_type].
+					     table, id);
+	if (scope == NULL) {
+		return 1;	/* id is not known, so return success */
+	}
+	return is_scope_in_stack(scope, stack_top);
+}
+
+static int is_perm_in_scope_index(uint32_t perm_value, uint32_t class_value,
+				  scope_index_t * scope)
+{
+	if (class_value > scope->class_perms_len) {
+		return 1;
+	}
+	if (ebitmap_get_bit(scope->class_perms_map + class_value - 1,
+			    perm_value - 1)) {
+		return 1;
+	}
+	return 0;
+}
+
+static int is_perm_in_stack(uint32_t perm_value, uint32_t class_value,
+			    scope_stack_t * stack)
+{
+	if (stack == NULL) {
+		return 0;	/* no matching scope found */
+	}
+	if (stack->type == 1) {
+		avrule_decl_t *decl = stack->decl;
+		if (is_perm_in_scope_index
+		    (perm_value, class_value, &decl->required)
+		    || is_perm_in_scope_index(perm_value, class_value,
+					      &decl->declared)) {
+			return 1;
+		}
+	} else {
+		/* note that conditionals can't declare or require
+		 * symbols, so skip this level */
+	}
+
+	/* not within scope of this stack, so try its parent */
+	return is_perm_in_stack(perm_value, class_value, stack->parent);
+}
+
+int is_perm_in_scope(hashtab_key_t perm_id, hashtab_key_t class_id)
+{
+	class_datum_t *cladatum =
+	    (class_datum_t *) hashtab_search(policydbp->p_classes.table,
+					     class_id);
+	perm_datum_t *perdatum;
+	if (cladatum == NULL) {
+		return 1;
+	}
+	perdatum = (perm_datum_t *) hashtab_search(cladatum->permissions.table,
+						   perm_id);
+	if (perdatum == NULL) {
+		return 1;
+	}
+	return is_perm_in_stack(perdatum->s.value, cladatum->s.value,
+				stack_top);
+}
+
+cond_list_t *get_current_cond_list(cond_list_t * cond)
+{
+	/* FIX ME: do something different here if in a nested
+	 * conditional? */
+	avrule_decl_t *decl = stack_top->decl;
+	return get_decl_cond_list(policydbp, decl, cond);
+}
+
+/* Append the new conditional node to the existing ones.  During
+ * expansion the list will be reversed -- i.e., the last AV rule will
+ * be the first one listed in the policy.  This matches the behavior
+ * of the upstream compiler. */
+void append_cond_list(cond_list_t * cond)
+{
+	cond_list_t *old_cond = get_current_cond_list(cond);
+	avrule_t *tmp;
+	assert(old_cond != NULL);	/* probably out of memory */
+	if (old_cond->avtrue_list == NULL) {
+		old_cond->avtrue_list = cond->avtrue_list;
+	} else {
+		for (tmp = old_cond->avtrue_list; tmp->next != NULL;
+		     tmp = tmp->next) ;
+		tmp->next = cond->avtrue_list;
+	}
+	if (old_cond->avfalse_list == NULL) {
+		old_cond->avfalse_list = cond->avfalse_list;
+	} else {
+		for (tmp = old_cond->avfalse_list; tmp->next != NULL;
+		     tmp = tmp->next) ;
+		tmp->next = cond->avfalse_list;
+	}
+
+	old_cond->flags |= cond->flags;
+}
+
+void append_avrule(avrule_t * avrule)
+{
+	avrule_decl_t *decl = stack_top->decl;
+
+	/* currently avrules follow a completely different code path
+	 * for handling avrules and compute types
+	 * (define_cond_avrule_te_avtab, define_cond_compute_type);
+	 * therefore there ought never be a conditional on top of the
+	 * scope stack */
+	assert(stack_top->type == 1);
+
+	if (stack_top->last_avrule == NULL) {
+		decl->avrules = avrule;
+	} else {
+		stack_top->last_avrule->next = avrule;
+	}
+	stack_top->last_avrule = avrule;
+}
+
+/* this doesn't actually append, but really prepends it */
+void append_role_trans(role_trans_rule_t * role_tr_rules)
+{
+	avrule_decl_t *decl = stack_top->decl;
+
+	/* role transitions are not allowed within conditionals */
+	assert(stack_top->type == 1);
+
+	role_tr_rules->next = decl->role_tr_rules;
+	decl->role_tr_rules = role_tr_rules;
+}
+
+/* this doesn't actually append, but really prepends it */
+void append_role_allow(role_allow_rule_t * role_allow_rules)
+{
+	avrule_decl_t *decl = stack_top->decl;
+
+	/* role allows are not allowed within conditionals */
+	assert(stack_top->type == 1);
+
+	role_allow_rules->next = decl->role_allow_rules;
+	decl->role_allow_rules = role_allow_rules;
+}
+
+/* this doesn't actually append, but really prepends it */
+void append_filename_trans(filename_trans_rule_t * filename_trans_rules)
+{
+	avrule_decl_t *decl = stack_top->decl;
+
+	/* filename transitions are not allowed within conditionals */
+	assert(stack_top->type == 1);
+
+	filename_trans_rules->next = decl->filename_trans_rules;
+	decl->filename_trans_rules = filename_trans_rules;
+}
+
+/* this doesn't actually append, but really prepends it */
+void append_range_trans(range_trans_rule_t * range_tr_rules)
+{
+	avrule_decl_t *decl = stack_top->decl;
+
+	/* range transitions are not allowed within conditionals */
+	assert(stack_top->type == 1);
+
+	range_tr_rules->next = decl->range_tr_rules;
+	decl->range_tr_rules = range_tr_rules;
+}
+
+int begin_optional(int pass)
+{
+	avrule_block_t *block = NULL;
+	avrule_decl_t *decl;
+	if (pass == 1) {
+		/* allocate a new avrule block for this optional block */
+		if ((block = avrule_block_create()) == NULL ||
+		    (decl = avrule_decl_create(next_decl_id)) == NULL) {
+			goto cleanup;
+		}
+		block->flags |= AVRULE_OPTIONAL;
+		block->branch_list = decl;
+		last_block->next = block;
+	} else {
+		/* select the next block from the chain built during pass 1 */
+		block = last_block->next;
+		assert(block != NULL &&
+		       block->branch_list != NULL &&
+		       block->branch_list->decl_id == next_decl_id);
+		decl = block->branch_list;
+	}
+	if (push_stack(1, block, decl) == -1) {
+		goto cleanup;
+	}
+	stack_top->last_avrule = NULL;
+	last_block = block;
+	next_decl_id++;
+	return 0;
+      cleanup:
+	yyerror("Out of memory!");
+	avrule_block_destroy(block);
+	return -1;
+}
+
+int end_optional(int pass __attribute__ ((unused)))
+{
+	/* once nested conditionals are allowed, do the stack unfolding here */
+	pop_stack();
+	return 0;
+}
+
+int begin_optional_else(int pass)
+{
+	avrule_decl_t *decl;
+	assert(stack_top->type == 1 && stack_top->in_else == 0);
+	if (pass == 1) {
+		/* allocate a new declaration and add it to the
+		 * current chain */
+		if ((decl = avrule_decl_create(next_decl_id)) == NULL) {
+			yyerror("Out of memory!");
+			return -1;
+		}
+		stack_top->decl->next = decl;
+	} else {
+		/* pick the (hopefully last) declaration of this
+		   avrule block, built from pass 1 */
+		decl = stack_top->decl->next;
+		assert(decl != NULL &&
+		       decl->next == NULL && decl->decl_id == next_decl_id);
+	}
+	stack_top->in_else = 1;
+	stack_top->decl = decl;
+	stack_top->last_avrule = NULL;
+	stack_top->require_given = 0;
+	next_decl_id++;
+	return 0;
+}
+
+static int copy_requirements(avrule_decl_t * dest, scope_stack_t * stack)
+{
+	uint32_t i;
+	if (stack == NULL) {
+		return 0;
+	}
+	if (stack->type == 1) {
+		scope_index_t *src_scope = &stack->decl->required;
+		scope_index_t *dest_scope = &dest->required;
+		for (i = 0; i < SYM_NUM; i++) {
+			ebitmap_t *src_bitmap = &src_scope->scope[i];
+			ebitmap_t *dest_bitmap = &dest_scope->scope[i];
+			if (ebitmap_union(dest_bitmap, src_bitmap)) {
+				yyerror("Out of memory!");
+				return -1;
+			}
+		}
+		/* now copy class permissions */
+		if (src_scope->class_perms_len > dest_scope->class_perms_len) {
+			ebitmap_t *new_map =
+			    realloc(dest_scope->class_perms_map,
+				    src_scope->class_perms_len *
+				    sizeof(*new_map));
+			if (new_map == NULL) {
+				yyerror("Out of memory!");
+				return -1;
+			}
+			dest_scope->class_perms_map = new_map;
+			for (i = dest_scope->class_perms_len;
+			     i < src_scope->class_perms_len; i++) {
+				ebitmap_init(dest_scope->class_perms_map + i);
+			}
+			dest_scope->class_perms_len =
+			    src_scope->class_perms_len;
+		}
+		for (i = 0; i < src_scope->class_perms_len; i++) {
+			ebitmap_t *src_bitmap = &src_scope->class_perms_map[i];
+			ebitmap_t *dest_bitmap =
+			    &dest_scope->class_perms_map[i];
+			if (ebitmap_union(dest_bitmap, src_bitmap)) {
+				yyerror("Out of memory!");
+				return -1;
+			}
+		}
+	}
+	return copy_requirements(dest, stack->parent);
+}
+
+/* During pass 1, check that at least one thing was required within
+ * this block, for those places where a REQUIRED is necessary.  During
+ * pass 2, have this block inherit its parents' requirements.  Return
+ * 0 on success, -1 on failure. */
+int end_avrule_block(int pass)
+{
+	avrule_decl_t *decl = stack_top->decl;
+	assert(stack_top->type == 1);
+	if (pass == 2) {
+		/* this avrule_decl inherits all of its parents'
+		 * requirements */
+		if (copy_requirements(decl, stack_top->parent) == -1) {
+			return -1;
+		}
+		return 0;
+	}
+	if (!stack_top->in_else && !stack_top->require_given) {
+		if (policydbp->policy_type == POLICY_BASE
+		    && stack_top->parent != NULL) {
+			/* if this is base no require should be in the global block */
+			return 0;
+		} else {
+			/* non-ELSE branches must have at least one thing required */
+			yyerror("This block has no require section.");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/* Push a new scope on to the stack and update the 'last' pointer.
+ * Return 0 on success, -1 if out * of memory. */
+static int push_stack(int stack_type, ...)
+{
+	scope_stack_t *s = calloc(1, sizeof(*s));
+	va_list ap;
+	if (s == NULL) {
+		return -1;
+	}
+	va_start(ap, stack_type);
+	switch (s->type = stack_type) {
+	case 1:{
+			s->u.avrule = va_arg(ap, avrule_block_t *);
+			s->decl = va_arg(ap, avrule_decl_t *);
+			break;
+		}
+	case 2:{
+			s->u.cond_list = va_arg(ap, cond_list_t *);
+			break;
+		}
+	default:
+		/* invalid stack type given */
+		assert(0);
+	}
+	va_end(ap);
+	s->parent = stack_top;
+	s->child = NULL;
+	stack_top = s;
+	return 0;
+}
+
+/* Pop off the most recently added from the stack.  Update the 'last'
+ * pointer. */
+static void pop_stack(void)
+{
+	scope_stack_t *parent;
+	assert(stack_top != NULL);
+	parent = stack_top->parent;
+	if (parent != NULL) {
+		parent->child = NULL;
+	}
+	free(stack_top);
+	stack_top = parent;
+}
diff --git a/checkpolicy/module_compiler.h b/checkpolicy/module_compiler.h
new file mode 100644
index 0000000..72c2d9b
--- /dev/null
+++ b/checkpolicy/module_compiler.h
@@ -0,0 +1,109 @@
+/* Author : Joshua Brindle <jbrindle@tresys.com>
+ *	    Karl MacMillan <kmacmillan@tresys.com>
+ *          Jason Tang     <jtang@tresys.com>
+ *	Added support for binary policy modules
+ *
+ * Copyright (C) 2004 - 2005 Tresys Technology, LLC
+ *	This program is free software; you can redistribute it and/or modify
+ *  	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, version 2.
+ */
+
+#ifndef MODULE_COMPILER_H
+#define MODULE_COMPILER_H
+
+#include <sepol/policydb/hashtab.h>
+
+/* Called when checkpolicy begins to parse a policy -- either at the
+ * very beginning for a kernel/base policy, or after the module header
+ * for policy modules.  Initialize the memory structures within.
+ * Return 0 on success, -1 on error. */
+int define_policy(int pass, int module_header_given);
+
+/* Declare a symbol declaration to the current avrule_decl.  Check
+ * that insertion is allowed here and that the symbol does not already
+ * exist.  Returns 0 on success, 1 if symbol was already there (caller
+ * needs to free() the datum), -1 if declarations not allowed, -2 for
+ * duplicate declarations, -3 for all else.
+ */
+int declare_symbol(uint32_t symbol_type,
+		   hashtab_key_t key, hashtab_datum_t datum,
+		   uint32_t * dest_value, uint32_t * datum_value);
+
+role_datum_t *declare_role(unsigned char isattr);
+type_datum_t *declare_type(unsigned char primary, unsigned char isattr);
+user_datum_t *declare_user(void);
+
+type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr);
+role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr);
+
+/* Add a symbol to the current avrule_block's require section.  Note
+ * that a module may not both declare and require the same symbol.
+ * Returns 0 on success, -1 on error. */
+int require_symbol(uint32_t symbol_type,
+		   hashtab_key_t key, hashtab_datum_t datum,
+		   uint32_t * dest_value, uint32_t * datum_value);
+
+/* Enable a permission for a class within the current avrule_decl.
+ * Return 0 on success, -1 if out of memory. */
+int add_perm_to_class(uint32_t perm_value, uint32_t class_value);
+
+/* Functions called from REQUIRE blocks.  Add the first symbol on the
+ * id_queue to this avrule_decl's scope if not already there.
+ * c.f. require_symbol(). */
+int require_class(int pass);
+int require_role(int pass);
+int require_type(int pass);
+int require_attribute(int pass);
+int require_attribute_role(int pass);
+int require_user(int pass);
+int require_bool(int pass);
+int require_tunable(int pass);
+int require_sens(int pass);
+int require_cat(int pass);
+
+/* Check if an identifier is within the scope of the current
+ * declaration or any of its parents.  Return 1 if it is, 0 if not.
+ * If the identifier is not known at all then return 1 (truth).  */
+int is_id_in_scope(uint32_t symbol_type, hashtab_key_t id);
+
+/* Check if a particular permission is within the scope of the current
+ * declaration or any of its parents.  Return 1 if it is, 0 if not.
+ * If the identifier is not known at all then return 1 (truth).  */
+int is_perm_in_scope(hashtab_key_t perm_id, hashtab_key_t class_id);
+
+/* Search the current avrules block for a conditional with the same
+ * expression as 'cond'.  If the conditional does not exist then
+ * create one.  Either way, return the conditional. */
+cond_list_t *get_current_cond_list(cond_list_t * cond);
+
+/* Append rule to the current avrule_block. */
+void append_cond_list(cond_list_t * cond);
+void append_avrule(avrule_t * avrule);
+void append_role_trans(role_trans_rule_t * role_tr_rules);
+void append_role_allow(role_allow_rule_t * role_allow_rules);
+void append_range_trans(range_trans_rule_t * range_tr_rules);
+void append_filename_trans(filename_trans_rule_t * filename_trans_rules);
+
+/* Create a new optional block and add it to the global policy.
+ * During the second pass resolve the block's requirements.  Return 0
+ * on success, -1 on error.
+ */
+int begin_optional(int pass);
+int end_optional(int pass);
+
+/* ELSE blocks are similar to normal blocks with the following two
+ * limitations:
+ *   - no declarations are allowed within else branches
+ *   - no REQUIRES are allowed; the else branch inherits the parent's
+ *     requirements
+ */
+int begin_optional_else(int pass);
+
+/* Called whenever existing an avrule block.  Check that the block had
+ * a non-empty REQUIRE section.  If so pop the block off of the scop
+ * stack and return 0.  If not then send an error to yyerror and
+ * return -1. */
+int end_avrule_block(int pass);
+
+#endif
diff --git a/checkpolicy/parse_util.c b/checkpolicy/parse_util.c
new file mode 100644
index 0000000..9fda5b4
--- /dev/null
+++ b/checkpolicy/parse_util.c
@@ -0,0 +1,78 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "parse_util.h"
+#include "queue.h"
+
+/* these are defined in policy_parse.y and are needed for read_source_policy */
+extern FILE *yyin;
+extern void init_parser(int);
+extern int yyparse(void);
+extern void yyrestart(FILE *);
+extern queue_t id_queue;
+extern unsigned int policydb_errors;
+extern unsigned long policydb_lineno;
+extern policydb_t *policydbp;
+extern int mlspol;
+extern void set_source_file(const char *name);
+
+int read_source_policy(policydb_t * p, const char *file, const char *progname)
+{
+	yyin = fopen(file, "r");
+	if (!yyin) {
+		fprintf(stderr, "%s:  unable to open %s\n", progname, file);
+		return -1;
+	}
+	set_source_file(file);
+
+	if ((id_queue = queue_create()) == NULL) {
+		fprintf(stderr, "%s: out of memory!\n", progname);
+		return -1;
+	}
+
+	policydbp = p;
+	mlspol = p->mls;
+
+	init_parser(1);
+	if (yyparse() || policydb_errors) {
+		fprintf(stderr,
+			"%s:  error(s) encountered while parsing configuration\n",
+			progname);
+		return -1;
+	}
+	rewind(yyin);
+	init_parser(2);
+	set_source_file(file);
+	yyrestart(yyin);
+	if (yyparse() || policydb_errors) {
+		fprintf(stderr,
+			"%s:  error(s) encountered while parsing configuration\n",
+			progname);
+		return -1;
+	}
+	queue_destroy(id_queue);
+
+	if (policydb_errors)
+		return -1;
+
+	fclose(yyin);
+
+	return 0;
+}
diff --git a/checkpolicy/parse_util.h b/checkpolicy/parse_util.h
new file mode 100644
index 0000000..a80128a
--- /dev/null
+++ b/checkpolicy/parse_util.h
@@ -0,0 +1,35 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* Utility functions shared by checkpolicy and checkmodule */
+
+#ifndef __PARSE_UTIL_H__
+#define __PARSE_UTIL_H__
+
+#include <sepol/policydb/policydb.h>
+
+/* Read a source policy and populate the policydb passed in. The
+ * policydb must already have been created and configured (e.g.,
+ * expected policy type set. The string progname is used for
+ * error messages. No checking of assertions, hierarchy, etc.
+ * is done. */
+int read_source_policy(policydb_t * p, const char *file, const char *progname);
+
+#endif
diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
new file mode 100644
index 0000000..100e517
--- /dev/null
+++ b/checkpolicy/policy_define.c
@@ -0,0 +1,5476 @@
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Updated: David Caplan, <dac@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Updated: Joshua Brindle <jbrindle@tresys.com>
+ *	    Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *          Jason Tang     <jtang@tresys.com>
+ *
+ *	Added support for binary policy modules
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2008 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat Inc.
+ *	This program is free software; you can redistribute it and/or modify
+ *  	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, version 2.
+ */
+
+/* FLASK */
+
+#include <sys/types.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <ctype.h>
+
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/polcaps.h>
+#include "queue.h"
+#include "checkpolicy.h"
+#include "module_compiler.h"
+#include "policy_define.h"
+
+policydb_t *policydbp;
+queue_t id_queue = 0;
+unsigned int pass;
+char *curfile = 0;
+int mlspol = 0;
+
+extern unsigned long policydb_lineno;
+extern unsigned long source_lineno;
+extern unsigned int policydb_errors;
+extern char source_file[PATH_MAX];
+
+extern int yywarn(const char *msg);
+extern int yyerror(const char *msg);
+
+#define ERRORMSG_LEN 255
+static char errormsg[ERRORMSG_LEN + 1] = {0};
+
+static int id_has_dot(char *id);
+static int parse_security_context(context_struct_t *c);
+
+/* initialize all of the state variables for the scanner/parser */
+void init_parser(int pass_number)
+{
+	policydb_lineno = 1;
+	source_lineno = 1;
+	policydb_errors = 0;
+	pass = pass_number;
+}
+
+__attribute__ ((format(printf, 1, 2)))
+void yyerror2(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	vsnprintf(errormsg, ERRORMSG_LEN, fmt, ap);
+	yyerror(errormsg);
+	va_end(ap);
+}
+
+int insert_separator(int push)
+{
+	int error;
+
+	if (push)
+		error = queue_push(id_queue, 0);
+	else
+		error = queue_insert(id_queue, 0);
+
+	if (error) {
+		yyerror("queue overflow");
+		return -1;
+	}
+	return 0;
+}
+
+int insert_id(const char *id, int push)
+{
+	char *newid = 0;
+	int error;
+
+	newid = (char *)malloc(strlen(id) + 1);
+	if (!newid) {
+		yyerror("out of memory");
+		return -1;
+	}
+	strcpy(newid, id);
+	if (push)
+		error = queue_push(id_queue, (queue_element_t) newid);
+	else
+		error = queue_insert(id_queue, (queue_element_t) newid);
+
+	if (error) {
+		yyerror("queue overflow");
+		free(newid);
+		return -1;
+	}
+	return 0;
+}
+
+/* If the identifier has a dot within it and that its first character
+   is not a dot then return 1, else return 0. */
+static int id_has_dot(char *id)
+{
+	if (strchr(id, '.') >= id + 1) {
+		return 1;
+	}
+	return 0;
+}
+
+int define_class(void)
+{
+	char *id = 0;
+	class_datum_t *datum = 0;
+	int ret;
+	uint32_t value;
+
+	if (pass == 2) {
+		id = queue_remove(id_queue);
+		free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no class name for class definition?");
+		return -1;
+	}
+	datum = (class_datum_t *) malloc(sizeof(class_datum_t));
+	if (!datum) {
+		yyerror("out of memory");
+		goto bad;
+	}
+	memset(datum, 0, sizeof(class_datum_t));
+	ret = declare_symbol(SYM_CLASSES, id, datum, &value, &value);
+	switch (ret) {
+	case -3:{
+			yyerror("Out of memory!");
+			goto bad;
+		}
+	case -2:{
+			yyerror2("duplicate declaration of class %s", id);
+			goto bad;
+		}
+	case -1:{
+			yyerror("could not declare class here");
+			goto bad;
+		}
+	case 0:
+	case 1:{
+			break;
+		}
+	default:{
+			assert(0);	/* should never get here */
+		}
+	}
+	datum->s.value = value;
+	return 0;
+
+      bad:
+	if (id)
+		free(id);
+	if (datum)
+		free(datum);
+	return -1;
+}
+
+int define_permissive(void)
+{
+	char *type = NULL;
+	struct type_datum *t;
+	int rc = 0;
+
+	type = queue_remove(id_queue);
+
+	if (!type) {
+		yyerror2("forgot to include type in permissive definition?");
+		rc = -1;
+		goto out;
+	}
+
+	if (pass == 1)
+		goto out;
+
+	if (!is_id_in_scope(SYM_TYPES, type)) {
+		yyerror2("type %s is not within scope", type);
+		rc = -1;
+		goto out;
+	}
+
+	t = hashtab_search(policydbp->p_types.table, type);
+	if (!t) {
+		yyerror2("type is not defined: %s", type);
+		rc = -1;
+		goto out;
+	}
+
+	if (t->flavor == TYPE_ATTRIB) {
+		yyerror2("attributes may not be permissive: %s\n", type);
+		rc = -1;
+		goto out;
+	}
+
+	t->flags |= TYPE_FLAGS_PERMISSIVE;
+
+out:
+	free(type);
+	return rc;
+}
+
+int define_polcap(void)
+{
+	char *id = 0;
+	int capnum;
+
+	if (pass == 2) {
+		id = queue_remove(id_queue);
+		free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no capability name for policycap definition?");
+		goto bad;
+	}
+
+	/* Check for valid cap name -> number mapping */
+	capnum = sepol_polcap_getnum(id);
+	if (capnum < 0) {
+		yyerror2("invalid policy capability name %s", id);
+		goto bad;
+	}
+
+	/* Store it */
+	if (ebitmap_set_bit(&policydbp->policycaps, capnum, TRUE)) {
+		yyerror("out of memory");
+		goto bad;
+	}
+
+	free(id);
+	return 0;
+
+      bad:
+	free(id);
+	return -1;
+}
+
+int define_initial_sid(void)
+{
+	char *id = 0;
+	ocontext_t *newc = 0, *c, *head;
+
+	if (pass == 2) {
+		id = queue_remove(id_queue);
+		free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no sid name for SID definition?");
+		return -1;
+	}
+	newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		goto bad;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+	newc->u.name = id;
+	context_init(&newc->context[0]);
+	head = policydbp->ocontexts[OCON_ISID];
+
+	for (c = head; c; c = c->next) {
+		if (!strcmp(newc->u.name, c->u.name)) {
+			yyerror2("duplicate initial SID %s", id);
+			goto bad;
+		}
+	}
+
+	if (head) {
+		newc->sid[0] = head->sid[0] + 1;
+	} else {
+		newc->sid[0] = 1;
+	}
+	newc->next = head;
+	policydbp->ocontexts[OCON_ISID] = newc;
+
+	return 0;
+
+      bad:
+	if (id)
+		free(id);
+	if (newc)
+		free(newc);
+	return -1;
+}
+
+static int read_classes(ebitmap_t *e_classes)
+{
+	char *id;
+	class_datum_t *cladatum;
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_CLASSES, id)) {
+			yyerror2("class %s is not within scope", id);
+			return -1;
+		}
+		cladatum = hashtab_search(policydbp->p_classes.table, id);
+		if (!cladatum) {
+			yyerror2("unknown class %s", id);
+			return -1;
+		}
+		if (ebitmap_set_bit(e_classes, cladatum->s.value - 1, TRUE)) {
+			yyerror("Out of memory");
+			return -1;
+		}
+		free(id);
+	}
+	return 0;
+}
+
+int define_default_user(int which)
+{
+	char *id;
+	class_datum_t *cladatum;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_CLASSES, id)) {
+			yyerror2("class %s is not within scope", id);
+			return -1;
+		}
+		cladatum = hashtab_search(policydbp->p_classes.table, id);
+		if (!cladatum) {
+			yyerror2("unknown class %s", id);
+			return -1;
+		}
+		if (cladatum->default_user && cladatum->default_user != which) {
+			yyerror2("conflicting default user information for class %s", id);
+			return -1;
+		}
+		cladatum->default_user = which;
+		free(id);
+	}
+
+	return 0;
+}
+
+int define_default_role(int which)
+{
+	char *id;
+	class_datum_t *cladatum;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_CLASSES, id)) {
+			yyerror2("class %s is not within scope", id);
+			return -1;
+		}
+		cladatum = hashtab_search(policydbp->p_classes.table, id);
+		if (!cladatum) {
+			yyerror2("unknown class %s", id);
+			return -1;
+		}
+		if (cladatum->default_role && cladatum->default_role != which) {
+			yyerror2("conflicting default role information for class %s", id);
+			return -1;
+		}
+		cladatum->default_role = which;
+		free(id);
+	}
+
+	return 0;
+}
+
+int define_default_type(int which)
+{
+	char *id;
+	class_datum_t *cladatum;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_CLASSES, id)) {
+			yyerror2("class %s is not within scope", id);
+			return -1;
+		}
+		cladatum = hashtab_search(policydbp->p_classes.table, id);
+		if (!cladatum) {
+			yyerror2("unknown class %s", id);
+			return -1;
+		}
+		if (cladatum->default_type && cladatum->default_type != which) {
+			yyerror2("conflicting default type information for class %s", id);
+			return -1;
+		}
+		cladatum->default_type = which;
+		free(id);
+	}
+
+	return 0;
+}
+
+int define_default_range(int which)
+{
+	char *id;
+	class_datum_t *cladatum;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_CLASSES, id)) {
+			yyerror2("class %s is not within scope", id);
+			return -1;
+		}
+		cladatum = hashtab_search(policydbp->p_classes.table, id);
+		if (!cladatum) {
+			yyerror2("unknown class %s", id);
+			return -1;
+		}
+		if (cladatum->default_range && cladatum->default_range != which) {
+			yyerror2("conflicting default range information for class %s", id);
+			return -1;
+		}
+		cladatum->default_range = which;
+		free(id);
+	}
+
+	return 0;
+}
+
+int define_common_perms(void)
+{
+	char *id = 0, *perm = 0;
+	common_datum_t *comdatum = 0;
+	perm_datum_t *perdatum = 0;
+	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 common name for common perm definition?");
+		return -1;
+	}
+	comdatum = hashtab_search(policydbp->p_commons.table, id);
+	if (comdatum) {
+		yyerror2("duplicate declaration for common %s\n", id);
+		return -1;
+	}
+	comdatum = (common_datum_t *) malloc(sizeof(common_datum_t));
+	if (!comdatum) {
+		yyerror("out of memory");
+		goto bad;
+	}
+	memset(comdatum, 0, sizeof(common_datum_t));
+	ret = hashtab_insert(policydbp->p_commons.table,
+			     (hashtab_key_t) id, (hashtab_datum_t) comdatum);
+
+	if (ret == SEPOL_EEXIST) {
+		yyerror("duplicate common definition");
+		goto bad;
+	}
+	if (ret == SEPOL_ENOMEM) {
+		yyerror("hash table overflow");
+		goto bad;
+	}
+	comdatum->s.value = policydbp->p_commons.nprim + 1;
+	if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE)) {
+		yyerror("out of memory");
+		goto bad;
+	}
+	policydbp->p_commons.nprim++;
+	while ((perm = queue_remove(id_queue))) {
+		perdatum = (perm_datum_t *) malloc(sizeof(perm_datum_t));
+		if (!perdatum) {
+			yyerror("out of memory");
+			goto bad_perm;
+		}
+		memset(perdatum, 0, sizeof(perm_datum_t));
+		perdatum->s.value = comdatum->permissions.nprim + 1;
+
+		if (perdatum->s.value > (sizeof(sepol_access_vector_t) * 8)) {
+			yyerror
+			    ("too many permissions to fit in an access vector");
+			goto bad_perm;
+		}
+		ret = hashtab_insert(comdatum->permissions.table,
+				     (hashtab_key_t) perm,
+				     (hashtab_datum_t) perdatum);
+
+		if (ret == SEPOL_EEXIST) {
+			yyerror2("duplicate permission %s in common %s", perm,
+				 id);
+			goto bad_perm;
+		}
+		if (ret == SEPOL_ENOMEM) {
+			yyerror("hash table overflow");
+			goto bad_perm;
+		}
+		comdatum->permissions.nprim++;
+	}
+
+	return 0;
+
+      bad:
+	if (id)
+		free(id);
+	if (comdatum)
+		free(comdatum);
+	return -1;
+
+      bad_perm:
+	if (perm)
+		free(perm);
+	if (perdatum)
+		free(perdatum);
+	return -1;
+}
+
+int define_av_perms(int inherits)
+{
+	char *id;
+	class_datum_t *cladatum;
+	common_datum_t *comdatum;
+	perm_datum_t *perdatum = 0, *perdatum2 = 0;
+	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 tclass name for av perm definition?");
+		return -1;
+	}
+	cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table,
+						    (hashtab_key_t) id);
+	if (!cladatum) {
+		yyerror2("class %s is not defined", id);
+		goto bad;
+	}
+	free(id);
+
+	if (cladatum->comdatum || cladatum->permissions.nprim) {
+		yyerror("duplicate access vector definition");
+		return -1;
+	}
+	if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE)) {
+		yyerror("out of memory");
+		return -1;
+	}
+	if (inherits) {
+		id = (char *)queue_remove(id_queue);
+		if (!id) {
+			yyerror
+			    ("no inherits name for access vector definition?");
+			return -1;
+		}
+		comdatum =
+		    (common_datum_t *) hashtab_search(policydbp->p_commons.
+						      table,
+						      (hashtab_key_t) id);
+
+		if (!comdatum) {
+			yyerror2("common %s is not defined", id);
+			goto bad;
+		}
+		cladatum->comkey = id;
+		cladatum->comdatum = comdatum;
+
+		/*
+		 * Class-specific permissions start with values 
+		 * after the last common permission.
+		 */
+		cladatum->permissions.nprim += comdatum->permissions.nprim;
+	}
+	while ((id = queue_remove(id_queue))) {
+		perdatum = (perm_datum_t *) malloc(sizeof(perm_datum_t));
+		if (!perdatum) {
+			yyerror("out of memory");
+			goto bad;
+		}
+		memset(perdatum, 0, sizeof(perm_datum_t));
+		perdatum->s.value = ++cladatum->permissions.nprim;
+
+		if (perdatum->s.value > (sizeof(sepol_access_vector_t) * 8)) {
+			yyerror
+			    ("too many permissions to fit in an access vector");
+			goto bad;
+		}
+		if (inherits) {
+			/*
+			 * Class-specific permissions and 
+			 * common permissions exist in the same
+			 * name space.
+			 */
+			perdatum2 =
+			    (perm_datum_t *) hashtab_search(cladatum->comdatum->
+							    permissions.table,
+							    (hashtab_key_t) id);
+			if (perdatum2) {
+				yyerror2("permission %s conflicts with an "
+					 "inherited permission", id);
+				goto bad;
+			}
+		}
+		ret = hashtab_insert(cladatum->permissions.table,
+				     (hashtab_key_t) id,
+				     (hashtab_datum_t) perdatum);
+
+		if (ret == SEPOL_EEXIST) {
+			yyerror2("duplicate permission %s", id);
+			goto bad;
+		}
+		if (ret == SEPOL_ENOMEM) {
+			yyerror("hash table overflow");
+			goto bad;
+		}
+		if (add_perm_to_class(perdatum->s.value, cladatum->s.value)) {
+			yyerror("out of memory");
+			goto bad;
+		}
+	}
+
+	return 0;
+
+      bad:
+	if (id)
+		free(id);
+	if (perdatum)
+		free(perdatum);
+	return -1;
+}
+
+int define_sens(void)
+{
+	char *id;
+	mls_level_t *level = 0;
+	level_datum_t *datum = 0, *aliasdatum = 0;
+	int ret;
+	uint32_t value;		/* dummy variable -- its value is never used */
+
+	if (!mlspol) {
+		yyerror("sensitivity definition in non-MLS configuration");
+		return -1;
+	}
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no sensitivity name for sensitivity definition?");
+		return -1;
+	}
+	if (id_has_dot(id)) {
+		yyerror("sensitivity identifiers may not contain periods");
+		goto bad;
+	}
+	level = (mls_level_t *) malloc(sizeof(mls_level_t));
+	if (!level) {
+		yyerror("out of memory");
+		goto bad;
+	}
+	mls_level_init(level);
+	level->sens = 0;	/* actual value set in define_dominance */
+	ebitmap_init(&level->cat);	/* actual value set in define_level */
+
+	datum = (level_datum_t *) malloc(sizeof(level_datum_t));
+	if (!datum) {
+		yyerror("out of memory");
+		goto bad;
+	}
+	level_datum_init(datum);
+	datum->isalias = FALSE;
+	datum->level = level;
+
+	ret = declare_symbol(SYM_LEVELS, id, datum, &value, &value);
+	switch (ret) {
+	case -3:{
+			yyerror("Out of memory!");
+			goto bad;
+		}
+	case -2:{
+			yyerror("duplicate declaration of sensitivity level");
+			goto bad;
+		}
+	case -1:{
+			yyerror("could not declare sensitivity level here");
+			goto bad;
+		}
+	case 0:
+	case 1:{
+			break;
+		}
+	default:{
+			assert(0);	/* should never get here */
+		}
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (id_has_dot(id)) {
+			yyerror("sensitivity aliases may not contain periods");
+			goto bad_alias;
+		}
+		aliasdatum = (level_datum_t *) malloc(sizeof(level_datum_t));
+		if (!aliasdatum) {
+			yyerror("out of memory");
+			goto bad_alias;
+		}
+		level_datum_init(aliasdatum);
+		aliasdatum->isalias = TRUE;
+		aliasdatum->level = level;
+
+		ret = declare_symbol(SYM_LEVELS, id, aliasdatum, NULL, &value);
+		switch (ret) {
+		case -3:{
+				yyerror("Out of memory!");
+				goto bad_alias;
+			}
+		case -2:{
+				yyerror
+				    ("duplicate declaration of sensitivity alias");
+				goto bad_alias;
+			}
+		case -1:{
+				yyerror
+				    ("could not declare sensitivity alias here");
+				goto bad_alias;
+			}
+		case 0:
+		case 1:{
+				break;
+			}
+		default:{
+				assert(0);	/* should never get here */
+			}
+		}
+	}
+
+	return 0;
+
+      bad:
+	if (id)
+		free(id);
+	if (level)
+		free(level);
+	if (datum) {
+		level_datum_destroy(datum);
+		free(datum);
+	}
+	return -1;
+
+      bad_alias:
+	if (id)
+		free(id);
+	if (aliasdatum) {
+		level_datum_destroy(aliasdatum);
+		free(aliasdatum);
+	}
+	return -1;
+}
+
+int define_dominance(void)
+{
+	level_datum_t *datum;
+	uint32_t order;
+	char *id;
+
+	if (!mlspol) {
+		yyerror("dominance definition in non-MLS configuration");
+		return -1;
+	}
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	order = 0;
+	while ((id = (char *)queue_remove(id_queue))) {
+		datum =
+		    (level_datum_t *) hashtab_search(policydbp->p_levels.table,
+						     (hashtab_key_t) id);
+		if (!datum) {
+			yyerror2("unknown sensitivity %s used in dominance "
+				 "definition", id);
+			free(id);
+			return -1;
+		}
+		if (datum->level->sens != 0) {
+			yyerror2("sensitivity %s occurs multiply in dominance "
+				 "definition", id);
+			free(id);
+			return -1;
+		}
+		datum->level->sens = ++order;
+
+		/* no need to keep sensitivity name */
+		free(id);
+	}
+
+	if (order != policydbp->p_levels.nprim) {
+		yyerror
+		    ("all sensitivities must be specified in dominance definition");
+		return -1;
+	}
+	return 0;
+}
+
+int define_category(void)
+{
+	char *id;
+	cat_datum_t *datum = 0, *aliasdatum = 0;
+	int ret;
+	uint32_t value;
+
+	if (!mlspol) {
+		yyerror("category definition in non-MLS configuration");
+		return -1;
+	}
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no category name for category definition?");
+		return -1;
+	}
+	if (id_has_dot(id)) {
+		yyerror("category identifiers may not contain periods");
+		goto bad;
+	}
+	datum = (cat_datum_t *) malloc(sizeof(cat_datum_t));
+	if (!datum) {
+		yyerror("out of memory");
+		goto bad;
+	}
+	cat_datum_init(datum);
+	datum->isalias = FALSE;
+
+	ret = declare_symbol(SYM_CATS, id, datum, &value, &value);
+	switch (ret) {
+	case -3:{
+			yyerror("Out of memory!");
+			goto bad;
+		}
+	case -2:{
+			yyerror("duplicate declaration of category");
+			goto bad;
+		}
+	case -1:{
+			yyerror("could not declare category here");
+			goto bad;
+		}
+	case 0:
+	case 1:{
+			break;
+		}
+	default:{
+			assert(0);	/* should never get here */
+		}
+	}
+	datum->s.value = value;
+
+	while ((id = queue_remove(id_queue))) {
+		if (id_has_dot(id)) {
+			yyerror("category aliases may not contain periods");
+			goto bad_alias;
+		}
+		aliasdatum = (cat_datum_t *) malloc(sizeof(cat_datum_t));
+		if (!aliasdatum) {
+			yyerror("out of memory");
+			goto bad_alias;
+		}
+		cat_datum_init(aliasdatum);
+		aliasdatum->isalias = TRUE;
+		aliasdatum->s.value = datum->s.value;
+
+		ret =
+		    declare_symbol(SYM_CATS, id, aliasdatum, NULL,
+				   &datum->s.value);
+		switch (ret) {
+		case -3:{
+				yyerror("Out of memory!");
+				goto bad_alias;
+			}
+		case -2:{
+				yyerror
+				    ("duplicate declaration of category aliases");
+				goto bad_alias;
+			}
+		case -1:{
+				yyerror
+				    ("could not declare category aliases here");
+				goto bad_alias;
+			}
+		case 0:
+		case 1:{
+				break;
+			}
+		default:{
+				assert(0);	/* should never get here */
+			}
+		}
+	}
+
+	return 0;
+
+      bad:
+	if (id)
+		free(id);
+	if (datum) {
+		cat_datum_destroy(datum);
+		free(datum);
+	}
+	return -1;
+
+      bad_alias:
+	if (id)
+		free(id);
+	if (aliasdatum) {
+		cat_datum_destroy(aliasdatum);
+		free(aliasdatum);
+	}
+	return -1;
+}
+
+static int clone_level(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *arg)
+{
+	level_datum_t *levdatum = (level_datum_t *) datum;
+	mls_level_t *level = (mls_level_t *) arg, *newlevel;
+
+	if (levdatum->level == level) {
+		levdatum->defined = 1;
+		if (!levdatum->isalias)
+			return 0;
+		newlevel = (mls_level_t *) malloc(sizeof(mls_level_t));
+		if (!newlevel)
+			return -1;
+		if (mls_level_cpy(newlevel, level)) {
+			free(newlevel);
+			return -1;
+		}
+		levdatum->level = newlevel;
+	}
+	return 0;
+}
+
+int define_level(void)
+{
+	char *id;
+	level_datum_t *levdatum;
+
+	if (!mlspol) {
+		yyerror("level definition in non-MLS configuration");
+		return -1;
+	}
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no level name for level definition?");
+		return -1;
+	}
+	levdatum = (level_datum_t *) hashtab_search(policydbp->p_levels.table,
+						    (hashtab_key_t) id);
+	if (!levdatum) {
+		yyerror2("unknown sensitivity %s used in level definition", id);
+		free(id);
+		return -1;
+	}
+	if (ebitmap_length(&levdatum->level->cat)) {
+		yyerror2("sensitivity %s used in multiple level definitions",
+			 id);
+		free(id);
+		return -1;
+	}
+	free(id);
+
+	levdatum->defined = 1;
+
+	while ((id = queue_remove(id_queue))) {
+		cat_datum_t *cdatum;
+		int range_start, range_end, i;
+
+		if (id_has_dot(id)) {
+			char *id_start = id;
+			char *id_end = strchr(id, '.');
+
+			*(id_end++) = '\0';
+
+			cdatum =
+			    (cat_datum_t *) hashtab_search(policydbp->p_cats.
+							   table,
+							   (hashtab_key_t)
+							   id_start);
+			if (!cdatum) {
+				yyerror2("unknown category %s", id_start);
+				free(id);
+				return -1;
+			}
+			range_start = cdatum->s.value - 1;
+			cdatum =
+			    (cat_datum_t *) hashtab_search(policydbp->p_cats.
+							   table,
+							   (hashtab_key_t)
+							   id_end);
+			if (!cdatum) {
+				yyerror2("unknown category %s", id_end);
+				free(id);
+				return -1;
+			}
+			range_end = cdatum->s.value - 1;
+
+			if (range_end < range_start) {
+				yyerror2("category range is invalid");
+				free(id);
+				return -1;
+			}
+		} else {
+			cdatum =
+			    (cat_datum_t *) hashtab_search(policydbp->p_cats.
+							   table,
+							   (hashtab_key_t) id);
+			range_start = range_end = cdatum->s.value - 1;
+		}
+
+		for (i = range_start; i <= range_end; i++) {
+			if (ebitmap_set_bit(&levdatum->level->cat, i, TRUE)) {
+				yyerror("out of memory");
+				free(id);
+				return -1;
+			}
+		}
+
+		free(id);
+	}
+
+	if (hashtab_map
+	    (policydbp->p_levels.table, clone_level, levdatum->level)) {
+		yyerror("out of memory");
+		return -1;
+	}
+
+	return 0;
+}
+
+int define_attrib(void)
+{
+	if (pass == 2) {
+		free(queue_remove(id_queue));
+		return 0;
+	}
+
+	if (declare_type(TRUE, TRUE) == NULL) {
+		return -1;
+	}
+	return 0;
+}
+
+static int add_aliases_to_type(type_datum_t * type)
+{
+	char *id;
+	type_datum_t *aliasdatum = NULL;
+	int ret;
+	while ((id = queue_remove(id_queue))) {
+		if (id_has_dot(id)) {
+			free(id);
+			yyerror
+			    ("type alias identifiers may not contain periods");
+			return -1;
+		}
+		aliasdatum = (type_datum_t *) malloc(sizeof(type_datum_t));
+		if (!aliasdatum) {
+			free(id);
+			yyerror("Out of memory!");
+			return -1;
+		}
+		memset(aliasdatum, 0, sizeof(type_datum_t));
+		aliasdatum->s.value = type->s.value;
+
+		ret = declare_symbol(SYM_TYPES, id, aliasdatum,
+				     NULL, &aliasdatum->s.value);
+		switch (ret) {
+		case -3:{
+				yyerror("Out of memory!");
+				goto cleanup;
+			}
+		case -2:{
+				yyerror2("duplicate declaration of alias %s",
+					 id);
+				goto cleanup;
+			}
+		case -1:{
+				yyerror("could not declare alias here");
+				goto cleanup;
+			}
+		case 0:	 	break;
+		case 1:{
+				/* ret == 1 means the alias was required and therefore already
+				 * has a value. Set it up as an alias with a different primary. */
+				type_datum_destroy(aliasdatum);
+				free(aliasdatum);
+
+				aliasdatum = hashtab_search(policydbp->symtab[SYM_TYPES].table, id);
+				assert(aliasdatum);
+
+				aliasdatum->primary = type->s.value;
+				aliasdatum->flavor = TYPE_ALIAS;
+
+				break;
+			}
+		default:{
+				assert(0);	/* should never get here */
+			}
+		}
+	}
+	return 0;
+      cleanup:
+	free(id);
+	type_datum_destroy(aliasdatum);
+	free(aliasdatum);
+	return -1;
+}
+
+int define_typealias(void)
+{
+	char *id;
+	type_datum_t *t;
+
+	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;
+	}
+
+	if (!is_id_in_scope(SYM_TYPES, id)) {
+		yyerror2("type %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	t = hashtab_search(policydbp->p_types.table, id);
+	if (!t || t->flavor == TYPE_ATTRIB) {
+		yyerror2("unknown type %s, or it was already declared as an "
+			 "attribute", id);
+		free(id);
+		return -1;
+	}
+	return add_aliases_to_type(t);
+}
+
+int define_typeattribute(void)
+{
+	char *id;
+	type_datum_t *t, *attr;
+
+	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 typeattribute definition?");
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_TYPES, id)) {
+		yyerror2("type %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	t = hashtab_search(policydbp->p_types.table, id);
+	if (!t || t->flavor == TYPE_ATTRIB) {
+		yyerror2("unknown type %s", id);
+		free(id);
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_TYPES, id)) {
+			yyerror2("attribute %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		attr = hashtab_search(policydbp->p_types.table, id);
+		if (!attr) {
+			/* treat it as a fatal error */
+			yyerror2("attribute %s is not declared", id);
+			free(id);
+			return -1;
+		}
+
+		if (attr->flavor != TYPE_ATTRIB) {
+			yyerror2("%s is a type, not an attribute", id);
+			free(id);
+			return -1;
+		}
+
+		if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) {
+			yyerror("Out of memory!");
+			return -1;
+		}
+
+		if (ebitmap_set_bit(&attr->types, (t->s.value - 1), TRUE)) {
+			yyerror("out of memory");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int define_typebounds_helper(char *bounds_id, char *type_id)
+{
+	type_datum_t *bounds, *type;
+
+	if (!is_id_in_scope(SYM_TYPES, bounds_id)) {
+		yyerror2("type %s is not within scope", bounds_id);
+		return -1;
+	}
+
+	bounds = hashtab_search(policydbp->p_types.table, bounds_id);
+	if (!bounds || bounds->flavor == TYPE_ATTRIB) {
+		yyerror2("hoge unknown type %s", bounds_id);
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_TYPES, type_id)) {
+		yyerror2("type %s is not within scope", type_id);
+		return -1;
+	}
+
+	type = hashtab_search(policydbp->p_types.table, type_id);
+	if (!type || type->flavor == TYPE_ATTRIB) {
+		yyerror2("type %s is not declared", type_id);
+		return -1;
+	}
+
+	if (type->flavor == TYPE_TYPE && !type->primary) {
+		type = policydbp->type_val_to_struct[type->s.value - 1];
+	} else if (type->flavor == TYPE_ALIAS) {
+		type = policydbp->type_val_to_struct[type->primary - 1];
+	}
+
+	if (!type->bounds)
+		type->bounds = bounds->s.value;
+	else if (type->bounds != bounds->s.value) {
+		yyerror2("type %s has inconsistent master {%s,%s}",
+			 type_id,
+			 policydbp->p_type_val_to_name[type->bounds - 1],
+			 policydbp->p_type_val_to_name[bounds->s.value - 1]);
+		return -1;
+	}
+
+	return 0;
+}
+
+int define_typebounds(void)
+{
+	char *bounds, *id;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	bounds = (char *) queue_remove(id_queue);
+	if (!bounds) {
+		yyerror("no type name for typebounds definition?");
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (define_typebounds_helper(bounds, id))
+			return -1;
+		free(id);
+	}
+	free(bounds);
+
+	return 0;
+}
+
+int define_type(int alias)
+{
+	char *id;
+	type_datum_t *datum, *attr;
+
+	if (pass == 2) {
+		/*
+		 * If type name contains ".", we have to define boundary
+		 * relationship implicitly to keep compatibility with
+		 * old name based hierarchy.
+		 */
+		if ((id = queue_remove(id_queue))) {
+			char *bounds, *delim;
+
+			if ((delim = strrchr(id, '.'))
+			    && (bounds = strdup(id))) {
+				bounds[(size_t)(delim - id)] = '\0';
+
+				if (define_typebounds_helper(bounds, id))
+					return -1;
+				free(bounds);
+			}
+			free(id);
+		}
+
+		if (alias) {
+			while ((id = queue_remove(id_queue)))
+				free(id);
+		}
+
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	if ((datum = declare_type(TRUE, FALSE)) == NULL) {
+		return -1;
+	}
+
+	if (alias) {
+		if (add_aliases_to_type(datum) == -1) {
+			return -1;
+		}
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_TYPES, id)) {
+			yyerror2("attribute %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		attr = hashtab_search(policydbp->p_types.table, id);
+		if (!attr) {
+			/* treat it as a fatal error */
+			yyerror2("attribute %s is not declared", id);
+			return -1;
+		}
+
+		if (attr->flavor != TYPE_ATTRIB) {
+			yyerror2("%s is a type, not an attribute", id);
+			return -1;
+		}
+
+		if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) {
+			yyerror("Out of memory!");
+			return -1;
+		}
+
+		if (ebitmap_set_bit(&attr->types, datum->s.value - 1, TRUE)) {
+			yyerror("Out of memory");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+struct val_to_name {
+	unsigned int val;
+	char *name;
+};
+
+/* Adds a type, given by its textual name, to a typeset.  If *add is
+   0, then add the type to the negative set; otherwise if *add is 1
+   then add it to the positive side. */
+static int set_types(type_set_t * set, char *id, int *add, char starallowed)
+{
+	type_datum_t *t;
+
+	if (strcmp(id, "*") == 0) {
+		if (!starallowed) {
+			yyerror("* not allowed in this type of rule");
+			return -1;
+		}
+		/* set TYPE_STAR flag */
+		set->flags = TYPE_STAR;
+		free(id);
+		*add = 1;
+		return 0;
+	}
+
+	if (strcmp(id, "~") == 0) {
+		if (!starallowed) {
+			yyerror("~ not allowed in this type of rule");
+			return -1;
+		}
+		/* complement the set */
+		set->flags = TYPE_COMP;
+		free(id);
+		*add = 1;
+		return 0;
+	}
+
+	if (strcmp(id, "-") == 0) {
+		*add = 0;
+		free(id);
+		return 0;
+	}
+
+	if (!is_id_in_scope(SYM_TYPES, id)) {
+		yyerror2("type %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	t = hashtab_search(policydbp->p_types.table, id);
+	if (!t) {
+		yyerror2("unknown type %s", id);
+		free(id);
+		return -1;
+	}
+
+	if (*add == 0) {
+		if (ebitmap_set_bit(&set->negset, t->s.value - 1, TRUE))
+			goto oom;
+	} else {
+		if (ebitmap_set_bit(&set->types, t->s.value - 1, TRUE))
+			goto oom;
+	}
+	free(id);
+	*add = 1;
+	return 0;
+      oom:
+	yyerror("Out of memory");
+	free(id);
+	return -1;
+}
+
+int define_compute_type_helper(int which, avrule_t ** rule)
+{
+	char *id;
+	type_datum_t *datum;
+	ebitmap_t tclasses;
+	ebitmap_node_t *node;
+	avrule_t *avrule;
+	class_perm_node_t *perm;
+	uint32_t i;
+	int add = 1;
+
+	avrule = malloc(sizeof(avrule_t));
+	if (!avrule) {
+		yyerror("out of memory");
+		return -1;
+	}
+	avrule_init(avrule);
+	avrule->specified = which;
+	avrule->line = policydb_lineno;
+	avrule->source_line = source_lineno;
+	avrule->source_filename = strdup(source_file);
+	if (!avrule->source_filename) {
+		yyerror("out of memory");
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (set_types(&avrule->stypes, id, &add, 0))
+			goto bad;
+	}
+	add = 1;
+	while ((id = queue_remove(id_queue))) {
+		if (set_types(&avrule->ttypes, id, &add, 0))
+			goto bad;
+	}
+
+	ebitmap_init(&tclasses);
+	if (read_classes(&tclasses))
+		goto bad;
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no newtype?");
+		goto bad;
+	}
+	if (!is_id_in_scope(SYM_TYPES, id)) {
+		yyerror2("type %s is not within scope", id);
+		free(id);
+		goto bad;
+	}
+	datum = (type_datum_t *) hashtab_search(policydbp->p_types.table,
+						(hashtab_key_t) id);
+	if (!datum || datum->flavor == TYPE_ATTRIB) {
+		yyerror2("unknown type %s", id);
+		goto bad;
+	}
+
+	ebitmap_for_each_bit(&tclasses, node, i) {
+		if (ebitmap_node_get_bit(node, i)) {
+			perm = malloc(sizeof(class_perm_node_t));
+			if (!perm) {
+				yyerror("out of memory");
+				goto bad;
+			}
+			class_perm_node_init(perm);
+			perm->tclass = i + 1;
+			perm->data = datum->s.value;
+			perm->next = avrule->perms;
+			avrule->perms = perm;
+		}
+	}
+	ebitmap_destroy(&tclasses);
+
+	*rule = avrule;
+	return 0;
+
+      bad:
+	avrule_destroy(avrule);
+	free(avrule);
+	return -1;
+}
+
+int define_compute_type(int which)
+{
+	char *id;
+	avrule_t *avrule;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		id = queue_remove(id_queue);
+		free(id);
+		return 0;
+	}
+
+	if (define_compute_type_helper(which, &avrule))
+		return -1;
+
+	append_avrule(avrule);
+	return 0;
+}
+
+avrule_t *define_cond_compute_type(int which)
+{
+	char *id;
+	avrule_t *avrule;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		id = queue_remove(id_queue);
+		free(id);
+		return (avrule_t *) 1;
+	}
+
+	if (define_compute_type_helper(which, &avrule))
+		return COND_ERR;
+
+	return avrule;
+}
+
+int define_bool_tunable(int is_tunable)
+{
+	char *id, *bool_value;
+	cond_bool_datum_t *datum;
+	int ret;
+	uint32_t value;
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no identifier for bool definition?");
+		return -1;
+	}
+	if (id_has_dot(id)) {
+		free(id);
+		yyerror("boolean identifiers may not contain periods");
+		return -1;
+	}
+	datum = (cond_bool_datum_t *) malloc(sizeof(cond_bool_datum_t));
+	if (!datum) {
+		yyerror("out of memory");
+		free(id);
+		return -1;
+	}
+	memset(datum, 0, sizeof(cond_bool_datum_t));
+	if (is_tunable)
+		datum->flags |= COND_BOOL_FLAGS_TUNABLE;
+	ret = declare_symbol(SYM_BOOLS, id, datum, &value, &value);
+	switch (ret) {
+	case -3:{
+			yyerror("Out of memory!");
+			goto cleanup;
+		}
+	case -2:{
+			yyerror2("duplicate declaration of boolean %s", id);
+			goto cleanup;
+		}
+	case -1:{
+			yyerror("could not declare boolean here");
+			goto cleanup;
+		}
+	case 0:
+	case 1:{
+			break;
+		}
+	default:{
+			assert(0);	/* should never get here */
+		}
+	}
+	datum->s.value = value;
+
+	bool_value = (char *)queue_remove(id_queue);
+	if (!bool_value) {
+		yyerror("no default value for bool definition?");
+		free(id);
+		return -1;
+	}
+
+	datum->state = (int)(bool_value[0] == 'T') ? 1 : 0;
+	return 0;
+      cleanup:
+	cond_destroy_bool(id, datum, NULL);
+	return -1;
+}
+
+avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl)
+{
+	if (pass == 1) {
+		/* return something so we get through pass 1 */
+		return (avrule_t *) 1;
+	}
+
+	if (sl == NULL) {
+		/* This is a require block, return previous list */
+		return avlist;
+	}
+
+	/* prepend the new avlist to the pre-existing one */
+	sl->next = avlist;
+	return sl;
+}
+
+typedef struct av_ioctl_range {
+	uint16_t low;
+	uint16_t high;
+} av_ioctl_range_t;
+
+struct av_ioctl_range_list {
+	uint8_t omit;
+	av_ioctl_range_t range;
+	struct av_ioctl_range_list *next;
+};
+
+int avrule_sort_ioctls(struct av_ioctl_range_list **rangehead)
+{
+	struct av_ioctl_range_list *r, *r2, *sorted, *sortedhead = NULL;
+
+	/* order list by range.low */
+	for (r = *rangehead; r != NULL; r = r->next) {
+		sorted = malloc(sizeof(struct av_ioctl_range_list));
+		if (sorted == NULL)
+			goto error;
+		memcpy(sorted, r, sizeof(struct av_ioctl_range_list));
+		sorted->next = NULL;
+		if (sortedhead == NULL) {
+			sortedhead = sorted;
+			continue;
+		}
+	        for (r2 = sortedhead; r2 != NULL; r2 = r2->next) {
+			if (sorted->range.low < r2->range.low) {
+				/* range is the new head */
+				sorted->next = r2;
+				sortedhead = sorted;
+				break;
+			} else if ((r2 ->next != NULL) &&
+					(r->range.low < r2->next->range.low)) {
+				/* insert range between elements */
+				sorted->next = r2->next;
+				r2->next = sorted;
+				break;
+			} else if (r2->next == NULL) {
+				/* range is the new tail*/
+				r2->next = sorted;
+				break;
+			}
+		}
+	}
+
+	r = *rangehead;
+	while (r != NULL) {
+		r2 = r;
+		r = r->next;
+		free(r2);
+	}
+	*rangehead = sortedhead;
+	return 0;
+error:
+	yyerror("out of memory");
+	return -1;
+}
+
+int avrule_merge_ioctls(struct av_ioctl_range_list **rangehead)
+{
+	struct av_ioctl_range_list *r, *tmp;
+	r = *rangehead;
+	while (r != NULL && r->next != NULL) {
+		/* merge */
+		if ((r->range.high + 1) >= r->next->range.low) {
+			/* keep the higher of the two */
+			if (r->range.high < r->next->range.high)
+				r->range.high = r->next->range.high;
+			tmp = r->next;
+			r->next = r->next->next;
+			free(tmp);
+			continue;
+		}
+		r = r->next;
+	}
+	return 0;
+}
+
+int avrule_read_ioctls(struct av_ioctl_range_list **rangehead)
+{
+	char *id;
+	struct av_ioctl_range_list *rnew, *r = NULL;
+	*rangehead = NULL;
+	uint8_t omit = 0;
+
+	/* read in all the ioctl commands */
+	while ((id = queue_remove(id_queue))) {
+		if (strcmp(id,"~") == 0) {
+			/* these are values to be omitted */
+			free(id);
+			omit = 1;
+		} else if (strcmp(id,"-") == 0) {
+			/* high value of range */
+			free(id);
+			id = queue_remove(id_queue);
+			r->range.high = (uint16_t) strtoul(id,NULL,0);
+			if (r->range.high < r->range.low) {
+				yyerror("Ioctl ranges must be in ascending order.");
+				return -1;
+			}
+			free(id);
+		} else {
+			/* read in new low value */
+			rnew = malloc(sizeof(struct av_ioctl_range_list));
+			if (rnew == NULL)
+				goto error;
+			rnew->next = NULL;
+			if (*rangehead == NULL) {
+				*rangehead = rnew;
+				r = *rangehead;
+			} else {
+				r->next = rnew;
+				r = r->next;
+			}
+			rnew->range.low = (uint16_t) strtoul(id,NULL,0);
+			rnew->range.high = rnew->range.low;
+			free(id);
+		}
+	}
+	r = *rangehead;
+	r->omit = omit;
+	return 0;
+error:
+	yyerror("out of memory");
+	return -1;
+}
+
+/* flip to included ranges */
+int avrule_omit_ioctls(struct av_ioctl_range_list **rangehead)
+{
+	struct av_ioctl_range_list *rnew, *r, *newhead, *r2;
+
+	rnew = calloc(1, sizeof(struct av_ioctl_range_list));
+	if (!rnew)
+		goto error;
+
+	newhead = rnew;
+
+	r = *rangehead;
+	r2 = newhead;
+
+	if (r->range.low == 0) {
+		r2->range.low = r->range.high + 1;
+		r = r->next;
+	} else {
+		r2->range.low = 0;
+	}
+
+	while (r) {
+		r2->range.high = r->range.low - 1;
+		rnew = calloc(1, sizeof(struct av_ioctl_range_list));
+		if (!rnew)
+			goto error;
+		r2->next = rnew;
+		r2 = r2->next;
+
+		r2->range.low = r->range.high + 1;
+		if (!r->next)
+			r2->range.high = 0xffff;
+		r = r->next;
+	}
+
+	r = *rangehead;
+	while (r != NULL) {
+		r2 = r;
+		r = r->next;
+		free(r2);
+	}
+	*rangehead = newhead;
+	return 0;
+
+error:
+	yyerror("out of memory");
+	return -1;
+}
+
+int avrule_ioctl_ranges(struct av_ioctl_range_list **rangelist)
+{
+	struct av_ioctl_range_list *rangehead;
+	uint8_t omit;
+
+	/* read in ranges to include and omit */
+	if (avrule_read_ioctls(&rangehead))
+		return -1;
+	omit = rangehead->omit;
+	if (rangehead == NULL) {
+		yyerror("error processing ioctl commands");
+		return -1;
+	}
+	/* sort and merge the input ioctls */
+	if (avrule_sort_ioctls(&rangehead))
+		return -1;
+	if (avrule_merge_ioctls(&rangehead))
+		return -1;
+	/* flip ranges if these are ommited*/
+	if (omit) {
+		if (avrule_omit_ioctls(&rangehead))
+			return -1;
+	}
+
+	*rangelist = rangehead;
+	return 0;
+}
+
+int define_te_avtab_xperms_helper(int which, avrule_t ** rule)
+{
+	char *id;
+	class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL;
+	class_datum_t *cladatum;
+	perm_datum_t *perdatum = NULL;
+	ebitmap_t tclasses;
+	ebitmap_node_t *node;
+	avrule_t *avrule;
+	unsigned int i;
+	int add = 1, ret = 0;
+
+	avrule = (avrule_t *) malloc(sizeof(avrule_t));
+	if (!avrule) {
+		yyerror("out of memory");
+		ret = -1;
+		goto out;
+	}
+	avrule_init(avrule);
+	avrule->specified = which;
+	avrule->line = policydb_lineno;
+	avrule->source_line = source_lineno;
+	avrule->source_filename = strdup(source_file);
+	avrule->xperms = NULL;
+	if (!avrule->source_filename) {
+		yyerror("out of memory");
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (set_types
+		    (&avrule->stypes, id, &add,
+		     which == AVRULE_XPERMS_NEVERALLOW ? 1 : 0)) {
+			ret = -1;
+			goto out;
+		}
+	}
+	add = 1;
+	while ((id = queue_remove(id_queue))) {
+		if (strcmp(id, "self") == 0) {
+			free(id);
+			avrule->flags |= RULE_SELF;
+			continue;
+		}
+		if (set_types
+		    (&avrule->ttypes, id, &add,
+		     which == AVRULE_XPERMS_NEVERALLOW ? 1 : 0)) {
+			ret = -1;
+			goto out;
+		}
+	}
+
+	ebitmap_init(&tclasses);
+	ret = read_classes(&tclasses);
+	if (ret)
+		goto out;
+
+	perms = NULL;
+	id = queue_head(id_queue);
+	ebitmap_for_each_bit(&tclasses, node, i) {
+		if (!ebitmap_node_get_bit(node, i))
+			continue;
+		cur_perms =
+		    (class_perm_node_t *) malloc(sizeof(class_perm_node_t));
+		if (!cur_perms) {
+			yyerror("out of memory");
+			ret = -1;
+			goto out;
+		}
+		class_perm_node_init(cur_perms);
+		cur_perms->tclass = i + 1;
+		if (!perms)
+			perms = cur_perms;
+		if (tail)
+			tail->next = cur_perms;
+		tail = cur_perms;
+
+		cladatum = policydbp->class_val_to_struct[i];
+		perdatum = hashtab_search(cladatum->permissions.table, id);
+		if (!perdatum) {
+			if (cladatum->comdatum) {
+				perdatum = hashtab_search(cladatum->comdatum->
+							permissions.table,
+							id);
+			}
+		}
+		if (!perdatum) {
+			yyerror2("permission %s is not defined"
+				     " for class %s", id,
+				     policydbp->p_class_val_to_name[i]);
+			continue;
+		} else if (!is_perm_in_scope (id, policydbp->p_class_val_to_name[i])) {
+			yyerror2("permission %s of class %s is"
+			     " not within scope", id,
+			     policydbp->p_class_val_to_name[i]);
+			continue;
+		} else {
+			cur_perms->data |= 1U << (perdatum->s.value - 1);
+		}
+	}
+
+	ebitmap_destroy(&tclasses);
+
+	avrule->perms = perms;
+	*rule = avrule;
+
+out:
+	return ret;
+}
+
+/* index of the u32 containing the permission */
+#define XPERM_IDX(x) (x >> 5)
+/* set bits 0 through x-1 within the u32 */
+#define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1)
+/* low value for this u32 */
+#define XPERM_LOW(x) (x << 5)
+/* high value for this u32 */
+#define XPERM_HIGH(x) (((x + 1) << 5) - 1)
+void avrule_xperm_setrangebits(uint16_t low, uint16_t high,
+				av_extended_perms_t *xperms)
+{
+	unsigned int i;
+	uint16_t h = high + 1;
+	/* for each u32 that this low-high range touches, set driver permissions */
+	for (i = XPERM_IDX(low); i <= XPERM_IDX(high); i++) {
+		/* set all bits in u32 */
+		if ((low <= XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
+			xperms->perms[i] |= ~0U;
+		/* set low bits */
+		else if ((low <= XPERM_LOW(i)) && (high < XPERM_HIGH(i)))
+			xperms->perms[i] |= XPERM_SETBITS(h);
+		/* set high bits */
+		else if ((low > XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
+			xperms->perms[i] |= ~0U - XPERM_SETBITS(low);
+		/* set middle bits */
+		else if ((low > XPERM_LOW(i)) && (high <= XPERM_HIGH(i)))
+			xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low);
+	}
+}
+
+int avrule_xperms_used(av_extended_perms_t *xperms)
+{
+	unsigned int i;
+
+	for (i = 0; i < sizeof(xperms->perms)/sizeof(xperms->perms[0]); i++) {
+		if (xperms->perms[i])
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * using definitions found in kernel document ioctl-number.txt
+ * The kernel components of an ioctl command are:
+ * dir, size, driver, and fucntion. Only the driver and function fields
+ * are considered here
+ */
+#define IOC_DRIV(x) (x >> 8)
+#define IOC_FUNC(x) (x & 0xff)
+#define IOC_CMD(driver, func) ((driver << 8) + func)
+int avrule_ioctl_partialdriver(struct av_ioctl_range_list *rangelist,
+				av_extended_perms_t *complete_driver,
+				av_extended_perms_t **extended_perms)
+{
+	struct av_ioctl_range_list *r;
+	av_extended_perms_t *xperms;
+	uint8_t low, high;
+
+	xperms = calloc(1, sizeof(av_extended_perms_t));
+	if (!xperms) {
+		yyerror("out of memory");
+		return - 1;
+	}
+
+	r = rangelist;
+	while(r) {
+		low = IOC_DRIV(r->range.low);
+		high = IOC_DRIV(r->range.high);
+		if (complete_driver) {
+			if (!xperm_test(low, complete_driver->perms))
+				xperm_set(low, xperms->perms);
+			if (!xperm_test(high, complete_driver->perms))
+				xperm_set(high, xperms->perms);
+		} else {
+			xperm_set(low, xperms->perms);
+			xperm_set(high, xperms->perms);
+		}
+		r = r->next;
+	}
+	if (avrule_xperms_used(xperms)) {
+		*extended_perms = xperms;
+	} else {
+		free(xperms);
+		*extended_perms = NULL;
+	}
+	return 0;
+
+}
+
+int avrule_ioctl_completedriver(struct av_ioctl_range_list *rangelist,
+			av_extended_perms_t **extended_perms)
+{
+	struct av_ioctl_range_list *r;
+	av_extended_perms_t *xperms;
+	uint16_t low, high;
+	xperms = calloc(1, sizeof(av_extended_perms_t));
+	if (!xperms) {
+		yyerror("out of memory");
+		return - 1;
+	}
+
+	r = rangelist;
+	while(r) {
+		/*
+		 * Any driver code that has sequence 0x00 - 0xff is a complete code,
+		 *
+		 * if command number = 0xff, then round high up to next code,
+		 * else 0x00 - 0xfe keep current code
+		 * of this range. temporarily u32 for the + 1
+		 * to account for possible rollover before right shift
+		 */
+		high = IOC_DRIV((uint32_t) (r->range.high + 1));
+		/* if 0x00 keep current driver code else 0x01 - 0xff round up to next code*/
+		low = IOC_DRIV(r->range.low);
+		if (IOC_FUNC(r->range.low))
+			low++;
+		if (high > low)
+			avrule_xperm_setrangebits(low, high - 1, xperms);
+		r = r->next;
+	}
+	if (avrule_xperms_used(xperms)) {
+		xperms->driver = 0x00;
+		xperms->specified = AVRULE_XPERMS_IOCTLDRIVER;
+		*extended_perms = xperms;
+	} else {
+		free(xperms);
+		*extended_perms = NULL;
+	}
+	return 0;
+}
+
+int avrule_ioctl_func(struct av_ioctl_range_list *rangelist,
+		av_extended_perms_t **extended_perms, unsigned int driver)
+{
+	struct av_ioctl_range_list *r;
+	av_extended_perms_t *xperms;
+	uint16_t low, high;
+
+	*extended_perms = NULL;
+	xperms = calloc(1, sizeof(av_extended_perms_t));
+	if (!xperms) {
+		yyerror("out of memory");
+		return - 1;
+	}
+
+	r = rangelist;
+	/* for the passed in driver code, find the ranges that apply */
+	while (r) {
+		low = r->range.low;
+		high = r->range.high;
+		if ((driver != IOC_DRIV(low)) && (driver != IOC_DRIV(high))) {
+			r = r->next;
+			continue;
+		}
+
+		if (driver == IOC_DRIV(low)) {
+			if (high > IOC_CMD(driver, 0xff))
+				high = IOC_CMD(driver, 0xff);
+
+		} else {
+			if (low < IOC_CMD(driver, 0))
+				low = IOC_CMD(driver, 0);
+		}
+
+		low = IOC_FUNC(low);
+		high = IOC_FUNC(high);
+		avrule_xperm_setrangebits(low, high, xperms);
+		xperms->driver = driver;
+		xperms->specified = AVRULE_XPERMS_IOCTLFUNCTION;
+		r = r->next;
+	}
+
+	if (avrule_xperms_used(xperms)) {
+		*extended_perms = xperms;
+	} else {
+		free(xperms);
+		*extended_perms = NULL;
+	}
+	return 0;
+}
+
+void avrule_ioctl_freeranges(struct av_ioctl_range_list *rangelist)
+{
+	struct av_ioctl_range_list *r, *tmp;
+	r = rangelist;
+	while (r) {
+		tmp = r;
+		r = r->next;
+		free(tmp);
+	}
+}
+
+unsigned int xperms_for_each_bit(unsigned int *bit, av_extended_perms_t *xperms)
+{
+	unsigned int i;
+	for (i = *bit; i < sizeof(xperms->perms)*8; i++) {
+		if (xperm_test(i,xperms->perms)) {
+			xperm_clear(i, xperms->perms);
+			*bit = i;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int avrule_cpy(avrule_t *dest, avrule_t *src)
+{
+	class_perm_node_t *src_perms;
+	class_perm_node_t *dest_perms, *dest_tail;
+	dest_tail = NULL;
+
+	avrule_init(dest);
+	dest->specified = src->specified;
+	dest->flags = src->flags;
+	if (type_set_cpy(&dest->stypes, &src->stypes)) {
+		yyerror("out of memory");
+		return - 1;
+	}
+	if (type_set_cpy(&dest->ttypes, &src->ttypes)) {
+		yyerror("out of memory");
+		return - 1;
+	}
+	dest->line = src->line;
+	dest->source_filename = strdup(source_file);
+	if (!dest->source_filename) {
+		yyerror("out of memory");
+		return -1;
+	}
+	dest->source_line = src->source_line;
+
+	/* increment through the class perms and copy over */
+	src_perms = src->perms;
+	while (src_perms) {
+		dest_perms = (class_perm_node_t *) calloc(1, sizeof(class_perm_node_t));
+		class_perm_node_init(dest_perms);
+		if (!dest_perms) {
+			yyerror("out of memory");
+			return -1;
+		}
+		if (!dest->perms)
+			dest->perms = dest_perms;
+		else
+			dest_tail->next = dest_perms;
+
+		dest_perms->tclass = src_perms->tclass;
+		dest_perms->data = src_perms->data;
+		dest_perms->next = NULL;
+		dest_tail = dest_perms;
+		src_perms = src_perms->next;
+	}
+	return 0;
+}
+
+int define_te_avtab_ioctl(avrule_t *avrule_template)
+{
+	avrule_t *avrule;
+	struct av_ioctl_range_list *rangelist;
+	av_extended_perms_t *complete_driver, *partial_driver, *xperms;
+	unsigned int i;
+
+
+	/* organize ioctl ranges */
+	if (avrule_ioctl_ranges(&rangelist))
+		return -1;
+
+	/* create rule for ioctl driver types that are entirely enabled */
+	if (avrule_ioctl_completedriver(rangelist, &complete_driver))
+		return -1;
+	if (complete_driver) {
+		avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
+		if (!avrule) {
+			yyerror("out of memory");
+			return -1;
+		}
+		if (avrule_cpy(avrule, avrule_template))
+			return -1;
+		avrule->xperms = complete_driver;
+		append_avrule(avrule);
+	}
+
+	/* flag ioctl driver codes that are partially enabled */
+	if (avrule_ioctl_partialdriver(rangelist, complete_driver, &partial_driver))
+		return -1;
+
+	if (!partial_driver || !avrule_xperms_used(partial_driver))
+		goto done;
+
+	/*
+	 * create rule for each partially used driver codes
+	 * "partially used" meaning that the code number e.g. socket 0x89
+	 * has some permission bits set and others not set.
+	 */
+	i = 0;
+	while (xperms_for_each_bit(&i, partial_driver)) {
+		if (avrule_ioctl_func(rangelist, &xperms, i))
+			return -1;
+
+		if (xperms) {
+			avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
+			if (!avrule) {
+				yyerror("out of memory");
+				return -1;
+			}
+			if (avrule_cpy(avrule, avrule_template))
+				return -1;
+			avrule->xperms = xperms;
+			append_avrule(avrule);
+		}
+	}
+
+done:
+	if (partial_driver)
+		free(partial_driver);
+
+	return 0;
+}
+
+int define_te_avtab_extended_perms(int which)
+{
+	char *id;
+	unsigned int i;
+	avrule_t *avrule_template;
+
+	if (pass == 1) {
+		for (i = 0; i < 4; i++) {
+			while ((id = queue_remove(id_queue)))
+				free(id);
+		}
+		return 0;
+	}
+
+	/* populate avrule template with source/target/tclass */
+	if (define_te_avtab_xperms_helper(which, &avrule_template))
+		return -1;
+
+	id = queue_remove(id_queue);
+	if (strcmp(id,"ioctl") == 0) {
+		if (define_te_avtab_ioctl(avrule_template))
+			return -1;
+		free(id);
+	} else {
+		yyerror("only ioctl extended permissions are supported");
+		return -1;
+	}
+	return 0;
+}
+
+int define_te_avtab_helper(int which, avrule_t ** rule)
+{
+	char *id;
+	class_datum_t *cladatum;
+	perm_datum_t *perdatum = NULL;
+	class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL;
+	ebitmap_t tclasses;
+	ebitmap_node_t *node;
+	avrule_t *avrule;
+	unsigned int i;
+	int add = 1, ret = 0;
+	int suppress = 0;
+
+	avrule = (avrule_t *) malloc(sizeof(avrule_t));
+	if (!avrule) {
+		yyerror("memory error");
+		ret = -1;
+		goto out;
+	}
+	avrule_init(avrule);
+	avrule->specified = which;
+	avrule->line = policydb_lineno;
+	avrule->source_line = source_lineno;
+	avrule->source_filename = strdup(source_file);
+	avrule->xperms = NULL;
+	if (!avrule->source_filename) {
+		yyerror("out of memory");
+		return -1;
+	}
+
+
+	while ((id = queue_remove(id_queue))) {
+		if (set_types
+		    (&avrule->stypes, id, &add,
+		     which == AVRULE_NEVERALLOW ? 1 : 0)) {
+			ret = -1;
+			goto out;
+		}
+	}
+	add = 1;
+	while ((id = queue_remove(id_queue))) {
+		if (strcmp(id, "self") == 0) {
+			free(id);
+			avrule->flags |= RULE_SELF;
+			continue;
+		}
+		if (set_types
+		    (&avrule->ttypes, id, &add,
+		     which == AVRULE_NEVERALLOW ? 1 : 0)) {
+			ret = -1;
+			goto out;
+		}
+	}
+
+	ebitmap_init(&tclasses);
+	ret = read_classes(&tclasses);
+	if (ret)
+		goto out;
+
+	perms = NULL;
+	ebitmap_for_each_bit(&tclasses, node, i) {
+		if (!ebitmap_node_get_bit(node, i))
+			continue;
+		cur_perms =
+		    (class_perm_node_t *) malloc(sizeof(class_perm_node_t));
+		if (!cur_perms) {
+			yyerror("out of memory");
+			ret = -1;
+			goto out;
+		}
+		class_perm_node_init(cur_perms);
+		cur_perms->tclass = i + 1;
+		if (!perms)
+			perms = cur_perms;
+		if (tail)
+			tail->next = cur_perms;
+		tail = cur_perms;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		cur_perms = perms;
+		ebitmap_for_each_bit(&tclasses, node, i) {
+			if (!ebitmap_node_get_bit(node, i))
+				continue;
+			cladatum = policydbp->class_val_to_struct[i];
+
+			if (strcmp(id, "*") == 0) {
+				/* set all permissions in the class */
+				cur_perms->data = ~0U;
+				goto next;
+			}
+
+			if (strcmp(id, "~") == 0) {
+				/* complement the set */
+				if (which == AVRULE_DONTAUDIT)
+					yywarn("dontaudit rule with a ~?");
+				cur_perms->data = ~cur_perms->data;
+				goto next;
+			}
+
+			perdatum =
+			    hashtab_search(cladatum->permissions.table, id);
+			if (!perdatum) {
+				if (cladatum->comdatum) {
+					perdatum =
+					    hashtab_search(cladatum->comdatum->
+							   permissions.table,
+							   id);
+				}
+			}
+			if (!perdatum) {
+				if (!suppress)
+					yyerror2("permission %s is not defined"
+					     " for class %s", id,
+					     policydbp->p_class_val_to_name[i]);
+				continue;
+			} else
+			    if (!is_perm_in_scope
+				(id, policydbp->p_class_val_to_name[i])) {
+				if (!suppress) {
+					yyerror2("permission %s of class %s is"
+					     " not within scope", id,
+					     policydbp->p_class_val_to_name[i]);
+				}
+				continue;
+			} else {
+				cur_perms->data |= 1U << (perdatum->s.value - 1);
+			}
+		      next:
+			cur_perms = cur_perms->next;
+		}
+
+		free(id);
+	}
+
+	ebitmap_destroy(&tclasses);
+
+	avrule->perms = perms;
+	*rule = avrule;
+
+      out:
+	return ret;
+
+}
+
+avrule_t *define_cond_te_avtab(int which)
+{
+	char *id;
+	avrule_t *avrule;
+	int i;
+
+	if (pass == 1) {
+		for (i = 0; i < 4; i++) {
+			while ((id = queue_remove(id_queue)))
+				free(id);
+		}
+		return (avrule_t *) 1;	/* any non-NULL value */
+	}
+
+	if (define_te_avtab_helper(which, &avrule))
+		return COND_ERR;
+
+	return avrule;
+}
+
+int define_te_avtab(int which)
+{
+	char *id;
+	avrule_t *avrule;
+	int i;
+
+	if (pass == 1) {
+		for (i = 0; i < 4; i++) {
+			while ((id = queue_remove(id_queue)))
+				free(id);
+		}
+		return 0;
+	}
+
+	if (define_te_avtab_helper(which, &avrule))
+		return -1;
+
+	/* append this avrule to the end of the current rules list */
+	append_avrule(avrule);
+	return 0;
+}
+
+/* The role-types rule is no longer used to declare regular role or
+ * role attribute, but solely aimed for declaring role-types associations.
+ */
+int define_role_types(void)
+{
+	role_datum_t *role;
+	char *id;
+	int add = 1;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no role name for role-types rule?");
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+
+	role = hashtab_search(policydbp->p_roles.table, id);
+	if (!role) {
+		yyerror2("unknown role %s", id);
+		free(id);
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (set_types(&role->types, id, &add, 0))
+			return -1;
+	}
+
+	return 0;
+}
+
+int define_attrib_role(void)
+{
+	if (pass == 2) {
+		free(queue_remove(id_queue));
+		return 0;
+	}
+
+	/* Declare a role attribute */
+	if (declare_role(TRUE) == NULL)
+		return -1;
+
+	return 0;
+}
+
+int define_role_attr(void)
+{
+	char *id;
+	role_datum_t *r, *attr;
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+	
+	/* Declare a regular role */
+	if ((r = declare_role(FALSE)) == NULL)
+		return -1;
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_ROLES, id)) {
+			yyerror2("attribute %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		attr = hashtab_search(policydbp->p_roles.table, id);
+		if (!attr) {
+			/* treat it as a fatal error */
+			yyerror2("role attribute %s is not declared", id);
+			free(id);
+			return -1;
+		}
+
+		if (attr->flavor != ROLE_ATTRIB) {
+			yyerror2("%s is a regular role, not an attribute", id);
+			free(id);
+			return -1;
+		}
+
+		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
+			yyerror("Out of memory!");
+			return -1;
+		}
+
+		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
+			yyerror("out of memory");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int define_roleattribute(void)
+{
+	char *id;
+	role_datum_t *r, *attr;
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no role name for roleattribute definition?");
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	r = hashtab_search(policydbp->p_roles.table, id);
+	/* We support adding one role attribute into another */
+	if (!r) {
+		yyerror2("unknown role %s", id);
+		free(id);
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_ROLES, id)) {
+			yyerror2("attribute %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		attr = hashtab_search(policydbp->p_roles.table, id);
+		if (!attr) {
+			/* treat it as a fatal error */
+			yyerror2("role attribute %s is not declared", id);
+			free(id);
+			return -1;
+		}
+
+		if (attr->flavor != ROLE_ATTRIB) {
+			yyerror2("%s is a regular role, not an attribute", id);
+			free(id);
+			return -1;
+		}
+
+		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
+			yyerror("Out of memory!");
+			return -1;
+		}
+
+		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
+			yyerror("out of memory");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+role_datum_t *merge_roles_dom(role_datum_t * r1, role_datum_t * r2)
+{
+	role_datum_t *new;
+
+	if (pass == 1) {
+		return (role_datum_t *) 1;	/* any non-NULL value */
+	}
+
+	new = malloc(sizeof(role_datum_t));
+	if (!new) {
+		yyerror("out of memory");
+		return NULL;
+	}
+	memset(new, 0, sizeof(role_datum_t));
+	new->s.value = 0;		/* temporary role */
+	if (ebitmap_or(&new->dominates, &r1->dominates, &r2->dominates)) {
+		yyerror("out of memory");
+		free(new);
+		return NULL;
+	}
+	if (ebitmap_or(&new->types.types, &r1->types.types, &r2->types.types)) {
+		yyerror("out of memory");
+		free(new);
+		return NULL;
+	}
+	if (!r1->s.value) {
+		/* free intermediate result */
+		type_set_destroy(&r1->types);
+		ebitmap_destroy(&r1->dominates);
+		free(r1);
+	}
+	if (!r2->s.value) {
+		/* free intermediate result */
+		yyerror("right hand role is temporary?");
+		type_set_destroy(&r2->types);
+		ebitmap_destroy(&r2->dominates);
+		free(r2);
+	}
+	return new;
+}
+
+/* This function eliminates the ordering dependency of role dominance rule */
+static int dominate_role_recheck(hashtab_key_t key __attribute__ ((unused)),
+				 hashtab_datum_t datum, void *arg)
+{
+	role_datum_t *rdp = (role_datum_t *) arg;
+	role_datum_t *rdatum = (role_datum_t *) datum;
+	ebitmap_node_t *node;
+	uint32_t i;
+
+	/* Don't bother to process against self role */
+	if (rdatum->s.value == rdp->s.value)
+		return 0;
+
+	/* If a dominating role found */
+	if (ebitmap_get_bit(&(rdatum->dominates), rdp->s.value - 1)) {
+		ebitmap_t types;
+		ebitmap_init(&types);
+		if (type_set_expand(&rdp->types, &types, policydbp, 1)) {
+			ebitmap_destroy(&types);
+			return -1;
+		}
+		/* raise types and dominates from dominated role */
+		ebitmap_for_each_bit(&rdp->dominates, node, i) {
+			if (ebitmap_node_get_bit(node, i))
+				if (ebitmap_set_bit
+				    (&rdatum->dominates, i, TRUE))
+					goto oom;
+		}
+		ebitmap_for_each_bit(&types, node, i) {
+			if (ebitmap_node_get_bit(node, i))
+				if (ebitmap_set_bit
+				    (&rdatum->types.types, i, TRUE))
+					goto oom;
+		}
+		ebitmap_destroy(&types);
+	}
+
+	/* go through all the roles */
+	return 0;
+      oom:
+	yyerror("Out of memory");
+	return -1;
+}
+
+role_datum_t *define_role_dom(role_datum_t * r)
+{
+	role_datum_t *role;
+	char *role_id;
+	ebitmap_node_t *node;
+	unsigned int i;
+	int ret;
+
+	if (pass == 1) {
+		role_id = queue_remove(id_queue);
+		free(role_id);
+		return (role_datum_t *) 1;	/* any non-NULL value */
+	}
+
+	yywarn("Role dominance has been deprecated");
+
+	role_id = queue_remove(id_queue);
+	if (!is_id_in_scope(SYM_ROLES, role_id)) {
+		yyerror2("role %s is not within scope", role_id);
+		free(role_id);
+		return NULL;
+	}
+	role = (role_datum_t *) hashtab_search(policydbp->p_roles.table,
+					       role_id);
+	if (!role) {
+		role = (role_datum_t *) malloc(sizeof(role_datum_t));
+		if (!role) {
+			yyerror("out of memory");
+			free(role_id);
+			return NULL;
+		}
+		memset(role, 0, sizeof(role_datum_t));
+		ret =
+		    declare_symbol(SYM_ROLES, (hashtab_key_t) role_id,
+				   (hashtab_datum_t) role, &role->s.value,
+				   &role->s.value);
+		switch (ret) {
+		case -3:{
+				yyerror("Out of memory!");
+				goto cleanup;
+			}
+		case -2:{
+				yyerror2("duplicate declaration of role %s",
+					 role_id);
+				goto cleanup;
+			}
+		case -1:{
+				yyerror("could not declare role here");
+				goto cleanup;
+			}
+		case 0:
+		case 1:{
+				break;
+			}
+		default:{
+				assert(0);	/* should never get here */
+			}
+		}
+		if (ebitmap_set_bit(&role->dominates, role->s.value - 1, TRUE)) {
+			yyerror("Out of memory!");
+			goto cleanup;
+		}
+	}
+	if (r) {
+		ebitmap_t types;
+		ebitmap_init(&types);
+		ebitmap_for_each_bit(&r->dominates, node, i) {
+			if (ebitmap_node_get_bit(node, i))
+				if (ebitmap_set_bit(&role->dominates, i, TRUE))
+					goto oom;
+		}
+		if (type_set_expand(&r->types, &types, policydbp, 1)) {
+			ebitmap_destroy(&types);
+			return NULL;
+		}
+		ebitmap_for_each_bit(&types, node, i) {
+			if (ebitmap_node_get_bit(node, i))
+				if (ebitmap_set_bit
+				    (&role->types.types, i, TRUE))
+					goto oom;
+		}
+		ebitmap_destroy(&types);
+		if (!r->s.value) {
+			/* free intermediate result */
+			type_set_destroy(&r->types);
+			ebitmap_destroy(&r->dominates);
+			free(r);
+		}
+		/*
+		 * Now go through all the roles and escalate this role's
+		 * dominates and types if a role dominates this role.
+		 */
+		hashtab_map(policydbp->p_roles.table,
+			    dominate_role_recheck, role);
+	}
+	return role;
+      cleanup:
+	free(role_id);
+	role_datum_destroy(role);
+	free(role);
+	return NULL;
+      oom:
+	yyerror("Out of memory");
+	goto cleanup;
+}
+
+static int role_val_to_name_helper(hashtab_key_t key, hashtab_datum_t datum,
+				   void *p)
+{
+	struct val_to_name *v = p;
+	role_datum_t *roldatum;
+
+	roldatum = (role_datum_t *) datum;
+
+	if (v->val == roldatum->s.value) {
+		v->name = key;
+		return 1;
+	}
+
+	return 0;
+}
+
+static char *role_val_to_name(unsigned int val)
+{
+	struct val_to_name v;
+	int rc;
+
+	v.val = val;
+	rc = hashtab_map(policydbp->p_roles.table, role_val_to_name_helper, &v);
+	if (rc)
+		return v.name;
+	return NULL;
+}
+
+static int set_roles(role_set_t * set, char *id)
+{
+	role_datum_t *r;
+
+	if (strcmp(id, "*") == 0) {
+		free(id);
+		yyerror("* is not allowed for role sets");
+		return -1;
+	}
+
+	if (strcmp(id, "~") == 0) {
+		free(id);
+		yyerror("~ is not allowed for role sets");
+		return -1;
+	}
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	r = hashtab_search(policydbp->p_roles.table, id);
+	if (!r) {
+		yyerror2("unknown role %s", id);
+		free(id);
+		return -1;
+	}
+
+	if (ebitmap_set_bit(&set->roles, r->s.value - 1, TRUE)) {
+		yyerror("out of memory");
+		free(id);
+		return -1;
+	}
+	free(id);
+	return 0;
+}
+
+int define_role_trans(int class_specified)
+{
+	char *id;
+	role_datum_t *role;
+	role_set_t roles;
+	type_set_t types;
+	class_datum_t *cladatum;
+	ebitmap_t e_types, e_roles, e_classes;
+	ebitmap_node_t *tnode, *rnode, *cnode;
+	struct role_trans *tr = NULL;
+	struct role_trans_rule *rule = NULL;
+	unsigned int i, j, k;
+	int add = 1;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		if (class_specified)
+			while ((id = queue_remove(id_queue)))
+				free(id);
+		id = queue_remove(id_queue);
+		free(id);
+		return 0;
+	}
+
+	role_set_init(&roles);
+	ebitmap_init(&e_roles);
+	type_set_init(&types);
+	ebitmap_init(&e_types);
+	ebitmap_init(&e_classes);
+
+	while ((id = queue_remove(id_queue))) {
+		if (set_roles(&roles, id))
+			return -1;
+	}
+	add = 1;
+	while ((id = queue_remove(id_queue))) {
+		if (set_types(&types, id, &add, 0))
+			return -1;
+	}
+
+	if (class_specified) {
+		if (read_classes(&e_classes))
+			return -1;
+	} else {
+		cladatum = hashtab_search(policydbp->p_classes.table,
+					  "process");
+		if (!cladatum) {
+			yyerror2("could not find process class for "
+				 "legacy role_transition statement");
+			return -1;
+		}
+
+		if (ebitmap_set_bit(&e_classes, cladatum->s.value - 1, TRUE)) {
+			yyerror("out of memory");
+			return -1;
+		}
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no new role in transition definition?");
+		goto bad;
+	}
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		goto bad;
+	}
+	role = hashtab_search(policydbp->p_roles.table, id);
+	if (!role) {
+		yyerror2("unknown role %s used in transition definition", id);
+		goto bad;
+	}
+
+	if (role->flavor != ROLE_ROLE) {
+		yyerror2("the new role %s must be a regular role", id);
+		goto bad;
+	}
+
+	/* This ebitmap business is just to ensure that there are not conflicting role_trans rules */
+	if (role_set_expand(&roles, &e_roles, policydbp, NULL, NULL))
+		goto bad;
+
+	if (type_set_expand(&types, &e_types, policydbp, 1))
+		goto bad;
+
+	ebitmap_for_each_bit(&e_roles, rnode, i) {
+		if (!ebitmap_node_get_bit(rnode, i))
+			continue;
+		ebitmap_for_each_bit(&e_types, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			ebitmap_for_each_bit(&e_classes, cnode, k) {
+				if (!ebitmap_node_get_bit(cnode, k))
+					continue;
+				for (tr = policydbp->role_tr; tr;
+				     tr = tr->next) {
+					if (tr->role == (i + 1) &&
+					    tr->type == (j + 1) &&
+					    tr->tclass == (k + 1)) {
+						yyerror2("duplicate role "
+							 "transition for "
+							 "(%s,%s,%s)",
+							 role_val_to_name(i+1),
+							 policydbp->p_type_val_to_name[j],
+							 policydbp->p_class_val_to_name[k]);
+						goto bad;
+					}
+				}
+
+				tr = malloc(sizeof(struct role_trans));
+				if (!tr) {
+					yyerror("out of memory");
+					return -1;
+				}
+				memset(tr, 0, sizeof(struct role_trans));
+				tr->role = i + 1;
+				tr->type = j + 1;
+				tr->tclass = k + 1;
+				tr->new_role = role->s.value;
+				tr->next = policydbp->role_tr;
+				policydbp->role_tr = tr;
+			}
+		}
+	}
+	/* Now add the real rule */
+	rule = malloc(sizeof(struct role_trans_rule));
+	if (!rule) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(rule, 0, sizeof(struct role_trans_rule));
+	rule->roles = roles;
+	rule->types = types;
+	rule->classes = e_classes;
+	rule->new_role = role->s.value;
+
+	append_role_trans(rule);
+
+	ebitmap_destroy(&e_roles);
+	ebitmap_destroy(&e_types);
+
+	return 0;
+
+      bad:
+	return -1;
+}
+
+int define_role_allow(void)
+{
+	char *id;
+	struct role_allow_rule *ra = 0;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	ra = malloc(sizeof(role_allow_rule_t));
+	if (!ra) {
+		yyerror("out of memory");
+		return -1;
+	}
+	role_allow_rule_init(ra);
+
+	while ((id = queue_remove(id_queue))) {
+		if (set_roles(&ra->roles, id)) {
+			free(ra);
+			return -1;
+		}
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (set_roles(&ra->new_roles, id)) {
+			free(ra);
+			return -1;
+		}
+	}
+
+	append_role_allow(ra);
+	return 0;
+}
+
+avrule_t *define_cond_filename_trans(void)
+{
+	yyerror("type transitions with a filename not allowed inside "
+		"conditionals\n");
+	return COND_ERR;
+}
+
+int define_filename_trans(void)
+{
+	char *id, *name = NULL;
+	type_set_t stypes, ttypes;
+	ebitmap_t e_stypes, e_ttypes;
+	ebitmap_t e_tclasses;
+	ebitmap_node_t *snode, *tnode, *cnode;
+	filename_trans_t *ft;
+	filename_trans_rule_t *ftr;
+	type_datum_t *typdatum;
+	uint32_t otype;
+	unsigned int c, s, t;
+	int add;
+
+	if (pass == 1) {
+		/* stype */
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		/* ttype */
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		/* tclass */
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		/* otype */
+		id = queue_remove(id_queue);
+		free(id);
+		/* name */
+		id = queue_remove(id_queue);
+		free(id);
+		return 0;
+	}
+
+
+	add = 1;
+	type_set_init(&stypes);
+	while ((id = queue_remove(id_queue))) {
+		if (set_types(&stypes, id, &add, 0))
+			goto bad;
+	}
+
+	add =1;
+	type_set_init(&ttypes);
+	while ((id = queue_remove(id_queue))) {
+		if (set_types(&ttypes, id, &add, 0))
+			goto bad;
+	}
+
+	ebitmap_init(&e_tclasses);
+	if (read_classes(&e_tclasses))
+		goto bad;
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no otype in transition definition?");
+		goto bad;
+	}
+	if (!is_id_in_scope(SYM_TYPES, id)) {
+		yyerror2("type %s is not within scope", id);
+		free(id);
+		goto bad;
+	}
+	typdatum = hashtab_search(policydbp->p_types.table, id);
+	if (!typdatum) {
+		yyerror2("unknown type %s used in transition definition", id);
+		goto bad;
+	}
+	free(id);
+	otype = typdatum->s.value;
+
+	name = queue_remove(id_queue);
+	if (!name) {
+		yyerror("no pathname specified in filename_trans definition?");
+		goto bad;
+	}
+
+	/* We expand the class set into seperate rules.  We expand the types
+	 * just to make sure there are not duplicates.  They will get turned
+	 * into seperate rules later */
+	ebitmap_init(&e_stypes);
+	if (type_set_expand(&stypes, &e_stypes, policydbp, 1))
+		goto bad;
+
+	ebitmap_init(&e_ttypes);
+	if (type_set_expand(&ttypes, &e_ttypes, policydbp, 1))
+		goto bad;
+
+	ebitmap_for_each_bit(&e_tclasses, cnode, c) {
+		if (!ebitmap_node_get_bit(cnode, c))
+			continue;
+		ebitmap_for_each_bit(&e_stypes, snode, s) {
+			if (!ebitmap_node_get_bit(snode, s))
+				continue;
+			ebitmap_for_each_bit(&e_ttypes, tnode, t) {
+				if (!ebitmap_node_get_bit(tnode, t))
+					continue;
+	
+				for (ft = policydbp->filename_trans; ft; ft = ft->next) {
+					if (ft->stype == (s + 1) &&
+					    ft->ttype == (t + 1) &&
+					    ft->tclass == (c + 1) &&
+					    !strcmp(ft->name, name)) {
+						yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s",
+							 name, 
+							 policydbp->p_type_val_to_name[s],
+							 policydbp->p_type_val_to_name[t],
+							 policydbp->p_class_val_to_name[c]);
+						goto bad;
+					}
+				}
+	
+				ft = malloc(sizeof(*ft));
+				if (!ft) {
+					yyerror("out of memory");
+					goto bad;
+				}
+				memset(ft, 0, sizeof(*ft));
+	
+				ft->next = policydbp->filename_trans;
+				policydbp->filename_trans = ft;
+	
+				ft->name = strdup(name);
+				if (!ft->name) {
+					yyerror("out of memory");
+					goto bad;
+				}
+				ft->stype = s + 1;
+				ft->ttype = t + 1;
+				ft->tclass = c + 1;
+				ft->otype = otype;
+			}
+		}
+	
+		/* Now add the real rule since we didn't find any duplicates */
+		ftr = malloc(sizeof(*ftr));
+		if (!ftr) {
+			yyerror("out of memory");
+			goto bad;
+		}
+		filename_trans_rule_init(ftr);
+		append_filename_trans(ftr);
+
+		ftr->name = strdup(name);
+		if (type_set_cpy(&ftr->stypes, &stypes)) {
+			yyerror("out of memory");
+			goto bad;
+		}
+		if (type_set_cpy(&ftr->ttypes, &ttypes)) {
+			yyerror("out of memory");
+			goto bad;
+		}
+		ftr->tclass = c + 1;
+		ftr->otype = otype;
+	}
+
+	free(name);
+	ebitmap_destroy(&e_stypes);
+	ebitmap_destroy(&e_ttypes);
+	ebitmap_destroy(&e_tclasses);
+
+	return 0;
+
+bad:
+	free(name);
+	return -1;
+}
+
+static constraint_expr_t *constraint_expr_clone(constraint_expr_t * expr)
+{
+	constraint_expr_t *h = NULL, *l = NULL, *e, *newe;
+	for (e = expr; e; e = e->next) {
+		newe = malloc(sizeof(*newe));
+		if (!newe)
+			goto oom;
+		if (constraint_expr_init(newe) == -1) {
+			free(newe);
+			goto oom;
+		}
+		if (l)
+			l->next = newe;
+		else
+			h = newe;
+		l = newe;
+		newe->expr_type = e->expr_type;
+		newe->attr = e->attr;
+		newe->op = e->op;
+		if (newe->expr_type == CEXPR_NAMES) {
+			if (newe->attr & CEXPR_TYPE) {
+				if (type_set_cpy
+				    (newe->type_names, e->type_names))
+					goto oom;
+			} else {
+				if (ebitmap_cpy(&newe->names, &e->names))
+					goto oom;
+			}
+		}
+	}
+
+	return h;
+      oom:
+	e = h;
+	while (e) {
+		l = e;
+		e = e->next;
+		constraint_expr_destroy(l);
+	}
+	return NULL;
+}
+
+int define_constraint(constraint_expr_t * expr)
+{
+	struct constraint_node *node;
+	char *id;
+	class_datum_t *cladatum;
+	perm_datum_t *perdatum;
+	ebitmap_t classmap;
+	ebitmap_node_t *enode;
+	constraint_expr_t *e;
+	unsigned int i;
+	int depth;
+	unsigned char useexpr = 1;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	depth = -1;
+	for (e = expr; e; e = e->next) {
+		switch (e->expr_type) {
+		case CEXPR_NOT:
+			if (depth < 0) {
+				yyerror("illegal constraint expression");
+				return -1;
+			}
+			break;
+		case CEXPR_AND:
+		case CEXPR_OR:
+			if (depth < 1) {
+				yyerror("illegal constraint expression");
+				return -1;
+			}
+			depth--;
+			break;
+		case CEXPR_ATTR:
+		case CEXPR_NAMES:
+			if (e->attr & CEXPR_XTARGET) {
+				yyerror("illegal constraint expression");
+				return -1;	/* only for validatetrans rules */
+			}
+			if (depth == (CEXPR_MAXDEPTH - 1)) {
+				yyerror("constraint expression is too deep");
+				return -1;
+			}
+			depth++;
+			break;
+		default:
+			yyerror("illegal constraint expression");
+			return -1;
+		}
+	}
+	if (depth != 0) {
+		yyerror("illegal constraint expression");
+		return -1;
+	}
+
+	ebitmap_init(&classmap);
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_CLASSES, id)) {
+			yyerror2("class %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		cladatum =
+		    (class_datum_t *) hashtab_search(policydbp->p_classes.table,
+						     (hashtab_key_t) id);
+		if (!cladatum) {
+			yyerror2("class %s is not defined", id);
+			ebitmap_destroy(&classmap);
+			free(id);
+			return -1;
+		}
+		if (ebitmap_set_bit(&classmap, cladatum->s.value - 1, TRUE)) {
+			yyerror("out of memory");
+			ebitmap_destroy(&classmap);
+			free(id);
+			return -1;
+		}
+		node = malloc(sizeof(struct constraint_node));
+		if (!node) {
+			yyerror("out of memory");
+			free(node);
+			return -1;
+		}
+		memset(node, 0, sizeof(constraint_node_t));
+		if (useexpr) {
+			node->expr = expr;
+			useexpr = 0;
+		} else {
+			node->expr = constraint_expr_clone(expr);
+		}
+		if (!node->expr) {
+			yyerror("out of memory");
+			free(node);
+			return -1;
+		}
+		node->permissions = 0;
+
+		node->next = cladatum->constraints;
+		cladatum->constraints = node;
+
+		free(id);
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		ebitmap_for_each_bit(&classmap, enode, i) {
+			if (ebitmap_node_get_bit(enode, i)) {
+				cladatum = policydbp->class_val_to_struct[i];
+				node = cladatum->constraints;
+
+				perdatum =
+				    (perm_datum_t *) hashtab_search(cladatum->
+								    permissions.
+								    table,
+								    (hashtab_key_t)
+								    id);
+				if (!perdatum) {
+					if (cladatum->comdatum) {
+						perdatum =
+						    (perm_datum_t *)
+						    hashtab_search(cladatum->
+								   comdatum->
+								   permissions.
+								   table,
+								   (hashtab_key_t)
+								   id);
+					}
+					if (!perdatum) {
+						yyerror2("permission %s is not"
+							 " defined", id);
+						free(id);
+						ebitmap_destroy(&classmap);
+						return -1;
+					}
+				}
+				node->permissions |=
+				    (1 << (perdatum->s.value - 1));
+			}
+		}
+		free(id);
+	}
+
+	ebitmap_destroy(&classmap);
+
+	return 0;
+}
+
+int define_validatetrans(constraint_expr_t * expr)
+{
+	struct constraint_node *node;
+	char *id;
+	class_datum_t *cladatum;
+	ebitmap_t classmap;
+	constraint_expr_t *e;
+	int depth;
+	unsigned char useexpr = 1;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	depth = -1;
+	for (e = expr; e; e = e->next) {
+		switch (e->expr_type) {
+		case CEXPR_NOT:
+			if (depth < 0) {
+				yyerror("illegal validatetrans expression");
+				return -1;
+			}
+			break;
+		case CEXPR_AND:
+		case CEXPR_OR:
+			if (depth < 1) {
+				yyerror("illegal validatetrans expression");
+				return -1;
+			}
+			depth--;
+			break;
+		case CEXPR_ATTR:
+		case CEXPR_NAMES:
+			if (depth == (CEXPR_MAXDEPTH - 1)) {
+				yyerror("validatetrans expression is too deep");
+				return -1;
+			}
+			depth++;
+			break;
+		default:
+			yyerror("illegal validatetrans expression");
+			return -1;
+		}
+	}
+	if (depth != 0) {
+		yyerror("illegal validatetrans expression");
+		return -1;
+	}
+
+	ebitmap_init(&classmap);
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_CLASSES, id)) {
+			yyerror2("class %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		cladatum =
+		    (class_datum_t *) hashtab_search(policydbp->p_classes.table,
+						     (hashtab_key_t) id);
+		if (!cladatum) {
+			yyerror2("class %s is not defined", id);
+			ebitmap_destroy(&classmap);
+			free(id);
+			return -1;
+		}
+		if (ebitmap_set_bit(&classmap, (cladatum->s.value - 1), TRUE)) {
+			yyerror("out of memory");
+			ebitmap_destroy(&classmap);
+			free(id);
+			return -1;
+		}
+
+		node = malloc(sizeof(struct constraint_node));
+		if (!node) {
+			yyerror("out of memory");
+			return -1;
+		}
+		memset(node, 0, sizeof(constraint_node_t));
+		if (useexpr) {
+			node->expr = expr;
+			useexpr = 0;
+		} else {
+			node->expr = constraint_expr_clone(expr);
+		}
+		node->permissions = 0;
+
+		node->next = cladatum->validatetrans;
+		cladatum->validatetrans = node;
+
+		free(id);
+	}
+
+	ebitmap_destroy(&classmap);
+
+	return 0;
+}
+
+uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2)
+{
+	struct constraint_expr *expr, *e1 = NULL, *e2;
+	user_datum_t *user;
+	role_datum_t *role;
+	ebitmap_t negset;
+	char *id;
+	uint32_t val;
+	int add = 1;
+
+	if (pass == 1) {
+		if (expr_type == CEXPR_NAMES) {
+			while ((id = queue_remove(id_queue)))
+				free(id);
+		}
+		return 1;	/* any non-NULL value */
+	}
+
+	if ((expr = malloc(sizeof(*expr))) == NULL ||
+	    constraint_expr_init(expr) == -1) {
+		yyerror("out of memory");
+		free(expr);
+		return 0;
+	}
+	expr->expr_type = expr_type;
+
+	switch (expr_type) {
+	case CEXPR_NOT:
+		e1 = NULL;
+		e2 = (struct constraint_expr *)arg1;
+		while (e2) {
+			e1 = e2;
+			e2 = e2->next;
+		}
+		if (!e1 || e1->next) {
+			yyerror("illegal constraint expression");
+			constraint_expr_destroy(expr);
+			return 0;
+		}
+		e1->next = expr;
+		return arg1;
+	case CEXPR_AND:
+	case CEXPR_OR:
+		e1 = NULL;
+		e2 = (struct constraint_expr *)arg1;
+		while (e2) {
+			e1 = e2;
+			e2 = e2->next;
+		}
+		if (!e1 || e1->next) {
+			yyerror("illegal constraint expression");
+			constraint_expr_destroy(expr);
+			return 0;
+		}
+		e1->next = (struct constraint_expr *)arg2;
+
+		e1 = NULL;
+		e2 = (struct constraint_expr *)arg2;
+		while (e2) {
+			e1 = e2;
+			e2 = e2->next;
+		}
+		if (!e1 || e1->next) {
+			yyerror("illegal constraint expression");
+			constraint_expr_destroy(expr);
+			return 0;
+		}
+		e1->next = expr;
+		return arg1;
+	case CEXPR_ATTR:
+		expr->attr = arg1;
+		expr->op = arg2;
+		return (uintptr_t) expr;
+	case CEXPR_NAMES:
+		add = 1;
+		expr->attr = arg1;
+		expr->op = arg2;
+		ebitmap_init(&negset);
+		while ((id = (char *)queue_remove(id_queue))) {
+			if (expr->attr & CEXPR_USER) {
+				if (!is_id_in_scope(SYM_USERS, id)) {
+					yyerror2("user %s is not within scope",
+						 id);
+					constraint_expr_destroy(expr);
+					return 0;
+				}
+				user =
+				    (user_datum_t *) hashtab_search(policydbp->
+								    p_users.
+								    table,
+								    (hashtab_key_t)
+								    id);
+				if (!user) {
+					yyerror2("unknown user %s", id);
+					constraint_expr_destroy(expr);
+					return 0;
+				}
+				val = user->s.value;
+			} else if (expr->attr & CEXPR_ROLE) {
+				if (!is_id_in_scope(SYM_ROLES, id)) {
+					yyerror2("role %s is not within scope",
+						 id);
+					constraint_expr_destroy(expr);
+					return 0;
+				}
+				role =
+				    (role_datum_t *) hashtab_search(policydbp->
+								    p_roles.
+								    table,
+								    (hashtab_key_t)
+								    id);
+				if (!role) {
+					yyerror2("unknown role %s", id);
+					constraint_expr_destroy(expr);
+					return 0;
+				}
+				val = role->s.value;
+			} else if (expr->attr & CEXPR_TYPE) {
+				if (set_types(expr->type_names, id, &add, 0)) {
+					constraint_expr_destroy(expr);
+					return 0;
+				}
+				continue;
+			} else {
+				yyerror("invalid constraint expression");
+				constraint_expr_destroy(expr);
+				return 0;
+			}
+			if (ebitmap_set_bit(&expr->names, val - 1, TRUE)) {
+				yyerror("out of memory");
+				ebitmap_destroy(&expr->names);
+				constraint_expr_destroy(expr);
+				return 0;
+			}
+			free(id);
+		}
+		ebitmap_destroy(&negset);
+		return (uintptr_t) expr;
+	default:
+		break;
+	}
+
+	yyerror("invalid constraint expression");
+	constraint_expr_destroy(expr);
+	return 0;
+}
+
+int define_conditional(cond_expr_t * expr, avrule_t * t, avrule_t * f)
+{
+	cond_expr_t *e;
+	int depth;
+	cond_node_t cn, *cn_old;
+
+	/* expression cannot be NULL */
+	if (!expr) {
+		yyerror("illegal conditional expression");
+		return -1;
+	}
+	if (!t) {
+		if (!f) {
+			/* empty is fine, destroy expression and return */
+			cond_expr_destroy(expr);
+			return 0;
+		}
+		/* Invert */
+		t = f;
+		f = 0;
+		expr = define_cond_expr(COND_NOT, expr, 0);
+		if (!expr) {
+			yyerror("unable to invert");
+			return -1;
+		}
+	}
+
+	/* verify expression */
+	depth = -1;
+	for (e = expr; e; e = e->next) {
+		switch (e->expr_type) {
+		case COND_NOT:
+			if (depth < 0) {
+				yyerror
+				    ("illegal conditional expression; Bad NOT");
+				return -1;
+			}
+			break;
+		case COND_AND:
+		case COND_OR:
+		case COND_XOR:
+		case COND_EQ:
+		case COND_NEQ:
+			if (depth < 1) {
+				yyerror
+				    ("illegal conditional expression; Bad binary op");
+				return -1;
+			}
+			depth--;
+			break;
+		case COND_BOOL:
+			if (depth == (COND_EXPR_MAXDEPTH - 1)) {
+				yyerror
+				    ("conditional expression is like totally too deep");
+				return -1;
+			}
+			depth++;
+			break;
+		default:
+			yyerror("illegal conditional expression");
+			return -1;
+		}
+	}
+	if (depth != 0) {
+		yyerror("illegal conditional expression");
+		return -1;
+	}
+
+	/*  use tmp conditional node to partially build new node */
+	memset(&cn, 0, sizeof(cn));
+	cn.expr = expr;
+	cn.avtrue_list = t;
+	cn.avfalse_list = f;
+
+	/* normalize/precompute expression */
+	if (cond_normalize_expr(policydbp, &cn) < 0) {
+		yyerror("problem normalizing conditional expression");
+		return -1;
+	}
+
+	/* get the existing conditional node, or create a new one */
+	cn_old = get_current_cond_list(&cn);
+	if (!cn_old) {
+		return -1;
+	}
+
+	append_cond_list(&cn);
+
+	/* note that there is no check here for duplicate rules, nor
+	 * check that rule already exists in base -- that will be
+	 * handled during conditional expansion, in expand.c */
+
+	cn.avtrue_list = NULL;
+	cn.avfalse_list = NULL;
+	cond_node_destroy(&cn);
+
+	return 0;
+}
+
+cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void *arg2)
+{
+	struct cond_expr *expr, *e1 = NULL, *e2;
+	cond_bool_datum_t *bool_var;
+	char *id;
+
+	/* expressions are handled in the second pass */
+	if (pass == 1) {
+		if (expr_type == COND_BOOL) {
+			while ((id = queue_remove(id_queue))) {
+				free(id);
+			}
+		}
+		return (cond_expr_t *) 1;	/* any non-NULL value */
+	}
+
+	/* create a new expression struct */
+	expr = malloc(sizeof(struct cond_expr));
+	if (!expr) {
+		yyerror("out of memory");
+		return NULL;
+	}
+	memset(expr, 0, sizeof(cond_expr_t));
+	expr->expr_type = expr_type;
+
+	/* create the type asked for */
+	switch (expr_type) {
+	case COND_NOT:
+		e1 = NULL;
+		e2 = (struct cond_expr *)arg1;
+		while (e2) {
+			e1 = e2;
+			e2 = e2->next;
+		}
+		if (!e1 || e1->next) {
+			yyerror("illegal conditional NOT expression");
+			free(expr);
+			return NULL;
+		}
+		e1->next = expr;
+		return (struct cond_expr *)arg1;
+	case COND_AND:
+	case COND_OR:
+	case COND_XOR:
+	case COND_EQ:
+	case COND_NEQ:
+		e1 = NULL;
+		e2 = (struct cond_expr *)arg1;
+		while (e2) {
+			e1 = e2;
+			e2 = e2->next;
+		}
+		if (!e1 || e1->next) {
+			yyerror
+			    ("illegal left side of conditional binary op expression");
+			free(expr);
+			return NULL;
+		}
+		e1->next = (struct cond_expr *)arg2;
+
+		e1 = NULL;
+		e2 = (struct cond_expr *)arg2;
+		while (e2) {
+			e1 = e2;
+			e2 = e2->next;
+		}
+		if (!e1 || e1->next) {
+			yyerror
+			    ("illegal right side of conditional binary op expression");
+			free(expr);
+			return NULL;
+		}
+		e1->next = expr;
+		return (struct cond_expr *)arg1;
+	case COND_BOOL:
+		id = (char *)queue_remove(id_queue);
+		if (!id) {
+			yyerror("bad conditional; expected boolean id");
+			free(id);
+			free(expr);
+			return NULL;
+		}
+		if (!is_id_in_scope(SYM_BOOLS, id)) {
+			yyerror2("boolean %s is not within scope", id);
+			free(id);
+			free(expr);
+			return NULL;
+		}
+		bool_var =
+		    (cond_bool_datum_t *) hashtab_search(policydbp->p_bools.
+							 table,
+							 (hashtab_key_t) id);
+		if (!bool_var) {
+			yyerror2("unknown boolean %s in conditional expression",
+				 id);
+			free(expr);
+			free(id);
+			return NULL;
+		}
+		expr->bool = bool_var->s.value;
+		free(id);
+		return expr;
+	default:
+		yyerror("illegal conditional expression");
+		free(expr);
+		return NULL;
+	}
+}
+
+static int set_user_roles(role_set_t * set, char *id)
+{
+	role_datum_t *r;
+	unsigned int i;
+	ebitmap_node_t *node;
+
+	if (strcmp(id, "*") == 0) {
+		free(id);
+		yyerror("* is not allowed in user declarations");
+		return -1;
+	}
+
+	if (strcmp(id, "~") == 0) {
+		free(id);
+		yyerror("~ is not allowed in user declarations");
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	r = hashtab_search(policydbp->p_roles.table, id);
+	if (!r) {
+		yyerror2("unknown role %s", id);
+		free(id);
+		return -1;
+	}
+
+	/* set the role and every role it dominates */
+	ebitmap_for_each_bit(&r->dominates, node, i) {
+		if (ebitmap_node_get_bit(node, i))
+			if (ebitmap_set_bit(&set->roles, i, TRUE))
+				goto oom;
+	}
+	free(id);
+	return 0;
+      oom:
+	yyerror("out of memory");
+	return -1;
+}
+
+static int parse_categories(char *id, level_datum_t * levdatum, ebitmap_t * cats)
+{
+	cat_datum_t *cdatum;
+	int range_start, range_end, i;
+
+	if (id_has_dot(id)) {
+		char *id_start = id;
+		char *id_end = strchr(id, '.');
+
+		*(id_end++) = '\0';
+
+		cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table,
+							(hashtab_key_t)
+							id_start);
+		if (!cdatum) {
+			yyerror2("unknown category %s", id_start);
+			return -1;
+		}
+		range_start = cdatum->s.value - 1;
+		cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table,
+							(hashtab_key_t) id_end);
+		if (!cdatum) {
+			yyerror2("unknown category %s", id_end);
+			return -1;
+		}
+		range_end = cdatum->s.value - 1;
+
+		if (range_end < range_start) {
+			yyerror2("category range is invalid");
+			return -1;
+		}
+	} else {
+		cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table,
+							(hashtab_key_t) id);
+		if (!cdatum) {
+			yyerror2("unknown category %s", id);
+			return -1;
+		}
+		range_start = range_end = cdatum->s.value - 1;
+	}
+
+	for (i = range_start; i <= range_end; i++) {
+		if (!ebitmap_get_bit(&levdatum->level->cat, i)) {
+			uint32_t level_value = levdatum->level->sens - 1;
+			policydb_index_others(NULL, policydbp, 0);
+			yyerror2("category %s can not be associated "
+				 "with level %s",
+				 policydbp->p_cat_val_to_name[i],
+				 policydbp->p_sens_val_to_name[level_value]);
+			return -1;
+		}
+		if (ebitmap_set_bit(cats, i, TRUE)) {
+			yyerror("out of memory");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int parse_semantic_categories(char *id, level_datum_t * levdatum __attribute__ ((unused)),
+				     mls_semantic_cat_t ** cats)
+{
+	cat_datum_t *cdatum;
+	mls_semantic_cat_t *newcat;
+	unsigned int range_start, range_end;
+
+	if (id_has_dot(id)) {
+		char *id_start = id;
+		char *id_end = strchr(id, '.');
+
+		*(id_end++) = '\0';
+
+		cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table,
+							(hashtab_key_t)
+							id_start);
+		if (!cdatum) {
+			yyerror2("unknown category %s", id_start);
+			return -1;
+		}
+		range_start = cdatum->s.value;
+
+		cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table,
+							(hashtab_key_t) id_end);
+		if (!cdatum) {
+			yyerror2("unknown category %s", id_end);
+			return -1;
+		}
+		range_end = cdatum->s.value;
+	} else {
+		cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table,
+							(hashtab_key_t) id);
+		if (!cdatum) {
+			yyerror2("unknown category %s", id);
+			return -1;
+		}
+		range_start = range_end = cdatum->s.value;
+	}
+
+	newcat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+	if (!newcat) {
+		yyerror("out of memory");
+		return -1;
+	}
+
+	mls_semantic_cat_init(newcat);
+	newcat->next = *cats;
+	newcat->low = range_start;
+	newcat->high = range_end;
+
+	*cats = newcat;
+
+	return 0;
+}
+
+int define_user(void)
+{
+	char *id;
+	user_datum_t *usrdatum;
+	level_datum_t *levdatum;
+	int l;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		if (mlspol) {
+			while ((id = queue_remove(id_queue)))
+				free(id);
+			id = queue_remove(id_queue);
+			free(id);
+			for (l = 0; l < 2; l++) {
+				while ((id = queue_remove(id_queue))) {
+					free(id);
+				}
+				id = queue_remove(id_queue);
+				if (!id)
+					break;
+				free(id);
+			}
+		}
+		return 0;
+	}
+
+	if ((usrdatum = declare_user()) == NULL) {
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (set_user_roles(&usrdatum->roles, id))
+			continue;
+	}
+
+	if (mlspol) {
+		id = queue_remove(id_queue);
+		if (!id) {
+			yyerror("no default level specified for user");
+			return -1;
+		}
+
+		levdatum = (level_datum_t *)
+		    hashtab_search(policydbp->p_levels.table,
+				   (hashtab_key_t) id);
+		if (!levdatum) {
+			yyerror2("unknown sensitivity %s used in user"
+				 " level definition", id);
+			free(id);
+			return -1;
+		}
+		free(id);
+
+		usrdatum->dfltlevel.sens = levdatum->level->sens;
+
+		while ((id = queue_remove(id_queue))) {
+			if (parse_semantic_categories(id, levdatum,
+			                            &usrdatum->dfltlevel.cat)) {
+				free(id);
+				return -1;
+			}
+			free(id);
+		}
+
+		id = queue_remove(id_queue);
+
+		for (l = 0; l < 2; l++) {
+			levdatum = (level_datum_t *)
+			    hashtab_search(policydbp->p_levels.table,
+					   (hashtab_key_t) id);
+			if (!levdatum) {
+				yyerror2("unknown sensitivity %s used in user"
+					 " range definition", id);
+				free(id);
+				return -1;
+			}
+			free(id);
+
+			usrdatum->range.level[l].sens = levdatum->level->sens;
+
+			while ((id = queue_remove(id_queue))) {
+				if (parse_semantic_categories(id, levdatum,
+				               &usrdatum->range.level[l].cat)) {
+					free(id);
+					return -1;
+				}
+				free(id);
+			}
+
+			id = queue_remove(id_queue);
+			if (!id)
+				break;
+		}
+
+		if (l == 0) {
+			if (mls_semantic_level_cpy(&usrdatum->range.level[1],
+			                           &usrdatum->range.level[0])) {
+				yyerror("out of memory");
+				return -1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int parse_security_context(context_struct_t * c)
+{
+	char *id;
+	role_datum_t *role;
+	type_datum_t *typdatum;
+	user_datum_t *usrdatum;
+	level_datum_t *levdatum;
+	int l;
+
+	if (pass == 1) {
+		id = queue_remove(id_queue);
+		free(id);	/* user  */
+		id = queue_remove(id_queue);
+		free(id);	/* role  */
+		id = queue_remove(id_queue);
+		free(id);	/* type  */
+		if (mlspol) {
+			id = queue_remove(id_queue);
+			free(id);
+			for (l = 0; l < 2; l++) {
+				while ((id = queue_remove(id_queue))) {
+					free(id);
+				}
+				id = queue_remove(id_queue);
+				if (!id)
+					break;
+				free(id);
+			}
+		}
+		return 0;
+	}
+
+	/* check context c to make sure ok to dereference c later */
+	if (c == NULL) {
+		yyerror("null context pointer!");
+		return -1;
+	}
+
+	context_init(c);
+
+	/* extract the user */
+	id = queue_remove(id_queue);
+	if (!id) {
+		yyerror("no effective user?");
+		goto bad;
+	}
+	if (!is_id_in_scope(SYM_USERS, id)) {
+		yyerror2("user %s is not within scope", id);
+		free(id);
+		goto bad;
+	}
+	usrdatum = (user_datum_t *) hashtab_search(policydbp->p_users.table,
+						   (hashtab_key_t) id);
+	if (!usrdatum) {
+		yyerror2("user %s is not defined", id);
+		free(id);
+		goto bad;
+	}
+	c->user = usrdatum->s.value;
+
+	/* no need to keep the user name */
+	free(id);
+
+	/* extract the role */
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no role name for sid context definition?");
+		return -1;
+	}
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	role = (role_datum_t *) hashtab_search(policydbp->p_roles.table,
+					       (hashtab_key_t) id);
+	if (!role) {
+		yyerror2("role %s is not defined", id);
+		free(id);
+		return -1;
+	}
+	c->role = role->s.value;
+
+	/* no need to keep the role name */
+	free(id);
+
+	/* extract the type */
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no type name for sid context definition?");
+		return -1;
+	}
+	if (!is_id_in_scope(SYM_TYPES, id)) {
+		yyerror2("type %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	typdatum = (type_datum_t *) hashtab_search(policydbp->p_types.table,
+						   (hashtab_key_t) id);
+	if (!typdatum || typdatum->flavor == TYPE_ATTRIB) {
+		yyerror2("type %s is not defined or is an attribute", id);
+		free(id);
+		return -1;
+	}
+	c->type = typdatum->s.value;
+
+	/* no need to keep the type name */
+	free(id);
+
+	if (mlspol) {
+		/* extract the low sensitivity */
+		id = (char *)queue_head(id_queue);
+		if (!id) {
+			yyerror("no sensitivity name for sid context"
+				" definition?");
+			return -1;
+		}
+
+		id = (char *)queue_remove(id_queue);
+		for (l = 0; l < 2; l++) {
+			levdatum = (level_datum_t *)
+			    hashtab_search(policydbp->p_levels.table,
+					   (hashtab_key_t) id);
+			if (!levdatum) {
+				yyerror2("Sensitivity %s is not defined", id);
+				free(id);
+				return -1;
+			}
+			free(id);
+			c->range.level[l].sens = levdatum->level->sens;
+
+			/* extract low category set */
+			while ((id = queue_remove(id_queue))) {
+				if (parse_categories(id, levdatum,
+						     &c->range.level[l].cat)) {
+					free(id);
+					return -1;
+				}
+				free(id);
+			}
+
+			/* extract high sensitivity */
+			id = (char *)queue_remove(id_queue);
+			if (!id)
+				break;
+		}
+
+		if (l == 0) {
+			c->range.level[1].sens = c->range.level[0].sens;
+			if (ebitmap_cpy(&c->range.level[1].cat,
+					&c->range.level[0].cat)) {
+
+				yyerror("out of memory");
+				goto bad;
+			}
+		}
+	}
+
+	if (!policydb_context_isvalid(policydbp, c)) {
+		yyerror("invalid security context");
+		goto bad;
+	}
+	return 0;
+
+      bad:
+	context_destroy(c);
+
+	return -1;
+}
+
+int define_initial_sid_context(void)
+{
+	char *id;
+	ocontext_t *c, *head;
+
+	if (pass == 1) {
+		id = (char *)queue_remove(id_queue);
+		free(id);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no sid name for SID context definition?");
+		return -1;
+	}
+	head = policydbp->ocontexts[OCON_ISID];
+	for (c = head; c; c = c->next) {
+		if (!strcmp(id, c->u.name))
+			break;
+	}
+
+	if (!c) {
+		yyerror2("SID %s is not defined", id);
+		free(id);
+		return -1;
+	}
+	if (c->context[0].user) {
+		yyerror2("The context for SID %s is multiply defined", id);
+		free(id);
+		return -1;
+	}
+	/* no need to keep the sid name */
+	free(id);
+
+	if (parse_security_context(&c->context[0]))
+		return -1;
+
+	return 0;
+}
+
+int define_fs_context(unsigned int major, unsigned int minor)
+{
+	ocontext_t *newc, *c, *head;
+
+	if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+		yyerror("fscon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		parse_security_context(NULL);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	newc->u.name = (char *)malloc(6);
+	if (!newc->u.name) {
+		yyerror("out of memory");
+		free(newc);
+		return -1;
+	}
+	sprintf(newc->u.name, "%02x:%02x", major, minor);
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc->u.name);
+		free(newc);
+		return -1;
+	}
+	if (parse_security_context(&newc->context[1])) {
+		context_destroy(&newc->context[0]);
+		free(newc->u.name);
+		free(newc);
+		return -1;
+	}
+	head = policydbp->ocontexts[OCON_FS];
+
+	for (c = head; c; c = c->next) {
+		if (!strcmp(newc->u.name, c->u.name)) {
+			yyerror2("duplicate entry for file system %s",
+				 newc->u.name);
+			context_destroy(&newc->context[0]);
+			context_destroy(&newc->context[1]);
+			free(newc->u.name);
+			free(newc);
+			return -1;
+		}
+	}
+
+	newc->next = head;
+	policydbp->ocontexts[OCON_FS] = newc;
+
+	return 0;
+}
+
+int define_pirq_context(unsigned int pirq)
+{
+	ocontext_t *newc, *c, *l, *head;
+	char *id;
+
+	if (policydbp->target_platform != SEPOL_TARGET_XEN) {
+		yyerror("pirqcon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		id = (char *) queue_remove(id_queue);
+		free(id);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	newc->u.pirq = pirq;
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc);
+		return -1;
+	}
+
+	head = policydbp->ocontexts[OCON_XEN_PIRQ];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		unsigned int pirq2;
+
+		pirq2 = c->u.pirq;
+		if (pirq == pirq2) {
+			yyerror2("duplicate pirqcon entry for %d ", pirq);
+			goto bad;
+		}
+	}
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_XEN_PIRQ] = newc;
+
+	return 0;
+
+bad:
+	free(newc);
+	return -1;
+}
+
+int define_iomem_context(uint64_t low, uint64_t high)
+{
+	ocontext_t *newc, *c, *l, *head;
+	char *id;
+
+	if (policydbp->target_platform != SEPOL_TARGET_XEN) {
+		yyerror("iomemcon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		id = (char *)queue_remove(id_queue);
+		free(id);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	newc->u.iomem.low_iomem  = low;
+	newc->u.iomem.high_iomem = high;
+
+	if (low > high) {
+		yyerror2("low memory 0x%"PRIx64" exceeds high memory 0x%"PRIx64"", low, high);
+		free(newc);
+		return -1;
+	}
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc);
+		return -1;
+	}
+
+	head = policydbp->ocontexts[OCON_XEN_IOMEM];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		uint64_t low2, high2;
+
+		low2 = c->u.iomem.low_iomem;
+		high2 = c->u.iomem.high_iomem;
+		if (low <= high2 && low2 <= high) {
+			yyerror2("iomemcon entry for 0x%"PRIx64"-0x%"PRIx64" overlaps with "
+				"earlier entry 0x%"PRIx64"-0x%"PRIx64"", low, high,
+				low2, high2);
+			goto bad;
+		}
+	}
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_XEN_IOMEM] = newc;
+
+	return 0;
+
+bad:
+	free(newc);
+	return -1;
+}
+
+int define_ioport_context(unsigned long low, unsigned long high)
+{
+	ocontext_t *newc, *c, *l, *head;
+	char *id;
+
+	if (policydbp->target_platform != SEPOL_TARGET_XEN) {
+		yyerror("ioportcon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		id = (char *)queue_remove(id_queue);
+		free(id);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	newc->u.ioport.low_ioport  = low;
+	newc->u.ioport.high_ioport = high;
+
+	if (low > high) {
+		yyerror2("low ioport 0x%lx exceeds high ioport 0x%lx", low, high);
+		free(newc);
+		return -1;
+	}
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc);
+		return -1;
+	}
+
+	head = policydbp->ocontexts[OCON_XEN_IOPORT];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		uint32_t low2, high2;
+
+		low2 = c->u.ioport.low_ioport;
+		high2 = c->u.ioport.high_ioport;
+		if (low <= high2 && low2 <= high) {
+			yyerror2("ioportcon entry for 0x%lx-0x%lx overlaps with"
+				"earlier entry 0x%x-0x%x", low, high,
+				low2, high2);
+			goto bad;
+		}
+	}
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_XEN_IOPORT] = newc;
+
+	return 0;
+
+bad:
+	free(newc);
+	return -1;
+}
+
+int define_pcidevice_context(unsigned long device)
+{
+	ocontext_t *newc, *c, *l, *head;
+	char *id;
+
+	if (policydbp->target_platform != SEPOL_TARGET_XEN) {
+		yyerror("pcidevicecon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		id = (char *) queue_remove(id_queue);
+		free(id);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	newc->u.device = device;
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc);
+		return -1;
+	}
+
+	head = policydbp->ocontexts[OCON_XEN_PCIDEVICE];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		unsigned int device2;
+
+		device2 = c->u.device;
+		if (device == device2) {
+			yyerror2("duplicate pcidevicecon entry for 0x%lx",
+				 device);
+			goto bad;
+		}
+	}
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_XEN_PCIDEVICE] = newc;
+
+	return 0;
+
+bad:
+	free(newc);
+	return -1;
+}
+
+int define_devicetree_context()
+{
+	ocontext_t *newc, *c, *l, *head;
+
+	if (policydbp->target_platform != SEPOL_TARGET_XEN) {
+		yyerror("devicetreecon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		free(queue_remove(id_queue));
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	newc->u.name = (char *)queue_remove(id_queue);
+	if (!newc->u.name) {
+		free(newc);
+		return -1;
+	}
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc->u.name);
+		free(newc);
+		return -1;
+	}
+
+	head = policydbp->ocontexts[OCON_XEN_DEVICETREE];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		if (strcmp(newc->u.name, c->u.name) == 0) {
+			yyerror2("duplicate devicetree entry for '%s'", newc->u.name);
+			goto bad;
+		}
+	}
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_XEN_DEVICETREE] = newc;
+
+	return 0;
+
+bad:
+	free(newc->u.name);
+	free(newc);
+	return -1;
+}
+
+int define_port_context(unsigned int low, unsigned int high)
+{
+	ocontext_t *newc, *c, *l, *head;
+	unsigned int protocol;
+	char *id;
+
+	if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+		yyerror("portcon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		id = (char *)queue_remove(id_queue);
+		free(id);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		free(newc);
+		return -1;
+	}
+	if ((strcmp(id, "tcp") == 0) || (strcmp(id, "TCP") == 0)) {
+		protocol = IPPROTO_TCP;
+	} else if ((strcmp(id, "udp") == 0) || (strcmp(id, "UDP") == 0)) {
+		protocol = IPPROTO_UDP;
+	} else if ((strcmp(id, "dccp") == 0) || (strcmp(id, "DCCP") == 0)) {
+		protocol = IPPROTO_DCCP;
+	} else {
+		yyerror2("unrecognized protocol %s", id);
+		free(newc);
+		return -1;
+	}
+
+	newc->u.port.protocol = protocol;
+	newc->u.port.low_port = low;
+	newc->u.port.high_port = high;
+
+	if (low > high) {
+		yyerror2("low port %d exceeds high port %d", low, high);
+		free(newc);
+		return -1;
+	}
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc);
+		return -1;
+	}
+
+	/* Preserve the matching order specified in the configuration. */
+	head = policydbp->ocontexts[OCON_PORT];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		unsigned int prot2, low2, high2;
+
+		prot2 = c->u.port.protocol;
+		low2 = c->u.port.low_port;
+		high2 = c->u.port.high_port;
+		if (protocol != prot2)
+			continue;
+		if (low == low2 && high == high2) {
+			yyerror2("duplicate portcon entry for %s %d-%d ", id,
+				 low, high);
+			goto bad;
+		}
+		if (low2 <= low && high2 >= high) {
+			yyerror2("portcon entry for %s %d-%d hidden by earlier "
+				 "entry for %d-%d", id, low, high, low2, high2);
+			goto bad;
+		}
+	}
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_PORT] = newc;
+
+	return 0;
+
+      bad:
+	free(newc);
+	return -1;
+}
+
+int define_netif_context(void)
+{
+	ocontext_t *newc, *c, *head;
+
+	if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+		yyerror("netifcon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		free(queue_remove(id_queue));
+		parse_security_context(NULL);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	newc->u.name = (char *)queue_remove(id_queue);
+	if (!newc->u.name) {
+		free(newc);
+		return -1;
+	}
+	if (parse_security_context(&newc->context[0])) {
+		free(newc->u.name);
+		free(newc);
+		return -1;
+	}
+	if (parse_security_context(&newc->context[1])) {
+		context_destroy(&newc->context[0]);
+		free(newc->u.name);
+		free(newc);
+		return -1;
+	}
+	head = policydbp->ocontexts[OCON_NETIF];
+
+	for (c = head; c; c = c->next) {
+		if (!strcmp(newc->u.name, c->u.name)) {
+			yyerror2("duplicate entry for network interface %s",
+				 newc->u.name);
+			context_destroy(&newc->context[0]);
+			context_destroy(&newc->context[1]);
+			free(newc->u.name);
+			free(newc);
+			return -1;
+		}
+	}
+
+	newc->next = head;
+	policydbp->ocontexts[OCON_NETIF] = newc;
+	return 0;
+}
+
+int define_ipv4_node_context()
+{	
+	char *id;
+	int rc = 0;
+	struct in_addr addr, mask;
+	ocontext_t *newc, *c, *l, *head;
+
+	if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+		yyerror("nodecon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		free(queue_remove(id_queue));
+		free(queue_remove(id_queue));
+		parse_security_context(NULL);
+		goto out;
+	}
+
+	id = queue_remove(id_queue);
+	if (!id) {
+		yyerror("failed to read ipv4 address");
+		rc = -1;
+		goto out;
+	}
+
+	rc = inet_pton(AF_INET, id, &addr);
+	free(id);
+	if (rc < 1) {
+		yyerror("failed to parse ipv4 address");
+		if (rc == 0)
+			rc = -1;
+		goto out;
+	}
+
+	id = queue_remove(id_queue);
+	if (!id) {
+		yyerror("failed to read ipv4 address");
+		rc = -1;
+		goto out;
+	}
+
+	rc = inet_pton(AF_INET, id, &mask);
+	free(id);
+	if (rc < 1) {
+		yyerror("failed to parse ipv4 mask");
+		if (rc == 0)
+			rc = -1;
+		goto out;
+	}
+
+	newc = malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		rc = -1;
+		goto out;
+	}
+
+	memset(newc, 0, sizeof(ocontext_t));
+	newc->u.node.addr = addr.s_addr;
+	newc->u.node.mask = mask.s_addr;
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc);
+		return -1;
+	}
+
+	/* Create order of most specific to least retaining
+	   the order specified in the configuration. */
+	head = policydbp->ocontexts[OCON_NODE];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		if (newc->u.node.mask > c->u.node.mask)
+			break;
+	}
+
+	newc->next = c;
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_NODE] = newc;
+	rc = 0;
+out:
+	return rc;
+}
+
+int define_ipv6_node_context(void)
+{
+	char *id;
+	int rc = 0;
+	struct in6_addr addr, mask;
+	ocontext_t *newc, *c, *l, *head;
+
+	if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+		yyerror("nodecon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		free(queue_remove(id_queue));
+		free(queue_remove(id_queue));
+		parse_security_context(NULL);
+		goto out;
+	}
+
+	id = queue_remove(id_queue);
+	if (!id) {
+		yyerror("failed to read ipv6 address");
+		rc = -1;
+		goto out;
+	}
+
+	rc = inet_pton(AF_INET6, id, &addr);
+	free(id);
+	if (rc < 1) {
+		yyerror("failed to parse ipv6 address");
+		if (rc == 0)
+			rc = -1;
+		goto out;
+	}
+
+	id = queue_remove(id_queue);
+	if (!id) {
+		yyerror("failed to read ipv6 address");
+		rc = -1;
+		goto out;
+	}
+
+	rc = inet_pton(AF_INET6, id, &mask);
+	free(id);
+	if (rc < 1) {
+		yyerror("failed to parse ipv6 mask");
+		if (rc == 0)
+			rc = -1;
+		goto out;
+	}
+
+	newc = malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		rc = -1;
+		goto out;
+	}
+
+	memset(newc, 0, sizeof(ocontext_t));
+
+#ifdef __APPLE__
+	memcpy(&newc->u.node6.addr[0], &addr.s6_addr[0], 16);
+	memcpy(&newc->u.node6.mask[0], &mask.s6_addr[0], 16);
+#else
+	memcpy(&newc->u.node6.addr[0], &addr.s6_addr32[0], 16);
+	memcpy(&newc->u.node6.mask[0], &mask.s6_addr32[0], 16);
+#endif
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc);
+		rc = -1;
+		goto out;
+	}
+
+	/* Create order of most specific to least retaining
+	   the order specified in the configuration. */
+	head = policydbp->ocontexts[OCON_NODE6];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		if (memcmp(&newc->u.node6.mask, &c->u.node6.mask, 16) > 0)
+			break;
+	}
+
+	newc->next = c;
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_NODE6] = newc;
+
+	rc = 0;
+      out:
+	return rc;
+}
+
+int define_fs_use(int behavior)
+{
+	ocontext_t *newc, *c, *head;
+
+	if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+		yyerror("fsuse not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		free(queue_remove(id_queue));
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	newc->u.name = (char *)queue_remove(id_queue);
+	if (!newc->u.name) {
+		free(newc);
+		return -1;
+	}
+	newc->v.behavior = behavior;
+	if (parse_security_context(&newc->context[0])) {
+		free(newc->u.name);
+		free(newc);
+		return -1;
+	}
+
+	head = policydbp->ocontexts[OCON_FSUSE];
+
+	for (c = head; c; c = c->next) {
+		if (!strcmp(newc->u.name, c->u.name)) {
+			yyerror2("duplicate fs_use entry for filesystem type %s",
+				 newc->u.name);
+			context_destroy(&newc->context[0]);
+			free(newc->u.name);
+			free(newc);
+			return -1;
+		}
+	}
+
+	newc->next = head;
+	policydbp->ocontexts[OCON_FSUSE] = newc;
+	return 0;
+}
+
+int define_genfs_context_helper(char *fstype, int has_type)
+{
+	struct genfs *genfs_p, *genfs, *newgenfs;
+	ocontext_t *newc, *c, *head, *p;
+	char *type = NULL;
+	int len, len2;
+
+	if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+		yyerror("genfs not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		free(fstype);
+		free(queue_remove(id_queue));
+		if (has_type)
+			free(queue_remove(id_queue));
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	for (genfs_p = NULL, genfs = policydbp->genfs;
+	     genfs; genfs_p = genfs, genfs = genfs->next) {
+		if (strcmp(fstype, genfs->fstype) <= 0)
+			break;
+	}
+
+	if (!genfs || strcmp(fstype, genfs->fstype)) {
+		newgenfs = malloc(sizeof(struct genfs));
+		if (!newgenfs) {
+			yyerror("out of memory");
+			return -1;
+		}
+		memset(newgenfs, 0, sizeof(struct genfs));
+		newgenfs->fstype = fstype;
+		newgenfs->next = genfs;
+		if (genfs_p)
+			genfs_p->next = newgenfs;
+		else
+			policydbp->genfs = newgenfs;
+		genfs = newgenfs;
+	}
+
+	newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(ocontext_t));
+
+	newc->u.name = (char *)queue_remove(id_queue);
+	if (!newc->u.name)
+		goto fail;
+	if (has_type) {
+		type = (char *)queue_remove(id_queue);
+		if (!type)
+			goto fail;
+		if (type[1] != 0) {
+			yyerror2("invalid type %s", type);
+			goto fail;
+		}
+		switch (type[0]) {
+		case 'b':
+			newc->v.sclass = SECCLASS_BLK_FILE;
+			break;
+		case 'c':
+			newc->v.sclass = SECCLASS_CHR_FILE;
+			break;
+		case 'd':
+			newc->v.sclass = SECCLASS_DIR;
+			break;
+		case 'p':
+			newc->v.sclass = SECCLASS_FIFO_FILE;
+			break;
+		case 'l':
+			newc->v.sclass = SECCLASS_LNK_FILE;
+			break;
+		case 's':
+			newc->v.sclass = SECCLASS_SOCK_FILE;
+			break;
+		case '-':
+			newc->v.sclass = SECCLASS_FILE;
+			break;
+		default:
+			yyerror2("invalid type %s", type);
+			goto fail;
+		}
+	}
+	if (parse_security_context(&newc->context[0]))
+		goto fail;
+
+	head = genfs->head;
+
+	for (p = NULL, c = head; c; p = c, c = c->next) {
+		if (!strcmp(newc->u.name, c->u.name) &&
+		    (!newc->v.sclass || !c->v.sclass
+		     || newc->v.sclass == c->v.sclass)) {
+			yyerror2("duplicate entry for genfs entry (%s, %s)",
+				 fstype, newc->u.name);
+			goto fail;
+		}
+		len = strlen(newc->u.name);
+		len2 = strlen(c->u.name);
+		if (len > len2)
+			break;
+	}
+
+	newc->next = c;
+	if (p)
+		p->next = newc;
+	else
+		genfs->head = newc;
+	return 0;
+      fail:
+	if (type)
+		free(type);
+	context_destroy(&newc->context[0]);
+	if (fstype)
+		free(fstype);
+	if (newc->u.name)
+		free(newc->u.name);
+	free(newc);
+	return -1;
+}
+
+int define_genfs_context(int has_type)
+{
+	return define_genfs_context_helper(queue_remove(id_queue), has_type);
+}
+
+int define_range_trans(int class_specified)
+{
+	char *id;
+	level_datum_t *levdatum = 0;
+	class_datum_t *cladatum;
+	range_trans_rule_t *rule;
+	int l, add = 1;
+
+	if (!mlspol) {
+		yyerror("range_transition rule in non-MLS configuration");
+		return -1;
+	}
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		if (class_specified)
+			while ((id = queue_remove(id_queue)))
+				free(id);
+		id = queue_remove(id_queue);
+		free(id);
+		for (l = 0; l < 2; l++) {
+			while ((id = queue_remove(id_queue))) {
+				free(id);
+			}
+			id = queue_remove(id_queue);
+			if (!id)
+				break;
+			free(id);
+		}
+		return 0;
+	}
+
+	rule = malloc(sizeof(struct range_trans_rule));
+	if (!rule) {
+		yyerror("out of memory");
+		return -1;
+	}
+	range_trans_rule_init(rule);
+
+	while ((id = queue_remove(id_queue))) {
+		if (set_types(&rule->stypes, id, &add, 0))
+			goto out;
+	}
+	add = 1;
+	while ((id = queue_remove(id_queue))) {
+		if (set_types(&rule->ttypes, id, &add, 0))
+			goto out;
+	}
+
+	if (class_specified) {
+		if (read_classes(&rule->tclasses))
+			goto out;
+	} else {
+		cladatum = hashtab_search(policydbp->p_classes.table,
+		                          "process");
+		if (!cladatum) {
+			yyerror2("could not find process class for "
+			         "legacy range_transition statement");
+			goto out;
+		}
+
+		if (ebitmap_set_bit(&rule->tclasses, cladatum->s.value - 1, TRUE)) {
+			yyerror("out of memory");
+			goto out;
+		}
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no range in range_transition definition?");
+		goto out;
+	}
+	for (l = 0; l < 2; l++) {
+		levdatum = hashtab_search(policydbp->p_levels.table, id);
+		if (!levdatum) {
+			yyerror2("unknown level %s used in range_transition "
+			         "definition", id);
+			free(id);
+			goto out;
+		}
+		free(id);
+
+		rule->trange.level[l].sens = levdatum->level->sens;
+
+		while ((id = queue_remove(id_queue))) {
+			if (parse_semantic_categories(id, levdatum,
+			                          &rule->trange.level[l].cat)) {
+				free(id);
+				goto out;
+			}
+			free(id);
+		}
+
+		id = (char *)queue_remove(id_queue);
+		if (!id)
+			break;
+	}
+	if (l == 0) {
+		if (mls_semantic_level_cpy(&rule->trange.level[1],
+		                           &rule->trange.level[0])) {
+			yyerror("out of memory");
+			goto out;
+		}
+	}
+
+	append_range_trans(rule);
+	return 0;
+
+out:
+	range_trans_rule_destroy(rule);
+	free(rule);
+	return -1;
+}
+
+/* FLASK */
diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
new file mode 100644
index 0000000..964baae
--- /dev/null
+++ b/checkpolicy/policy_define.h
@@ -0,0 +1,74 @@
+/* Functions used to define policy grammar components. */
+
+#ifndef _POLICY_DEFINE_H_
+#define _POLICY_DEFINE_H_
+
+/* 
+ * We need the following so we have a valid error return code in yacc
+ * when we have a parse error for a conditional rule.  We can't check 
+ * for NULL (ie 0) because that is a potentially valid return.
+ */
+#define COND_ERR ((avrule_t *)-1)
+#define TRUE 1
+#define FALSE 0
+
+avrule_t *define_cond_compute_type(int which);
+avrule_t *define_cond_pol_list(avrule_t *avlist, avrule_t *stmt);
+avrule_t *define_cond_te_avtab(int which);
+avrule_t *define_cond_filename_trans(void);
+cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void* arg2);
+int define_attrib(void);
+int define_attrib_role(void);
+int define_av_perms(int inherits);
+int define_bool_tunable(int is_tunable);
+int define_category(void);
+int define_class(void);
+int define_default_user(int which);
+int define_default_role(int which);
+int define_default_type(int which);
+int define_default_range(int which);
+int define_common_perms(void);
+int define_compute_type(int which);
+int define_conditional(cond_expr_t *expr, avrule_t *t_list, avrule_t *f_list );
+int define_constraint(constraint_expr_t *expr);
+int define_dominance(void);
+int define_fs_context(unsigned int major, unsigned int minor);
+int define_fs_use(int behavior);
+int define_genfs_context(int has_type);
+int define_initial_sid_context(void);
+int define_initial_sid(void);
+int define_ipv4_node_context(void);
+int define_ipv6_node_context(void);
+int define_level(void);
+int define_netif_context(void);
+int define_permissive(void);
+int define_polcap(void);
+int define_port_context(unsigned int low, unsigned int high);
+int define_pirq_context(unsigned int pirq);
+int define_iomem_context(uint64_t low, uint64_t high);
+int define_ioport_context(unsigned long low, unsigned long high);
+int define_pcidevice_context(unsigned long device);
+int define_devicetree_context(void);
+int define_range_trans(int class_specified);
+int define_role_allow(void);
+int define_role_trans(int class_specified);
+int define_role_types(void);
+int define_role_attr(void);
+int define_roleattribute(void);
+int define_filename_trans(void);
+int define_sens(void);
+int define_te_avtab(int which);
+int define_te_avtab_extended_perms(int which);
+int define_typealias(void);
+int define_typeattribute(void);
+int define_typebounds(void);
+int define_type(int alias);
+int define_user(void);
+int define_validatetrans(constraint_expr_t *expr);
+int insert_id(const char *id,int push);
+int insert_separator(int push);
+role_datum_t *define_role_dom(role_datum_t *r);
+role_datum_t *merge_roles_dom(role_datum_t *r1,role_datum_t *r2);
+uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2);
+
+#endif /* _POLICY_DEFINE_H_ */
diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
new file mode 100644
index 0000000..3b6a2f8
--- /dev/null
+++ b/checkpolicy/policy_parse.y
@@ -0,0 +1,949 @@
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Updated: David Caplan, <dac@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Updated: Joshua Brindle <jbrindle@tresys.com>
+ *	    Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *          Jason Tang     <jtang@tresys.com>
+ *
+ *	Added support for binary policy modules
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2008 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat Inc.
+ *	This program is free software; you can redistribute it and/or modify
+ *  	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, version 2.
+ */
+
+/* FLASK */
+
+%{
+#include <sys/types.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/polcaps.h>
+#include "queue.h"
+#include "checkpolicy.h"
+#include "module_compiler.h"
+#include "policy_define.h"
+
+extern policydb_t *policydbp;
+extern unsigned int pass;
+
+extern char yytext[];
+extern int yylex(void);
+extern int yywarn(const char *msg);
+extern int yyerror(const char *msg);
+
+typedef int (* require_func_t)(int pass);
+
+%}
+
+%union {
+	unsigned int val;
+	uint64_t val64;
+	uintptr_t valptr;
+	void *ptr;
+        require_func_t require_func;
+}
+
+%type <ptr> cond_expr cond_expr_prim cond_pol_list cond_else
+%type <ptr> cond_allow_def cond_auditallow_def cond_auditdeny_def cond_dontaudit_def
+%type <ptr> cond_transition_def cond_te_avtab_def cond_rule_def
+%type <ptr> role_def roles
+%type <valptr> cexpr cexpr_prim op role_mls_op
+%type <val> ipv4_addr_def number
+%type <val64> number64
+%type <require_func> require_decl_def
+
+%token PATH
+%token QPATH
+%token FILENAME
+%token CLONE
+%token COMMON
+%token CLASS
+%token CONSTRAIN
+%token VALIDATETRANS
+%token INHERITS
+%token SID
+%token ROLE
+%token ROLEATTRIBUTE
+%token ATTRIBUTE_ROLE
+%token ROLES
+%token TYPEALIAS
+%token TYPEATTRIBUTE
+%token TYPEBOUNDS
+%token TYPE
+%token TYPES
+%token ALIAS
+%token ATTRIBUTE
+%token BOOL
+%token TUNABLE
+%token IF
+%token ELSE
+%token TYPE_TRANSITION
+%token TYPE_MEMBER
+%token TYPE_CHANGE
+%token ROLE_TRANSITION
+%token RANGE_TRANSITION
+%token SENSITIVITY
+%token DOMINANCE
+%token DOM DOMBY INCOMP
+%token CATEGORY
+%token LEVEL
+%token RANGE
+%token MLSCONSTRAIN
+%token MLSVALIDATETRANS
+%token USER
+%token NEVERALLOW
+%token ALLOW
+%token AUDITALLOW
+%token AUDITDENY
+%token DONTAUDIT
+%token ALLOWXPERM
+%token AUDITALLOWXPERM
+%token DONTAUDITXPERM
+%token NEVERALLOWXPERM
+%token SOURCE
+%token TARGET
+%token SAMEUSER
+%token FSCON PORTCON NETIFCON NODECON 
+%token PIRQCON IOMEMCON IOPORTCON PCIDEVICECON DEVICETREECON
+%token FSUSEXATTR FSUSETASK FSUSETRANS
+%token GENFSCON
+%token U1 U2 U3 R1 R2 R3 T1 T2 T3 L1 L2 H1 H2
+%token NOT AND OR XOR
+%token CTRUE CFALSE
+%token IDENTIFIER
+%token NUMBER
+%token EQUALS
+%token NOTEQUAL
+%token IPV4_ADDR
+%token IPV6_ADDR
+%token MODULE VERSION_IDENTIFIER REQUIRE OPTIONAL
+%token POLICYCAP
+%token PERMISSIVE
+%token FILESYSTEM
+%token DEFAULT_USER DEFAULT_ROLE DEFAULT_TYPE DEFAULT_RANGE
+%token LOW_HIGH LOW HIGH
+
+%left OR
+%left XOR
+%left AND
+%right NOT
+%left EQUALS NOTEQUAL
+%%
+policy			: base_policy
+                        | module_policy
+                        ;
+base_policy             : { if (define_policy(pass, 0) == -1) return -1; }
+                          classes initial_sids access_vectors
+                          { if (pass == 1) { if (policydb_index_classes(policydbp)) return -1; }
+                            else if (pass == 2) { if (policydb_index_others(NULL, policydbp, 0)) return -1; }}
+			  opt_default_rules opt_mls te_rbac users opt_constraints 
+                         { if (pass == 1) { if (policydb_index_bools(policydbp)) return -1;}
+			   else if (pass == 2) { if (policydb_index_others(NULL, policydbp, 0)) return -1;}}
+			  initial_sid_contexts opt_fs_contexts opt_fs_uses opt_genfs_contexts net_contexts opt_dev_contexts
+			;
+classes			: class_def 
+			| classes class_def
+			;
+class_def		: CLASS identifier
+			{if (define_class()) return -1;}
+			;
+initial_sids 		: initial_sid_def 
+			| initial_sids initial_sid_def
+			;
+initial_sid_def		: SID identifier
+                        {if (define_initial_sid()) return -1;}
+			;
+access_vectors		: opt_common_perms av_perms
+			;
+opt_common_perms        : common_perms
+                        |
+                        ;
+common_perms		: common_perms_def
+			| common_perms common_perms_def
+			;
+common_perms_def	: COMMON identifier '{' identifier_list '}'
+			{if (define_common_perms()) return -1;}
+			;
+av_perms		: av_perms_def
+			| av_perms av_perms_def
+			;
+av_perms_def		: CLASS identifier '{' identifier_list '}'
+			{if (define_av_perms(FALSE)) return -1;}
+                        | CLASS identifier INHERITS identifier 
+			{if (define_av_perms(TRUE)) return -1;}
+                        | CLASS identifier INHERITS identifier '{' identifier_list '}'
+			{if (define_av_perms(TRUE)) return -1;}
+			;
+opt_default_rules	: default_rules
+			|
+			;
+default_rules		: default_user_def
+			| default_role_def
+			| default_type_def
+			| default_range_def
+			| default_rules default_user_def
+			| default_rules default_role_def
+			| default_rules default_type_def
+			| default_rules default_range_def
+			;
+default_user_def	: DEFAULT_USER names SOURCE ';'
+			{if (define_default_user(DEFAULT_SOURCE)) return -1; }
+			| DEFAULT_USER names TARGET ';'
+			{if (define_default_user(DEFAULT_TARGET)) return -1; }
+			;
+default_role_def	: DEFAULT_ROLE names SOURCE ';'
+			{if (define_default_role(DEFAULT_SOURCE)) return -1; }
+			| DEFAULT_ROLE names TARGET ';'
+			{if (define_default_role(DEFAULT_TARGET)) return -1; }
+			;
+default_type_def	: DEFAULT_TYPE names SOURCE ';'
+			{if (define_default_type(DEFAULT_SOURCE)) return -1; }
+			| DEFAULT_TYPE names TARGET ';'
+			{if (define_default_type(DEFAULT_TARGET)) return -1; }
+			;
+default_range_def	: DEFAULT_RANGE names SOURCE LOW ';'
+			{if (define_default_range(DEFAULT_SOURCE_LOW)) return -1; }
+			| DEFAULT_RANGE names SOURCE HIGH ';'
+			{if (define_default_range(DEFAULT_SOURCE_HIGH)) return -1; }
+			| DEFAULT_RANGE names SOURCE LOW_HIGH ';'
+			{if (define_default_range(DEFAULT_SOURCE_LOW_HIGH)) return -1; }
+			| DEFAULT_RANGE names TARGET LOW ';'
+			{if (define_default_range(DEFAULT_TARGET_LOW)) return -1; }
+			| DEFAULT_RANGE names TARGET HIGH ';'
+			{if (define_default_range(DEFAULT_TARGET_HIGH)) return -1; }
+			| DEFAULT_RANGE names TARGET LOW_HIGH ';'
+			{if (define_default_range(DEFAULT_TARGET_LOW_HIGH)) return -1; }
+			;
+opt_mls			: mls
+                        | 
+			;
+mls			: sensitivities dominance opt_categories levels mlspolicy
+			;
+sensitivities	 	: sensitivity_def 
+			| sensitivities sensitivity_def
+			;
+sensitivity_def		: SENSITIVITY identifier alias_def ';'
+			{if (define_sens()) return -1;}
+			| SENSITIVITY identifier ';'
+			{if (define_sens()) return -1;}
+	                ;
+alias_def		: ALIAS names
+			;
+dominance		: DOMINANCE identifier 
+			{if (define_dominance()) return -1;}
+                        | DOMINANCE '{' identifier_list '}' 
+			{if (define_dominance()) return -1;}
+			;
+opt_categories          : categories
+                        |
+                        ;
+categories 		: category_def 
+			| categories category_def
+			;
+category_def		: CATEGORY identifier alias_def ';'
+			{if (define_category()) return -1;}
+			| CATEGORY identifier ';'
+			{if (define_category()) return -1;}
+			;
+levels	 		: level_def 
+			| levels level_def
+			;
+level_def		: LEVEL identifier ':' id_comma_list ';'
+			{if (define_level()) return -1;}
+			| LEVEL identifier ';' 
+			{if (define_level()) return -1;}
+			;
+mlspolicy		: mlspolicy_decl
+			| mlspolicy mlspolicy_decl
+			;
+mlspolicy_decl		: mlsconstraint_def
+			| mlsvalidatetrans_def
+			;
+mlsconstraint_def	: MLSCONSTRAIN names names cexpr ';'
+			{ if (define_constraint((constraint_expr_t*)$4)) return -1; }
+			;
+mlsvalidatetrans_def	: MLSVALIDATETRANS names cexpr ';'
+			{ if (define_validatetrans((constraint_expr_t*)$3)) return -1; }
+			;
+te_rbac			: te_rbac_decl
+			| te_rbac te_rbac_decl
+			;
+te_rbac_decl		: te_decl
+			| rbac_decl
+                        | cond_stmt_def
+			| optional_block
+			| policycap_def
+			| ';'
+                        ;
+rbac_decl		: attribute_role_def
+			| role_type_def
+                        | role_dominance
+                        | role_trans_def
+ 			| role_allow_def
+			| roleattribute_def
+			| role_attr_def
+			;
+te_decl			: attribute_def
+                        | type_def
+                        | typealias_def
+                        | typeattribute_def
+                        | typebounds_def
+                        | bool_def
+			| tunable_def
+                        | transition_def
+                        | range_trans_def
+                        | te_avtab_def
+			| permissive_def
+			;
+attribute_def           : ATTRIBUTE identifier ';'
+                        { if (define_attrib()) return -1;}
+                        ;
+type_def		: TYPE identifier alias_def opt_attr_list ';'
+                        {if (define_type(1)) return -1;}
+	                | TYPE identifier opt_attr_list ';'
+                        {if (define_type(0)) return -1;}
+    			;
+typealias_def           : TYPEALIAS identifier alias_def ';'
+			{if (define_typealias()) return -1;}
+			;
+typeattribute_def	: TYPEATTRIBUTE identifier id_comma_list ';'
+			{if (define_typeattribute()) return -1;}
+			;
+typebounds_def          : TYPEBOUNDS identifier id_comma_list ';'
+                        {if (define_typebounds()) return -1;}
+                        ;
+opt_attr_list           : ',' id_comma_list
+			| 
+			;
+bool_def                : BOOL identifier bool_val ';'
+                        { if (define_bool_tunable(0)) return -1; }
+                        ;
+tunable_def		: TUNABLE identifier bool_val ';'
+			{ if (define_bool_tunable(1)) return -1; }
+			;
+bool_val                : CTRUE
+ 			{ if (insert_id("T",0)) return -1; }
+                        | CFALSE
+			{ if (insert_id("F",0)) return -1; }
+                        ;
+cond_stmt_def           : IF cond_expr '{' cond_pol_list '}' cond_else
+                        { if (pass == 2) { if (define_conditional((cond_expr_t*)$2, (avrule_t*)$4, (avrule_t*)$6) < 0) return -1;  }}
+                        ;
+cond_else		: ELSE '{' cond_pol_list '}'
+			{ $$ = $3; }
+			| /* empty */ 
+			{ $$ = NULL; }
+			;
+cond_expr               : '(' cond_expr ')'
+			{ $$ = $2;}
+			| NOT cond_expr
+			{ $$ = define_cond_expr(COND_NOT, $2, 0);
+			  if ($$ == 0) return -1; }
+			| cond_expr AND cond_expr
+			{ $$ = define_cond_expr(COND_AND, $1, $3);
+			  if ($$ == 0) return  -1; }
+			| cond_expr OR cond_expr
+			{ $$ = define_cond_expr(COND_OR, $1, $3);
+			  if ($$ == 0) return   -1; }
+			| cond_expr XOR cond_expr
+			{ $$ = define_cond_expr(COND_XOR, $1, $3);
+			  if ($$ == 0) return  -1; }
+			| cond_expr EQUALS cond_expr
+			{ $$ = define_cond_expr(COND_EQ, $1, $3);
+			  if ($$ == 0) return  -1; }
+			| cond_expr NOTEQUAL cond_expr
+			{ $$ = define_cond_expr(COND_NEQ, $1, $3);
+			  if ($$ == 0) return  -1; }
+			| cond_expr_prim
+			{ $$ = $1; }
+			;
+cond_expr_prim          : identifier
+                        { $$ = define_cond_expr(COND_BOOL,0, 0);
+			  if ($$ == COND_ERR) return   -1; }
+                        ;
+cond_pol_list           : cond_pol_list cond_rule_def 
+                        { $$ = define_cond_pol_list((avrule_t *)$1, (avrule_t *)$2); }
+			| /* empty */ 
+			{ $$ = NULL; }
+			;
+cond_rule_def           : cond_transition_def
+                        { $$ = $1; }
+                        | cond_te_avtab_def
+                        { $$ = $1; }
+			| require_block
+			{ $$ = NULL; }
+                        ;
+cond_transition_def	: TYPE_TRANSITION names names ':' names identifier filename ';'
+                        { $$ = define_cond_filename_trans() ;
+                          if ($$ == COND_ERR) return -1;}
+			| TYPE_TRANSITION names names ':' names identifier ';'
+                        { $$ = define_cond_compute_type(AVRULE_TRANSITION) ;
+                          if ($$ == COND_ERR) return -1;}
+                        | TYPE_MEMBER names names ':' names identifier ';'
+                        { $$ = define_cond_compute_type(AVRULE_MEMBER) ;
+                          if ($$ ==  COND_ERR) return -1;}
+                        | TYPE_CHANGE names names ':' names identifier ';'
+                        { $$ = define_cond_compute_type(AVRULE_CHANGE) ;
+                          if ($$ == COND_ERR) return -1;}
+    			;
+cond_te_avtab_def	: cond_allow_def
+                          { $$ = $1; }
+			| cond_auditallow_def
+			  { $$ = $1; }
+			| cond_auditdeny_def
+			  { $$ = $1; }
+			| cond_dontaudit_def
+			  { $$ = $1; }
+			;
+cond_allow_def		: ALLOW names names ':' names names  ';'
+			{ $$ = define_cond_te_avtab(AVRULE_ALLOWED) ;
+                          if ($$ == COND_ERR) return -1; }
+		        ;
+cond_auditallow_def	: AUDITALLOW names names ':' names names ';'
+			{ $$ = define_cond_te_avtab(AVRULE_AUDITALLOW) ;
+                          if ($$ == COND_ERR) return -1; }
+		        ;
+cond_auditdeny_def	: AUDITDENY names names ':' names names ';'
+			{ $$ = define_cond_te_avtab(AVRULE_AUDITDENY) ;
+                          if ($$ == COND_ERR) return -1; }
+		        ;
+cond_dontaudit_def	: DONTAUDIT names names ':' names names ';'
+			{ $$ = define_cond_te_avtab(AVRULE_DONTAUDIT);
+                          if ($$ == COND_ERR) return -1; }
+		        ;
+			;
+transition_def		: TYPE_TRANSITION  names names ':' names identifier filename ';'
+			{if (define_filename_trans()) return -1; }
+			| TYPE_TRANSITION names names ':' names identifier ';'
+                        {if (define_compute_type(AVRULE_TRANSITION)) return -1;}
+                        | TYPE_MEMBER names names ':' names identifier ';'
+                        {if (define_compute_type(AVRULE_MEMBER)) return -1;}
+                        | TYPE_CHANGE names names ':' names identifier ';'
+                        {if (define_compute_type(AVRULE_CHANGE)) return -1;}
+    			;
+range_trans_def		: RANGE_TRANSITION names names mls_range_def ';'
+			{ if (define_range_trans(0)) return -1; }
+			| RANGE_TRANSITION names names ':' names mls_range_def ';'
+			{ if (define_range_trans(1)) return -1; }
+			;
+te_avtab_def		: allow_def
+			| auditallow_def
+			| auditdeny_def
+			| dontaudit_def
+			| neverallow_def
+			| xperm_allow_def
+			| xperm_auditallow_def
+			| xperm_dontaudit_def
+			| xperm_neverallow_def
+			;
+allow_def		: ALLOW names names ':' names names  ';'
+			{if (define_te_avtab(AVRULE_ALLOWED)) return -1; }
+		        ;
+auditallow_def		: AUDITALLOW names names ':' names names ';'
+			{if (define_te_avtab(AVRULE_AUDITALLOW)) return -1; }
+		        ;
+auditdeny_def		: AUDITDENY names names ':' names names ';'
+			{if (define_te_avtab(AVRULE_AUDITDENY)) return -1; }
+		        ;
+dontaudit_def		: DONTAUDIT names names ':' names names ';'
+			{if (define_te_avtab(AVRULE_DONTAUDIT)) return -1; }
+		        ;
+neverallow_def		: NEVERALLOW names names ':' names names  ';'
+			{if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; }
+		        ;
+xperm_allow_def		: ALLOWXPERM names names ':' names identifier xperms ';'
+			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_ALLOWED)) return -1; }
+		        ;
+xperm_auditallow_def	: AUDITALLOWXPERM names names ':' names identifier xperms ';'
+			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_AUDITALLOW)) return -1; }
+		        ;
+xperm_dontaudit_def	: DONTAUDITXPERM names names ':' names identifier xperms ';'
+			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_DONTAUDIT)) return -1; }
+		        ;
+xperm_neverallow_def	: NEVERALLOWXPERM names names ':' names identifier xperms ';'
+			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_NEVERALLOW)) return -1; }
+		        ;
+attribute_role_def	: ATTRIBUTE_ROLE identifier ';'
+			{if (define_attrib_role()) return -1; }
+		        ;
+role_type_def		: ROLE identifier TYPES names ';'
+			{if (define_role_types()) return -1;}
+			;
+role_attr_def		: ROLE identifier opt_attr_list ';'
+ 			{if (define_role_attr()) return -1;}
+                        ;
+role_dominance		: DOMINANCE '{' roles '}'
+			;
+role_trans_def		: ROLE_TRANSITION names names identifier ';'
+			{if (define_role_trans(0)) return -1; }
+			| ROLE_TRANSITION names names ':' names identifier ';'
+			{if (define_role_trans(1)) return -1;}
+			;
+role_allow_def		: ALLOW names names ';'
+			{if (define_role_allow()) return -1; }
+			;
+roles			: role_def
+			{ $$ = $1; }
+			| roles role_def
+			{ $$ = merge_roles_dom((role_datum_t*)$1, (role_datum_t*)$2); if ($$ == 0) return -1;}
+			;
+role_def		: ROLE identifier_push ';'
+                        {$$ = define_role_dom(NULL); if ($$ == 0) return -1;}
+			| ROLE identifier_push '{' roles '}'
+                        {$$ = define_role_dom((role_datum_t*)$4); if ($$ == 0) return -1;}
+			;
+roleattribute_def	: ROLEATTRIBUTE identifier id_comma_list ';'
+			{if (define_roleattribute()) return -1;}
+			;
+opt_constraints         : constraints
+                        |
+                        ;
+constraints		: constraint_decl
+			| constraints constraint_decl
+			;
+constraint_decl		: constraint_def
+			| validatetrans_def
+			;
+constraint_def		: CONSTRAIN names names cexpr ';'
+			{ if (define_constraint((constraint_expr_t*)$4)) return -1; }
+			;
+validatetrans_def	: VALIDATETRANS names cexpr ';'
+			{ if (define_validatetrans((constraint_expr_t*)$3)) return -1; }
+			;
+cexpr			: '(' cexpr ')'
+			{ $$ = $2; }
+			| NOT cexpr
+			{ $$ = define_cexpr(CEXPR_NOT, $2, 0);
+			  if ($$ == 0) return -1; }
+			| cexpr AND cexpr
+			{ $$ = define_cexpr(CEXPR_AND, $1, $3);
+			  if ($$ == 0) return -1; }
+			| cexpr OR cexpr
+			{ $$ = define_cexpr(CEXPR_OR, $1, $3);
+			  if ($$ == 0) return -1; }
+			| cexpr_prim
+			{ $$ = $1; }
+			;
+cexpr_prim		: U1 op U2
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_USER, $2);
+			  if ($$ == 0) return -1; }
+			| R1 role_mls_op R2
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_ROLE, $2);
+			  if ($$ == 0) return -1; }
+			| T1 op T2
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_TYPE, $2);
+			  if ($$ == 0) return -1; }
+			| U1 op { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, CEXPR_USER, $2);
+			  if ($$ == 0) return -1; }
+			| U2 op { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, (CEXPR_USER | CEXPR_TARGET), $2);
+			  if ($$ == 0) return -1; }
+			| U3 op { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, (CEXPR_USER | CEXPR_XTARGET), $2);
+			  if ($$ == 0) return -1; }
+			| R1 op { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, CEXPR_ROLE, $2);
+			  if ($$ == 0) return -1; }
+			| R2 op { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, (CEXPR_ROLE | CEXPR_TARGET), $2);
+			  if ($$ == 0) return -1; }
+			| R3 op { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, (CEXPR_ROLE | CEXPR_XTARGET), $2);
+			  if ($$ == 0) return -1; }
+			| T1 op { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, CEXPR_TYPE, $2);
+			  if ($$ == 0) return -1; }
+			| T2 op { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, (CEXPR_TYPE | CEXPR_TARGET), $2);
+			  if ($$ == 0) return -1; }
+			| T3 op { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, (CEXPR_TYPE | CEXPR_XTARGET), $2);
+			  if ($$ == 0) return -1; }
+			| SAMEUSER
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_USER, CEXPR_EQ);
+			  if ($$ == 0) return -1; }
+			| SOURCE ROLE { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, CEXPR_ROLE, CEXPR_EQ);
+			  if ($$ == 0) return -1; }
+			| TARGET ROLE { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, (CEXPR_ROLE | CEXPR_TARGET), CEXPR_EQ);
+			  if ($$ == 0) return -1; }
+			| ROLE role_mls_op
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_ROLE, $2);
+			  if ($$ == 0) return -1; }
+			| SOURCE TYPE { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, CEXPR_TYPE, CEXPR_EQ);
+			  if ($$ == 0) return -1; }
+			| TARGET TYPE { if (insert_separator(1)) return -1; } names_push
+			{ $$ = define_cexpr(CEXPR_NAMES, (CEXPR_TYPE | CEXPR_TARGET), CEXPR_EQ);
+			  if ($$ == 0) return -1; }
+			| L1 role_mls_op L2
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_L1L2, $2);
+			  if ($$ == 0) return -1; }
+			| L1 role_mls_op H2
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_L1H2, $2);
+			  if ($$ == 0) return -1; }
+			| H1 role_mls_op L2
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_H1L2, $2);
+			  if ($$ == 0) return -1; }
+			| H1 role_mls_op H2
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_H1H2, $2);
+			  if ($$ == 0) return -1; }
+			| L1 role_mls_op H1
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_L1H1, $2);
+			  if ($$ == 0) return -1; }
+			| L2 role_mls_op H2
+			{ $$ = define_cexpr(CEXPR_ATTR, CEXPR_L2H2, $2);
+			  if ($$ == 0) return -1; }
+			;
+op			: EQUALS
+			{ $$ = CEXPR_EQ; }
+			| NOTEQUAL
+			{ $$ = CEXPR_NEQ; }
+			;
+role_mls_op		: op
+			{ $$ = $1; }
+			| DOM
+			{ $$ = CEXPR_DOM; }
+			| DOMBY
+			{ $$ = CEXPR_DOMBY; }
+			| INCOMP
+			{ $$ = CEXPR_INCOMP; }
+			;
+users			: user_def
+			| users user_def
+			;
+user_def		: USER identifier ROLES names opt_mls_user ';'
+	                {if (define_user()) return -1;}
+			;
+opt_mls_user		: LEVEL mls_level_def RANGE mls_range_def
+			|
+			;
+initial_sid_contexts	: initial_sid_context_def
+			| initial_sid_contexts initial_sid_context_def
+			;
+initial_sid_context_def	: SID identifier security_context_def
+			{if (define_initial_sid_context()) return -1;}
+			;
+opt_dev_contexts	: dev_contexts |
+			;
+dev_contexts		: dev_context_def
+			| dev_contexts dev_context_def
+			;
+dev_context_def		: pirq_context_def |
+			  iomem_context_def |
+			  ioport_context_def |
+			  pci_context_def |
+			  dtree_context_def
+			;
+pirq_context_def 	: PIRQCON number security_context_def
+		        {if (define_pirq_context($2)) return -1;}
+		        ;
+iomem_context_def	: IOMEMCON number64 security_context_def
+		        {if (define_iomem_context($2,$2)) return -1;}
+		        | IOMEMCON number64 '-' number64 security_context_def
+		        {if (define_iomem_context($2,$4)) return -1;}
+		        ;
+ioport_context_def	: IOPORTCON number security_context_def
+			{if (define_ioport_context($2,$2)) return -1;}
+			| IOPORTCON number '-' number security_context_def
+			{if (define_ioport_context($2,$4)) return -1;}
+			;
+pci_context_def  	: PCIDEVICECON number security_context_def
+		        {if (define_pcidevice_context($2)) return -1;}
+		        ;
+dtree_context_def	: DEVICETREECON path security_context_def
+		        {if (define_devicetree_context()) return -1;}
+		        ;
+opt_fs_contexts         : fs_contexts 
+                        |
+                        ;
+fs_contexts		: fs_context_def
+			| fs_contexts fs_context_def
+			;
+fs_context_def		: FSCON number number security_context_def security_context_def
+			{if (define_fs_context($2,$3)) return -1;}
+			;
+net_contexts		: opt_port_contexts opt_netif_contexts opt_node_contexts 
+			;
+opt_port_contexts       : port_contexts
+                        |
+                        ;
+port_contexts		: port_context_def
+			| port_contexts port_context_def
+			;
+port_context_def	: PORTCON identifier number security_context_def
+			{if (define_port_context($3,$3)) return -1;}
+			| PORTCON identifier number '-' number security_context_def
+			{if (define_port_context($3,$5)) return -1;}
+			;
+opt_netif_contexts      : netif_contexts 
+                        |
+                        ;
+netif_contexts		: netif_context_def
+			| netif_contexts netif_context_def
+			;
+netif_context_def	: NETIFCON identifier security_context_def security_context_def
+			{if (define_netif_context()) return -1;} 
+			;
+opt_node_contexts       : node_contexts 
+                        |
+                        ;
+node_contexts		: node_context_def
+			| node_contexts node_context_def
+			;
+node_context_def	: NODECON ipv4_addr_def ipv4_addr_def security_context_def
+			{if (define_ipv4_node_context()) return -1;}
+			| NODECON ipv6_addr ipv6_addr security_context_def
+			{if (define_ipv6_node_context()) return -1;}
+			;
+opt_fs_uses             : fs_uses
+                        |
+                        ;
+fs_uses                 : fs_use_def
+                        | fs_uses fs_use_def
+                        ;
+fs_use_def              : FSUSEXATTR filesystem security_context_def ';'
+                        {if (define_fs_use(SECURITY_FS_USE_XATTR)) return -1;}
+                        | FSUSETASK identifier security_context_def ';'
+                        {if (define_fs_use(SECURITY_FS_USE_TASK)) return -1;}
+                        | FSUSETRANS identifier security_context_def ';'
+                        {if (define_fs_use(SECURITY_FS_USE_TRANS)) return -1;}
+                        ;
+opt_genfs_contexts      : genfs_contexts
+                        |
+                        ;
+genfs_contexts          : genfs_context_def
+                        | genfs_contexts genfs_context_def
+                        ;
+genfs_context_def	: GENFSCON filesystem path '-' identifier security_context_def
+			{if (define_genfs_context(1)) return -1;}
+			| GENFSCON filesystem path '-' '-' {insert_id("-", 0);} security_context_def
+			{if (define_genfs_context(1)) return -1;}
+                        | GENFSCON filesystem path security_context_def
+			{if (define_genfs_context(0)) return -1;}
+			;
+ipv4_addr_def		: IPV4_ADDR
+			{ if (insert_id(yytext,0)) return -1; }
+			;
+xperms		: xperm
+			{ if (insert_separator(0)) return -1; }
+			| nested_xperm_set
+			{ if (insert_separator(0)) return -1; }
+			| tilde xperm
+                        { if (insert_id("~", 0)) return -1; }
+			| tilde nested_xperm_set
+			{ if (insert_id("~", 0)) return -1;
+			  if (insert_separator(0)) return -1; }
+			;
+nested_xperm_set	: '{' nested_xperm_list '}'
+			;
+nested_xperm_list	: nested_xperm_element
+			| nested_xperm_list nested_xperm_element
+			;
+nested_xperm_element: xperm '-' { if (insert_id("-", 0)) return -1; } xperm
+			| xperm
+			| nested_xperm_set
+			;
+xperm		: number
+                        { if (insert_id(yytext,0)) return -1; }
+			;
+security_context_def	: identifier ':' identifier ':' identifier opt_mls_range_def
+	                ;
+opt_mls_range_def	: ':' mls_range_def
+			|	
+			;
+mls_range_def		: mls_level_def '-' mls_level_def
+			{if (insert_separator(0)) return -1;}
+	                | mls_level_def
+			{if (insert_separator(0)) return -1;}
+	                ;
+mls_level_def		: identifier ':' id_comma_list
+			{if (insert_separator(0)) return -1;}
+	                | identifier
+			{if (insert_separator(0)) return -1;}
+	                ;
+id_comma_list           : identifier
+			| id_comma_list ',' identifier
+			;
+tilde			: '~'
+			;
+asterisk		: '*'
+			;
+names           	: identifier
+			{ if (insert_separator(0)) return -1; }
+			| nested_id_set
+			{ if (insert_separator(0)) return -1; }
+			| asterisk
+                        { if (insert_id("*", 0)) return -1; 
+			  if (insert_separator(0)) return -1; }
+			| tilde identifier
+                        { if (insert_id("~", 0)) return -1;
+			  if (insert_separator(0)) return -1; }
+			| 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; }
+			;
+asterisk_push           : asterisk
+                        { if (insert_id("*", 1)) return -1; }
+			;
+names_push		: identifier_push
+			| '{' identifier_list_push '}'
+			| asterisk_push
+			| tilde_push identifier_push
+			| tilde_push '{' identifier_list_push '}'
+			;
+identifier_list_push	: identifier_push
+			| identifier_list_push identifier_push
+			;
+identifier_push		: IDENTIFIER
+			{ if (insert_id(yytext, 1)) return -1; }
+			;
+identifier_list		: identifier
+			| identifier_list identifier
+			;
+nested_id_set           : '{' nested_id_list '}'
+                        ;
+nested_id_list          : nested_id_element | nested_id_list nested_id_element
+                        ;
+nested_id_element       : identifier | '-' { if (insert_id("-", 0)) return -1; } identifier | nested_id_set
+                        ;
+identifier		: IDENTIFIER
+			{ if (insert_id(yytext,0)) return -1; }
+			;
+filesystem		: FILESYSTEM
+                        { if (insert_id(yytext,0)) return -1; }
+                        | IDENTIFIER
+			{ if (insert_id(yytext,0)) return -1; }
+                        ;
+path     		: PATH
+			{ if (insert_id(yytext,0)) return -1; }
+			| QPATH
+			{ yytext[strlen(yytext) - 1] = '\0'; if (insert_id(yytext + 1,0)) return -1; }
+			;
+filename		: FILENAME
+			{ yytext[strlen(yytext) - 1] = '\0'; if (insert_id(yytext + 1,0)) return -1; }
+			;
+number			: NUMBER 
+			{ $$ = strtoul(yytext,NULL,0); }
+			;
+number64		: NUMBER
+			{ $$ = strtoull(yytext,NULL,0); }
+			;
+ipv6_addr		: IPV6_ADDR
+			{ if (insert_id(yytext,0)) return -1; }
+			;
+policycap_def		: POLICYCAP identifier ';'
+			{if (define_polcap()) return -1;}
+			;
+permissive_def		: PERMISSIVE identifier ';'
+			{if (define_permissive()) return -1;}
+
+/*********** module grammar below ***********/
+
+module_policy           : module_def avrules_block
+                        { if (end_avrule_block(pass) == -1) return -1;
+                          if (policydb_index_others(NULL, policydbp, 0)) return -1;
+                        }
+                        ;
+module_def              : MODULE identifier version_identifier ';'
+                        { if (define_policy(pass, 1) == -1) return -1; }
+                        ;
+version_identifier      : VERSION_IDENTIFIER
+                        { if (insert_id(yytext,0)) return -1; }
+			| number
+                        { if (insert_id(yytext,0)) return -1; }
+                        | ipv4_addr_def /* version can look like ipv4 address */
+                        ;
+avrules_block           : avrule_decls avrule_user_defs
+                        ;
+avrule_decls            : avrule_decls avrule_decl
+                        | avrule_decl
+                        ;
+avrule_decl             : rbac_decl
+                        | te_decl
+                        | cond_stmt_def
+                        | require_block
+                        | optional_block
+                        | ';'
+                        ;
+require_block           : REQUIRE '{' require_list '}'
+                        ;
+require_list            : require_list require_decl
+                        | require_decl
+                        ;
+require_decl            : require_class ';'
+                        | require_decl_def require_id_list ';'
+                        ;
+require_class           : CLASS identifier names
+                        { if (require_class(pass)) return -1; }
+                        ;
+require_decl_def        : ROLE        { $$ = require_role; }
+                        | TYPE        { $$ = require_type; }
+                        | ATTRIBUTE   { $$ = require_attribute; }
+                        | ATTRIBUTE_ROLE   { $$ = require_attribute_role; }
+                        | USER        { $$ = require_user; }
+                        | BOOL        { $$ = require_bool; }
+			| TUNABLE     { $$ = require_tunable; }
+                        | SENSITIVITY { $$ = require_sens; }
+                        | CATEGORY    { $$ = require_cat; }
+                        ;
+require_id_list         : identifier
+                        { if ($<require_func>0 (pass)) return -1; }
+                        | require_id_list ',' identifier
+                        { if ($<require_func>0 (pass)) return -1; }
+                        ;
+optional_block          : optional_decl '{' avrules_block '}'
+                        { if (end_avrule_block(pass) == -1) return -1; }
+                          optional_else
+                        { if (end_optional(pass) == -1) return -1; }
+                        ;
+optional_else           : else_decl '{' avrules_block '}'
+                        { if (end_avrule_block(pass) == -1) return -1; }
+                        | /* empty */
+                        ;
+optional_decl           : OPTIONAL
+                        { if (begin_optional(pass) == -1) return -1; }
+                        ;
+else_decl               : ELSE
+                        { if (begin_optional_else(pass) == -1) return -1; }
+                        ;
+avrule_user_defs        : user_def avrule_user_defs
+                        | /* empty */
+                        ;
diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
new file mode 100644
index 0000000..22da338
--- /dev/null
+++ b/checkpolicy/policy_scan.l
@@ -0,0 +1,324 @@
+
+/* 
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 
+ */
+
+/* Updated: David Caplan, <dac@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ *          Jason Tang    <jtang@tresys.com>
+ *
+ *	Added support for binary policy modules
+ *
+ * Copyright (C) 2003-5 Tresys Technology, LLC
+ *	This program is free software; you can redistribute it and/or modify
+ *  	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, version 2.
+ */
+
+/* FLASK */
+
+%{
+#include <sys/types.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+typedef int (* require_func_t)(void);
+
+#ifdef ANDROID
+#include "policy_parse.h"
+#else
+#include "y.tab.h"
+#endif
+
+static char linebuf[2][255];
+static unsigned int lno = 0;
+int yywarn(const char *msg);
+
+void set_source_file(const char *name);
+
+char source_file[PATH_MAX];
+unsigned long source_lineno = 1;
+
+unsigned long policydb_lineno = 1;
+
+unsigned int policydb_errors = 0;
+%}
+
+%option noinput nounput noyywrap
+
+%array
+letter  [A-Za-z]
+digit   [0-9]
+alnum   [a-zA-Z0-9]
+hexval	[0-9A-Fa-f]
+
+%%
+\n.*				{ strncpy(linebuf[lno], yytext+1, 255);
+                                  linebuf[lno][254] = 0;
+                                  lno = 1 - lno; 
+                                  policydb_lineno++;
+				  source_lineno++;
+                                  yyless(1); }
+CLONE |
+clone				{ return(CLONE); }
+COMMON |
+common				{ return(COMMON); }
+CLASS |
+class				{ return(CLASS); }
+CONSTRAIN |
+constrain			{ return(CONSTRAIN); }
+VALIDATETRANS |
+validatetrans			{ return(VALIDATETRANS); }
+INHERITS |
+inherits			{ return(INHERITS); }
+SID |
+sid				{ return(SID); }
+ROLE |
+role				{ return(ROLE); }
+ROLES |
+roles				{ return(ROLES); }
+ROLEATTRIBUTE |
+roleattribute			{ return(ROLEATTRIBUTE);}
+ATTRIBUTE_ROLE |
+attribute_role			{ return(ATTRIBUTE_ROLE);}
+TYPES |
+types				{ return(TYPES); }
+TYPEALIAS |
+typealias			{ return(TYPEALIAS); }
+TYPEATTRIBUTE |
+typeattribute			{ return(TYPEATTRIBUTE); }
+TYPEBOUNDS |
+typebounds			{ return(TYPEBOUNDS); }
+TYPE |
+type				{ return(TYPE); }
+BOOL |
+bool                            { return(BOOL); }
+TUNABLE |
+tunable				{ return(TUNABLE); }
+IF |
+if				{ return(IF); }
+ELSE |
+else				{ return(ELSE); }
+ALIAS |
+alias				{ return(ALIAS); }
+ATTRIBUTE |
+attribute			{ return(ATTRIBUTE); }
+TYPE_TRANSITION |
+type_transition			{ return(TYPE_TRANSITION); }
+TYPE_MEMBER |
+type_member			{ return(TYPE_MEMBER); }
+TYPE_CHANGE |
+type_change			{ return(TYPE_CHANGE); }
+ROLE_TRANSITION |
+role_transition			{ return(ROLE_TRANSITION); }
+RANGE_TRANSITION |
+range_transition		{ return(RANGE_TRANSITION); }
+SENSITIVITY |
+sensitivity			{ return(SENSITIVITY); }
+DOMINANCE |
+dominance			{ return(DOMINANCE); }
+CATEGORY |
+category			{ return(CATEGORY); }
+LEVEL |
+level				{ return(LEVEL); }
+RANGE |
+range				{ return(RANGE); }
+MLSCONSTRAIN |
+mlsconstrain			{ return(MLSCONSTRAIN); }
+MLSVALIDATETRANS |
+mlsvalidatetrans		{ return(MLSVALIDATETRANS); }
+USER |
+user				{ return(USER); }
+NEVERALLOW |
+neverallow		        { return(NEVERALLOW); }
+ALLOW |
+allow			        { return(ALLOW); }
+AUDITALLOW |
+auditallow		        { return(AUDITALLOW); }
+AUDITDENY |
+auditdeny		        { return(AUDITDENY); }
+DONTAUDIT |
+dontaudit                       { return(DONTAUDIT); }
+ALLOWXPERM |
+allowxperm			{ return(ALLOWXPERM); }
+AUDITALLOWXPERM |
+auditallowxperm			{ return(AUDITALLOWXPERM); }
+DONTAUDITXPERM |
+dontauditxperm			{ return(DONTAUDITXPERM); }
+NEVERALLOWXPERM |
+neverallowxperm			{ return(NEVERALLOWXPERM); }
+SOURCE |
+source			        { return(SOURCE); }
+TARGET |
+target			        { return(TARGET); }
+SAMEUSER |
+sameuser			{ return(SAMEUSER);}
+module|MODULE                   { return(MODULE); }
+require|REQUIRE                 { return(REQUIRE); }
+optional|OPTIONAL               { return(OPTIONAL); }
+OR |
+or     			        { return(OR);}
+AND |
+and				{ return(AND);}
+NOT |
+not				{ return(NOT);}
+xor |
+XOR                             { return(XOR); }
+eq |
+EQ				{ return(EQUALS);}
+true |
+TRUE                            { return(CTRUE); } 
+false |
+FALSE                           { return(CFALSE); } 
+dom |
+DOM				{ return(DOM);}
+domby |
+DOMBY				{ return(DOMBY);}
+INCOMP |
+incomp				{ return(INCOMP);}
+fscon |
+FSCON                           { return(FSCON);}
+portcon |
+PORTCON				{ return(PORTCON);}
+netifcon |                     
+NETIFCON			{ return(NETIFCON);}
+nodecon |                     
+NODECON				{ return(NODECON);}
+pirqcon |
+PIRQCON  		        { return(PIRQCON);}
+iomemcon |
+IOMEMCON            		{ return(IOMEMCON);}
+ioportcon |
+IOPORTCON           		{ return(IOPORTCON);}
+pcidevicecon |
+PCIDEVICECON           		{ return(PCIDEVICECON);}
+devicetreecon |
+DEVICETREECON           	{ return(DEVICETREECON);}
+fs_use_xattr |
+FS_USE_XATTR			{ return(FSUSEXATTR);}
+fs_use_task |
+FS_USE_TASK                     { return(FSUSETASK);}
+fs_use_trans |
+FS_USE_TRANS                    { return(FSUSETRANS);}
+genfscon |
+GENFSCON                        { return(GENFSCON);}
+r1 |
+R1				{ return(R1); }
+r2 |
+R2				{ return(R2); }
+r3 |
+R3				{ return(R3); }
+u1 |
+U1				{ return(U1); }
+u2 |
+U2				{ return(U2); }
+u3 |
+U3				{ return(U3); }
+t1 |
+T1				{ return(T1); }
+t2 |
+T2				{ return(T2); }
+t3 |
+T3				{ return(T3); }
+l1 |
+L1				{ return(L1); }
+l2 |
+L2				{ return(L2); }
+h1 |
+H1				{ return(H1); }
+h2 |
+H2				{ return(H2); }
+policycap |
+POLICYCAP			{ return(POLICYCAP); }
+permissive |
+PERMISSIVE			{ return(PERMISSIVE); }
+default_user |
+DEFAULT_USER			{ return(DEFAULT_USER); }
+default_role |
+DEFAULT_ROLE			{ return(DEFAULT_ROLE); }
+default_type |
+DEFAULT_TYPE			{ return(DEFAULT_TYPE); }
+default_range |
+DEFAULT_RANGE			{ return(DEFAULT_RANGE); }
+low-high |
+LOW-HIGH			{ return(LOW_HIGH); }
+high |
+HIGH				{ return(HIGH); }
+low |
+LOW				{ return(LOW); }
+"/"({alnum}|[_\.\-/])*	        { return(PATH); }
+\""/"[ !#-~]*\" 		{ return(QPATH); }
+\"({alnum}|[_\.\-\+\~\: ])+\"	{ return(FILENAME); }
+{letter}({alnum}|[_\-])*([\.]?({alnum}|[_\-]))*	{ return(IDENTIFIER); }
+{digit}+|0x{hexval}+            { return(NUMBER); }
+{alnum}*{letter}{alnum}*        { return(FILESYSTEM); }
+{digit}{1,3}(\.{digit}{1,3}){3}    { return(IPV4_ADDR); }
+{hexval}{0,4}":"{hexval}{0,4}":"({hexval}|[:.])*  { return(IPV6_ADDR); }
+{digit}+(\.({alnum}|[_.])*)?    { return(VERSION_IDENTIFIER); }
+#line[ ]1[ ]\"[^\n]*\"		{ set_source_file(yytext+9); }
+#line[ ]{digit}+	        { source_lineno = atoi(yytext+6)-1; }
+#[^\n]*                         { /* delete comments */ }
+[ \t\f]+			{ /* delete whitespace */ }
+"==" 				{ return(EQUALS); }
+"!="				{ return (NOTEQUAL); }
+"&&"				{ return (AND); }
+"||"				{ return (OR); }
+"!"				{ return (NOT); }
+"^"                             { return (XOR); }
+"," |
+":" |
+";" |
+"(" | 
+")" |
+"{" | 
+"}" |
+"[" |
+"-" |
+"." |
+"]" |
+"~" |
+"*"				{ return(yytext[0]); } 
+.                               { yywarn("unrecognized character");}
+%%
+int yyerror(const 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,
+			policydb_lineno,
+			linebuf[0], linebuf[1]);
+	policydb_errors++;
+	return -1;
+}
+
+int yywarn(const 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,
+			policydb_lineno,
+			linebuf[0], linebuf[1]);
+	return 0;
+}
+
+void set_source_file(const char *name)
+{
+	source_lineno = 1;
+	strncpy(source_file, name, sizeof(source_file)-1); 
+	source_file[sizeof(source_file)-1] = '\0';
+	if (strlen(source_file) && source_file[strlen(source_file)-1] == '"')
+		source_file[strlen(source_file)-1] = '\0';
+}
diff --git a/checkpolicy/queue.c b/checkpolicy/queue.c
new file mode 100644
index 0000000..272079c
--- /dev/null
+++ b/checkpolicy/queue.c
@@ -0,0 +1,180 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * Implementation of the double-ended queue type.
+ */
+
+#include <stdlib.h>
+#include "queue.h"
+
+queue_t queue_create(void)
+{
+	queue_t q;
+
+	q = (queue_t) malloc(sizeof(struct queue_info));
+	if (q == NULL)
+		return NULL;
+
+	q->head = q->tail = NULL;
+
+	return q;
+}
+
+int queue_insert(queue_t q, queue_element_t e)
+{
+	queue_node_ptr_t newnode;
+
+	if (!q)
+		return -1;
+
+	newnode = (queue_node_ptr_t) malloc(sizeof(struct queue_node));
+	if (newnode == NULL)
+		return -1;
+
+	newnode->element = e;
+	newnode->next = NULL;
+
+	if (q->head == NULL) {
+		q->head = q->tail = newnode;
+	} else {
+		q->tail->next = newnode;
+		q->tail = newnode;
+	}
+
+	return 0;
+}
+
+int queue_push(queue_t q, queue_element_t e)
+{
+	queue_node_ptr_t newnode;
+
+	if (!q)
+		return -1;
+
+	newnode = (queue_node_ptr_t) malloc(sizeof(struct queue_node));
+	if (newnode == NULL)
+		return -1;
+
+	newnode->element = e;
+	newnode->next = NULL;
+
+	if (q->head == NULL) {
+		q->head = q->tail = newnode;
+	} else {
+		newnode->next = q->head;
+		q->head = newnode;
+	}
+
+	return 0;
+}
+
+queue_element_t queue_remove(queue_t q)
+{
+	queue_node_ptr_t node;
+	queue_element_t e;
+
+	if (!q)
+		return NULL;
+
+	if (q->head == NULL)
+		return NULL;
+
+	node = q->head;
+	q->head = q->head->next;
+	if (q->head == NULL)
+		q->tail = NULL;
+
+	e = node->element;
+	free(node);
+
+	return e;
+}
+
+queue_element_t queue_head(queue_t q)
+{
+	if (!q)
+		return NULL;
+
+	if (q->head == NULL)
+		return NULL;
+
+	return q->head->element;
+}
+
+void queue_destroy(queue_t q)
+{
+	queue_node_ptr_t p, temp;
+
+	if (!q)
+		return;
+
+	p = q->head;
+	while (p != NULL) {
+		temp = p;
+		p = p->next;
+		free(temp);
+	}
+
+	free(q);
+}
+
+int queue_map(queue_t q, int (*f) (queue_element_t, void *), void *vp)
+{
+	queue_node_ptr_t p;
+	int ret;
+
+	if (!q)
+		return 0;
+
+	p = q->head;
+	while (p != NULL) {
+		ret = f(p->element, vp);
+		if (ret)
+			return ret;
+		p = p->next;
+	}
+	return 0;
+}
+
+void queue_map_remove_on_error(queue_t q,
+			       int (*f) (queue_element_t, void *),
+			       void (*g) (queue_element_t, void *), void *vp)
+{
+	queue_node_ptr_t p, last, temp;
+	int ret;
+
+	if (!q)
+		return;
+
+	last = NULL;
+	p = q->head;
+	while (p != NULL) {
+		ret = f(p->element, vp);
+		if (ret) {
+			if (last) {
+				last->next = p->next;
+				if (last->next == NULL)
+					q->tail = last;
+			} else {
+				q->head = p->next;
+				if (q->head == NULL)
+					q->tail = NULL;
+			}
+
+			temp = p;
+			p = p->next;
+			g(temp->element, vp);
+			free(temp);
+		} else {
+			last = p;
+			p = p->next;
+		}
+	}
+
+	return;
+}
+
+/* FLASK */
diff --git a/checkpolicy/queue.h b/checkpolicy/queue.h
new file mode 100644
index 0000000..655c94b
--- /dev/null
+++ b/checkpolicy/queue.h
@@ -0,0 +1,62 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/* 
+ * A double-ended queue is a singly linked list of 
+ * elements of arbitrary type that may be accessed
+ * at either end.
+ */
+
+#ifndef _QUEUE_H_
+#define _QUEUE_H_
+
+typedef void *queue_element_t;
+
+typedef struct queue_node *queue_node_ptr_t;
+
+typedef struct queue_node {
+	queue_element_t element;
+	queue_node_ptr_t next;
+} queue_node_t;
+
+typedef struct queue_info {
+	queue_node_ptr_t head;
+	queue_node_ptr_t tail;
+} queue_info_t;
+
+typedef queue_info_t *queue_t;
+
+queue_t queue_create(void);
+int queue_insert(queue_t, queue_element_t);
+int queue_push(queue_t, queue_element_t);
+queue_element_t queue_remove(queue_t);
+queue_element_t queue_head(queue_t);
+void queue_destroy(queue_t);
+
+/* 
+   Applies the specified function f to each element in the
+   specified queue. 
+
+   In addition to passing the element to f, queue_map
+   passes the specified void* pointer to f on each invocation.
+
+   If f returns a non-zero status, then queue_map will cease
+   iterating through the hash table and will propagate the error
+   return to its caller.
+ */
+int queue_map(queue_t, int (*f) (queue_element_t, void *), void *);
+
+/*
+   Same as queue_map, except that if f returns a non-zero status,
+   then the element will be removed from the queue and the g
+   function will be applied to the element. 
+ */
+void queue_map_remove_on_error(queue_t,
+			       int (*f) (queue_element_t, void *),
+			       void (*g) (queue_element_t, void *), void *);
+
+#endif
+
+/* FLASK */
diff --git a/checkpolicy/test/Makefile b/checkpolicy/test/Makefile
new file mode 100644
index 0000000..c2367e1
--- /dev/null
+++ b/checkpolicy/test/Makefile
@@ -0,0 +1,21 @@
+#
+# Makefile for building the dispol program
+#
+PREFIX ?= $(DESTDIR)/usr
+BINDIR=$(PREFIX)/bin
+LIBDIR ?= $(PREFIX)/lib
+INCLUDEDIR ?= $(PREFIX)/include
+
+CFLAGS ?= -g -Wall -W -Werror -O2 -pipe
+override CFLAGS += -I$(INCLUDEDIR)
+
+LDLIBS=-lfl $(LIBDIR)/libsepol.a -L$(LIBDIR)
+
+all: dispol dismod
+
+dispol: dispol.o
+
+dismod: dismod.o
+
+clean:
+	-rm -f dispol dismod *.o 
diff --git a/checkpolicy/test/dismod.c b/checkpolicy/test/dismod.c
new file mode 100644
index 0000000..08b039d
--- /dev/null
+++ b/checkpolicy/test/dismod.c
@@ -0,0 +1,1003 @@
+
+/* Authors: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2003,2004,2005 Tresys Technology, LLC
+ *	This program is free software; you can redistribute it and/or modify
+ *  	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, version 2.
+ */
+
+/* 
+ * dismod.c
+ *
+ * Test program to the contents of a binary policy in text
+ * form.
+ *
+ * 	dismod binary_mod_file
+ */
+
+#include <getopt.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/module.h>
+#include <sepol/policydb/util.h>
+#include <sepol/policydb/polcaps.h>
+
+#include <byteswap.h>
+#include <endian.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define le32_to_cpu(x) (x)
+#else
+#define le32_to_cpu(x) bswap_32(x)
+#endif
+
+#define DISPLAY_AVBLOCK_COND_AVTAB	0
+#define DISPLAY_AVBLOCK_UNCOND_AVTAB	1
+#define DISPLAY_AVBLOCK_ROLE_TYPE_NODE	2 /* unused? */
+#define DISPLAY_AVBLOCK_ROLE_TRANS	3
+#define DISPLAY_AVBLOCK_ROLE_ALLOW	4
+#define DISPLAY_AVBLOCK_REQUIRES	5
+#define DISPLAY_AVBLOCK_DECLARES	6
+#define DISPLAY_AVBLOCK_FILENAME_TRANS	7
+
+static policydb_t policydb;
+extern unsigned int ss_initialized;
+
+int policyvers = MOD_POLICYDB_VERSION_BASE;
+
+static const char *symbol_labels[9] = {
+	"commons",
+	"classes", "roles  ", "types  ", "users  ", "bools  ",
+	"levels ", "cats   ", "attribs"
+};
+
+void usage(const char *progname)
+{
+	printf("usage:  %s binary_pol_file\n\n", progname);
+	exit(1);
+}
+
+static void render_access_mask(uint32_t mask, uint32_t class, policydb_t * p,
+			       FILE * fp)
+{
+	char *perm;
+	fprintf(fp, "{");
+	perm = sepol_av_to_string(p, class, mask);
+	if (perm)
+		fprintf(fp, "%s ", perm);
+	fprintf(fp, "}");
+}
+
+static void render_access_bitmap(ebitmap_t * map, uint32_t class,
+				 policydb_t * p, FILE * fp)
+{
+	unsigned int i;
+	char *perm;
+	fprintf(fp, "{");
+	for (i = ebitmap_startbit(map); i < ebitmap_length(map); i++) {
+		if (ebitmap_get_bit(map, i)) {
+			perm = sepol_av_to_string(p, class, 1 << i);
+			if (perm)
+				fprintf(fp, " %s", perm);
+		}
+	}
+	fprintf(fp, " }");
+}
+
+static void display_id(policydb_t * p, FILE * fp, uint32_t symbol_type,
+		       uint32_t symbol_value, const char *prefix)
+{
+	char *id = p->sym_val_to_name[symbol_type][symbol_value];
+	scope_datum_t *scope =
+	    (scope_datum_t *) hashtab_search(p->scope[symbol_type].table, id);
+	assert(scope != NULL);
+	if (scope->scope == SCOPE_REQ) {
+		fprintf(fp, " [%s%s]", prefix, id);
+	} else {
+		fprintf(fp, " %s%s", prefix, id);
+	}
+}
+
+int display_type_set(type_set_t * set, uint32_t flags, policydb_t * policy,
+		     FILE * fp)
+{
+	unsigned int i, num_types;
+
+	if (set->flags & TYPE_STAR) {
+		fprintf(fp, " * ");
+		return 0;
+	} else if (set->flags & TYPE_COMP) {
+		fprintf(fp, " ~");
+	}
+
+	num_types = 0;
+	if (flags & RULE_SELF) {
+		num_types++;
+	}
+
+	for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types);
+	     i++) {
+		if (!ebitmap_get_bit(&set->types, i))
+			continue;
+		num_types++;
+		if (num_types > 1)
+			break;
+	}
+
+	if (num_types <= 1) {
+		for (i = ebitmap_startbit(&set->negset);
+		     i < ebitmap_length(&set->negset); i++) {
+			if (!ebitmap_get_bit(&set->negset, i))
+				continue;
+			num_types++;
+			if (num_types > 1)
+				break;
+		}
+	}
+
+	if (num_types > 1)
+		fprintf(fp, "{");
+
+	for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types);
+	     i++) {
+		if (!ebitmap_get_bit(&set->types, i))
+			continue;
+		display_id(policy, fp, SYM_TYPES, i, "");
+	}
+
+	for (i = ebitmap_startbit(&set->negset);
+	     i < ebitmap_length(&set->negset); i++) {
+		if (!ebitmap_get_bit(&set->negset, i))
+			continue;
+		display_id(policy, fp, SYM_TYPES, i, "-");
+	}
+
+	if (flags & RULE_SELF) {
+		fprintf(fp, " self");
+	}
+
+	if (num_types > 1)
+		fprintf(fp, " }");
+
+	return 0;
+}
+
+int display_mod_role_set(role_set_t * roles, policydb_t * p, FILE * fp)
+{
+	unsigned int i, num = 0;
+
+	if (roles->flags & ROLE_STAR) {
+		fprintf(fp, " * ");
+		return 0;
+	} else if (roles->flags & ROLE_COMP) {
+		fprintf(fp, " ~");
+	}
+
+	for (i = ebitmap_startbit(&roles->roles);
+	     i < ebitmap_length(&roles->roles); i++) {
+		if (!ebitmap_get_bit(&roles->roles, i))
+			continue;
+		num++;
+		if (num > 1) {
+			fprintf(fp, "{");
+			break;
+		}
+	}
+
+	for (i = ebitmap_startbit(&roles->roles);
+	     i < ebitmap_length(&roles->roles); i++) {
+		if (ebitmap_get_bit(&roles->roles, i))
+			display_id(p, fp, SYM_ROLES, i, "");
+	}
+
+	if (num > 1)
+		fprintf(fp, " }");
+
+	return 0;
+
+}
+
+int display_avrule(avrule_t * avrule, policydb_t * policy,
+		   FILE * fp)
+{
+	class_perm_node_t *cur;
+	int num_classes;
+
+	if (avrule == NULL) {
+		fprintf(fp, "  <empty>\n");
+		return 0;
+	}
+	if (avrule->specified & AVRULE_AV) {
+		if (avrule->specified & AVRULE_ALLOWED) {
+			fprintf(fp, "  allow");
+		}
+		if (avrule->specified & AVRULE_AUDITALLOW) {
+			fprintf(fp, "  auditallow ");
+		}
+		if (avrule->specified & AVRULE_DONTAUDIT) {
+			fprintf(fp, "  dontaudit");
+		}
+	} else if (avrule->specified & AVRULE_TYPE) {
+		if (avrule->specified & AVRULE_TRANSITION) {
+			fprintf(fp, "  type_transition");
+		}
+		if (avrule->specified & AVRULE_MEMBER) {
+			fprintf(fp, "  type_member");
+		}
+		if (avrule->specified & AVRULE_CHANGE) {
+			fprintf(fp, "  type_change");
+		}
+	} else if (avrule->specified & AVRULE_NEVERALLOW) {
+		fprintf(fp, "  neverallow");
+	} else {
+		fprintf(fp, "     ERROR: no valid rule type specified\n");
+		return -1;
+	}
+
+	if (display_type_set(&avrule->stypes, 0, policy, fp))
+		return -1;
+
+	if (display_type_set(&avrule->ttypes, avrule->flags, policy, fp))
+		return -1;
+
+	fprintf(fp, " :");
+	cur = avrule->perms;
+	num_classes = 0;
+	while (cur) {
+		num_classes++;
+		if (num_classes > 1)
+			break;
+		cur = cur->next;
+	}
+
+	if (num_classes > 1)
+		fprintf(fp, " {");
+
+	cur = avrule->perms;
+	while (cur) {
+		display_id(policy, fp, SYM_CLASSES, cur->tclass - 1, "");
+		cur = cur->next;
+	}
+
+	if (num_classes > 1)
+		fprintf(fp, " }");
+	fprintf(fp, " ");
+
+	if (avrule->specified & (AVRULE_AV | AVRULE_NEVERALLOW)) {
+		render_access_mask(avrule->perms->data, avrule->perms->tclass,
+				   policy, fp);
+	} else if (avrule->specified & AVRULE_TYPE) {
+		display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, "");
+	}
+
+	fprintf(fp, ";\n");
+
+	return 0;
+}
+
+int display_type_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	type_datum_t *type;
+	FILE *fp;
+	unsigned int i, first_attrib = 1;
+
+	type = (type_datum_t *) datum;
+	fp = (FILE *) data;
+
+	if (type->primary) {
+		display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, "");
+		fprintf(fp, " [%d]: ", type->s.value);
+	} else {
+		/* as that aliases have no value of their own and that
+		 * they can never be required by a module, use this
+		 * alternative way of displaying a name */
+		fprintf(fp, " %s [%d]: ", (char *)key, type->s.value);
+	}
+	if (type->flavor == TYPE_ATTRIB) {
+		fprintf(fp, "attribute for types");
+		for (i = ebitmap_startbit(&type->types);
+		     i < ebitmap_length(&type->types); i++) {
+			if (!ebitmap_get_bit(&type->types, i))
+				continue;
+			if (first_attrib) {
+				first_attrib = 0;
+			} else {
+				fprintf(fp, ",");
+			}
+			display_id(&policydb, fp, SYM_TYPES, i, "");
+		}
+	} else if (type->primary) {
+		fprintf(fp, "type");
+	} else {
+		fprintf(fp, "alias for type");
+		display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, "");
+	}
+	fprintf(fp, " flags:%x\n", type->flags);
+
+	return 0;
+}
+
+int display_types(policydb_t * p, FILE * fp)
+{
+	if (hashtab_map(p->p_types.table, display_type_callback, fp))
+		return -1;
+	return 0;
+}
+
+int display_users(policydb_t * p, FILE * fp)
+{
+	unsigned int i, j;
+	ebitmap_t *bitmap;
+	for (i = 0; i < p->p_users.nprim; i++) {
+		display_id(p, fp, SYM_USERS, i, "");
+		fprintf(fp, ":");
+		bitmap = &(p->user_val_to_struct[i]->roles.roles);
+		for (j = ebitmap_startbit(bitmap); j < ebitmap_length(bitmap);
+		     j++) {
+			if (ebitmap_get_bit(bitmap, j)) {
+				display_id(p, fp, SYM_ROLES, j, "");
+			}
+		}
+		fprintf(fp, "\n");
+	}
+	return 0;
+}
+
+int display_bools(policydb_t * p, FILE * fp)
+{
+	unsigned int i;
+
+	for (i = 0; i < p->p_bools.nprim; i++) {
+		display_id(p, fp, SYM_BOOLS, i, "");
+		fprintf(fp, " : %d\n", p->bool_val_to_struct[i]->state);
+	}
+	return 0;
+}
+
+void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp)
+{
+
+	cond_expr_t *cur;
+	for (cur = exp; cur != NULL; cur = cur->next) {
+		switch (cur->expr_type) {
+		case COND_BOOL:
+			fprintf(fp, "%s ",
+				p->p_bool_val_to_name[cur->bool - 1]);
+			break;
+		case COND_NOT:
+			fprintf(fp, "! ");
+			break;
+		case COND_OR:
+			fprintf(fp, "|| ");
+			break;
+		case COND_AND:
+			fprintf(fp, "&& ");
+			break;
+		case COND_XOR:
+			fprintf(fp, "^ ");
+			break;
+		case COND_EQ:
+			fprintf(fp, "== ");
+			break;
+		case COND_NEQ:
+			fprintf(fp, "!= ");
+			break;
+		default:
+			fprintf(fp, "error!");
+			break;
+		}
+	}
+}
+
+void display_policycon(FILE * fp)
+{
+	/* There was an attempt to implement this at one time.  Look through
+	 * git history to find it. */
+	fprintf(fp, "Sorry, not implemented\n");
+}
+
+void display_initial_sids(policydb_t * p, FILE * fp)
+{
+	ocontext_t *cur;
+	char *user, *role, *type;
+
+	fprintf(fp, "Initial SIDs:\n");
+	for (cur = p->ocontexts[OCON_ISID]; cur != NULL; cur = cur->next) {
+		user = p->p_user_val_to_name[cur->context[0].user - 1];
+		role = p->p_role_val_to_name[cur->context[0].role - 1];
+		type = p->p_type_val_to_name[cur->context[0].type - 1];
+		fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n",
+			cur->u.name, cur->sid[0], user, role, type);
+	}
+#if 0
+	fprintf(fp, "Policy Initial SIDs:\n");
+	for (cur = p->ocontexts[OCON_POLICYISID]; cur != NULL; cur = cur->next) {
+		user = p->p_user_val_to_name[cur->context[0].user - 1];
+		role = p->p_role_val_to_name[cur->context[0].role - 1];
+		type = p->p_type_val_to_name[cur->context[0].type - 1];
+		fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n",
+			cur->u.name, cur->sid[0], user, role, type);
+	}
+#endif
+}
+
+void display_class_set(ebitmap_t *classes, policydb_t *p, FILE *fp)
+{
+	unsigned int i, num = 0;
+
+	for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) {
+		if (!ebitmap_get_bit(classes, i))
+			continue;
+		num++;
+		if (num > 1) {
+			fprintf(fp, "{");
+			break;
+		}
+	}
+
+	for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) {
+		if (ebitmap_get_bit(classes, i))
+			display_id(p, fp, SYM_CLASSES, i, "");
+	}
+
+	if (num > 1)
+		fprintf(fp, " }");
+}
+
+void display_role_trans(role_trans_rule_t * tr, policydb_t * p, FILE * fp)
+{
+	for (; tr; tr = tr->next) {
+		fprintf(fp, "role transition ");
+		display_mod_role_set(&tr->roles, p, fp);
+		display_type_set(&tr->types, 0, p, fp);
+		fprintf(fp, " :");
+		display_class_set(&tr->classes, p, fp);
+		display_id(p, fp, SYM_ROLES, tr->new_role - 1, "");
+		fprintf(fp, "\n");
+	}
+}
+
+void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp)
+{
+	for (; ra; ra = ra->next) {
+		fprintf(fp, "role allow ");
+		display_mod_role_set(&ra->roles, p, fp);
+		display_mod_role_set(&ra->new_roles, p, fp);
+		fprintf(fp, "\n");
+	}
+}
+
+static void display_filename_trans(filename_trans_rule_t * tr, policydb_t * p, FILE * fp)
+{
+	fprintf(fp, "filename transition");
+	for (; tr; tr = tr->next) {
+		display_type_set(&tr->stypes, 0, p, fp);
+		display_type_set(&tr->ttypes, 0, p, fp);
+		display_id(p, fp, SYM_CLASSES, tr->tclass - 1, ":");
+		display_id(p, fp, SYM_TYPES, tr->otype - 1, "");
+		fprintf(fp, " %s\n", tr->name);
+	}
+}
+
+int role_display_callback(hashtab_key_t key __attribute__((unused)),
+			  hashtab_datum_t datum, void *data)
+{
+	role_datum_t *role;
+	FILE *fp;
+
+	role = (role_datum_t *) datum;
+	fp = (FILE *) data;
+
+	fprintf(fp, "role:");
+	display_id(&policydb, fp, SYM_ROLES, role->s.value - 1, "");
+	fprintf(fp, " types: ");
+	display_type_set(&role->types, 0, &policydb, fp);
+	fprintf(fp, "\n");
+
+	return 0;
+}
+
+static int display_scope_index(scope_index_t * indices, policydb_t * p,
+			       FILE * out_fp)
+{
+	unsigned int i;
+	for (i = 0; i < SYM_NUM; i++) {
+		unsigned int any_found = 0, j;
+		fprintf(out_fp, "%s:", symbol_labels[i]);
+		for (j = ebitmap_startbit(&indices->scope[i]);
+		     j < ebitmap_length(&indices->scope[i]); j++) {
+			if (ebitmap_get_bit(&indices->scope[i], j)) {
+				any_found = 1;
+				fprintf(out_fp, " %s",
+					p->sym_val_to_name[i][j]);
+				if (i == SYM_CLASSES) {
+					if (j < indices->class_perms_len) {
+						render_access_bitmap(indices->
+								     class_perms_map
+								     + j, j + 1,
+								     p, out_fp);
+					} else {
+						fprintf(out_fp,
+							"<no perms known>");
+					}
+				}
+			}
+		}
+		if (!any_found) {
+			fprintf(out_fp, " <empty>");
+		}
+		fprintf(out_fp, "\n");
+	}
+	return 0;
+}
+
+#if 0
+int display_cond_expressions(policydb_t * p, FILE * fp)
+{
+	cond_node_t *cur;
+	cond_av_list_t *av_cur;
+	for (cur = p->cond_list; cur != NULL; cur = cur->next) {
+		fprintf(fp, "expression: ");
+		display_expr(p, cur->expr, fp);
+		fprintf(fp, "current state: %d\n", cur->cur_state);
+		fprintf(fp, "True list:\n");
+		for (av_cur = cur->true_list; av_cur != NULL;
+		     av_cur = av_cur->next) {
+			fprintf(fp, "\t");
+			render_av_rule(&av_cur->node->key, &av_cur->node->datum,
+				       RENDER_CONDITIONAL, p, fp);
+		}
+		fprintf(fp, "False list:\n");
+		for (av_cur = cur->false_list; av_cur != NULL;
+		     av_cur = av_cur->next) {
+			fprintf(fp, "\t");
+			render_av_rule(&av_cur->node->key, &av_cur->node->datum,
+				       RENDER_CONDITIONAL, p, fp);
+		}
+	}
+	return 0;
+}
+
+int change_bool(char *name, int state, policydb_t * p, FILE * fp)
+{
+	cond_bool_datum_t *bool;
+
+	bool = hashtab_search(p->p_bools.table, name);
+	if (bool == NULL) {
+		fprintf(fp, "Could not find bool %s\n", name);
+		return -1;
+	}
+	bool->state = state;
+	evaluate_conds(p);
+	return 0;
+}
+#endif
+
+int display_avdecl(avrule_decl_t * decl, int field,
+		   policydb_t * policy, FILE * out_fp)
+{
+	fprintf(out_fp, "decl %u:%s\n", decl->decl_id,
+		(decl->enabled ? " [enabled]" : ""));
+	switch (field) {
+	case DISPLAY_AVBLOCK_COND_AVTAB:{
+			cond_list_t *cond = decl->cond_list;
+			avrule_t *avrule;
+			while (cond) {
+				fprintf(out_fp, "expression: ");
+				display_expr(&policydb, cond->expr, out_fp);
+				fprintf(out_fp, "current state: %d\n",
+					cond->cur_state);
+				fprintf(out_fp, "True list:\n");
+				avrule = cond->avtrue_list;
+				while (avrule) {
+					display_avrule(avrule,
+						       &policydb, out_fp);
+					avrule = avrule->next;
+				}
+				fprintf(out_fp, "False list:\n");
+				avrule = cond->avfalse_list;
+				while (avrule) {
+					display_avrule(avrule,
+						       &policydb, out_fp);
+					avrule = avrule->next;
+				}
+				cond = cond->next;
+			}
+			break;
+		}
+	case DISPLAY_AVBLOCK_UNCOND_AVTAB:{
+			avrule_t *avrule = decl->avrules;
+			if (avrule == NULL) {
+				fprintf(out_fp, "  <empty>\n");
+			}
+			while (avrule != NULL) {
+				if (display_avrule(avrule, policy, out_fp))
+					return -1;
+				avrule = avrule->next;
+			}
+			break;
+		}
+	case DISPLAY_AVBLOCK_ROLE_TYPE_NODE:{	/* role_type_node */
+			break;
+		}
+	case DISPLAY_AVBLOCK_ROLE_TRANS:{
+			display_role_trans(decl->role_tr_rules, policy, out_fp);
+			break;
+		}
+	case DISPLAY_AVBLOCK_ROLE_ALLOW:{
+			display_role_allow(decl->role_allow_rules, policy,
+					   out_fp);
+			break;
+		}
+	case DISPLAY_AVBLOCK_REQUIRES:{
+			if (display_scope_index
+			    (&decl->required, policy, out_fp)) {
+				return -1;
+			}
+			break;
+		}
+	case DISPLAY_AVBLOCK_DECLARES:{
+			if (display_scope_index
+			    (&decl->declared, policy, out_fp)) {
+				return -1;
+			}
+			break;
+		}
+	case DISPLAY_AVBLOCK_FILENAME_TRANS:
+		display_filename_trans(decl->filename_trans_rules, policy,
+				       out_fp);
+		break;
+	default:{
+			assert(0);
+		}
+	}
+	return 0;		/* should never get here */
+}
+
+int display_avblock(int field, policydb_t * policy,
+		    FILE * out_fp)
+{
+	avrule_block_t *block = policydb.global;
+	while (block != NULL) {
+		fprintf(out_fp, "--- begin avrule block ---\n");
+		avrule_decl_t *decl = block->branch_list;
+		while (decl != NULL) {
+			if (display_avdecl(decl, field, policy, out_fp)) {
+				return -1;
+			}
+			decl = decl->next;
+		}
+		block = block->next;
+	}
+	return 0;
+}
+
+int display_handle_unknown(policydb_t * p, FILE * out_fp)
+{
+	if (p->handle_unknown == ALLOW_UNKNOWN)
+		fprintf(out_fp, "Allow unknown classes and perms\n");
+	else if (p->handle_unknown == DENY_UNKNOWN)
+		fprintf(out_fp, "Deny unknown classes and perms\n");
+	else if (p->handle_unknown == REJECT_UNKNOWN)
+		fprintf(out_fp, "Reject unknown classes and perms\n");
+	return 0;
+}
+
+static int read_policy(char *filename, policydb_t * policy)
+{
+	FILE *in_fp;
+	struct policy_file f;
+	int retval;
+	uint32_t buf[1];
+
+	if ((in_fp = fopen(filename, "rb")) == NULL) {
+		fprintf(stderr, "Can't open '%s':  %s\n",
+			filename, strerror(errno));
+		exit(1);
+	}
+	policy_file_init(&f);
+	f.type = PF_USE_STDIO;
+	f.fp = in_fp;
+
+	/* peek at the first byte.  if they are indicative of a
+	   package use the package reader, otherwise use the normal
+	   policy reader */
+	if (fread(buf, sizeof(uint32_t), 1, in_fp) != 1) {
+		fprintf(stderr, "Could not read from policy.\n");
+		exit(1);
+	}
+	rewind(in_fp);
+	if (le32_to_cpu(buf[0]) == SEPOL_MODULE_PACKAGE_MAGIC) {
+		sepol_module_package_t *package;
+		if (sepol_module_package_create(&package)) {
+			fprintf(stderr, "%s:  Out of memory!\n", __FUNCTION__);
+			exit(1);
+		}
+		package->policy = (sepol_policydb_t *) policy;
+		package->file_contexts = NULL;
+		retval =
+		    sepol_module_package_read(package,
+					      (sepol_policy_file_t *) & f, 1);
+		free(package->file_contexts);
+	} else {
+		if (policydb_init(policy)) {
+			fprintf(stderr, "%s:  Out of memory!\n", __FUNCTION__);
+			exit(1);
+		}
+		retval = policydb_read(policy, &f, 1);
+	}
+	fclose(in_fp);
+	return retval;
+}
+
+static void link_module(policydb_t * base, FILE * out_fp)
+{
+	char module_name[80] = { 0 };
+	int ret;
+	policydb_t module, *mods = &module;
+
+	if (base->policy_type != POLICY_BASE) {
+		printf("Can only link if initial file was a base policy.\n");
+		return;
+	}
+	printf("\nModule filename: ");
+	if (fgets(module_name, sizeof(module_name), stdin) == NULL) {
+		fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
+				strerror(errno));
+		exit(1);
+	}
+
+	module_name[strlen(module_name) - 1] = '\0';	/* remove LF */
+	if (module_name[0] == '\0') {
+		return;
+	}
+
+	/* read the binary policy */
+	fprintf(out_fp, "Reading module...\n");
+	if (read_policy(module_name, mods)) {
+		fprintf(stderr,
+			"%s:  error(s) encountered while loading policy\n",
+			module_name);
+		exit(1);
+	}
+	if (module.policy_type != POLICY_MOD) {
+		fprintf(stderr, "This file is not a loadable policy module.\n");
+		exit(1);
+	}
+	if (policydb_index_classes(&module) ||
+	    policydb_index_others(NULL, &module, 0)) {
+		fprintf(stderr, "Could not index module.\n");
+		exit(1);
+	}
+	ret = link_modules(NULL, base, &mods, 1, 0);
+	if (ret != 0) {
+		printf("Link failed (error %d)\n", ret);
+		printf("(You will probably need to restart dismod.)\n");
+	}
+	policydb_destroy(&module);
+	return;
+}
+
+static void display_policycaps(policydb_t * p, FILE * fp)
+{
+	ebitmap_node_t *node;
+	const char *capname;
+	char buf[64];
+	unsigned int i;
+
+	fprintf(fp, "policy capabilities:\n");
+	ebitmap_for_each_bit(&p->policycaps, node, i) {
+		if (ebitmap_node_get_bit(node, i)) {
+			capname = sepol_polcap_getname(i);
+			if (capname == NULL) {
+				snprintf(buf, sizeof(buf), "unknown (%d)", i);
+				capname = buf;
+			}
+			fprintf(fp, "\t%s\n", capname);
+		}
+	}
+}
+
+int menu(void)
+{
+	printf("\nSelect a command:\n");
+	printf("1)  display unconditional AVTAB\n");
+	printf("2)  display conditional AVTAB\n");
+	printf("3)  display users\n");
+	printf("4)  display bools\n");
+	printf("5)  display roles\n");
+	printf("6)  display types, attributes, and aliases\n");
+	printf("7)  display role transitions\n");
+	printf("8)  display role allows\n");
+	printf("9)  Display policycon\n");
+	printf("0)  Display initial SIDs\n");
+	printf("\n");
+	printf("a)  Display avrule requirements\n");
+	printf("b)  Display avrule declarations\n");
+	printf("c)  Display policy capabilities\n");
+	printf("l)  Link in a module\n");
+	printf("u)  Display the unknown handling setting\n");
+	printf("F)  Display filename_trans rules\n");
+	printf("\n");
+	printf("f)  set output file\n");
+	printf("m)  display menu\n");
+	printf("q)  quit\n");
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	FILE *out_fp = stdout;
+	char ans[81], OutfileName[121];
+
+	if (argc != 2)
+		usage(argv[0]);
+
+	/* read the binary policy */
+	fprintf(out_fp, "Reading policy...\n");
+	if (policydb_init(&policydb)) {
+		fprintf(stderr, "%s:  Out of memory!\n", __FUNCTION__);
+		exit(1);
+	}
+	if (read_policy(argv[1], &policydb)) {
+		fprintf(stderr,
+			"%s:  error(s) encountered while loading policy\n",
+			argv[0]);
+		exit(1);
+	}
+
+	if (policydb.policy_type != POLICY_BASE &&
+	    policydb.policy_type != POLICY_MOD) {
+		fprintf(stderr,
+			"This file is neither a base nor loadable policy module.\n");
+		exit(1);
+	}
+
+	if (policydb_index_classes(&policydb)) {
+		fprintf(stderr, "Error indexing classes\n");
+		exit(1);
+	}
+
+	if (policydb_index_others(NULL, &policydb, 1)) {
+		fprintf(stderr, "Error indexing others\n");
+		exit(1);
+	}
+
+	if (policydb.policy_type == POLICY_BASE) {
+		printf("Binary base policy file loaded.\n\n");
+	} else {
+		printf("Binary policy module file loaded.\n");
+		printf("Module name: %s\n", policydb.name);
+		printf("Module version: %s\n", policydb.version);
+		printf("\n");
+	}
+
+	menu();
+	for (;;) {
+		printf("\nCommand (\'m\' for menu):  ");
+		if (fgets(ans, sizeof(ans), stdin) == NULL) {
+			fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
+					strerror(errno));
+			continue;
+		}
+
+		switch (ans[0]) {
+
+		case '1':
+			fprintf(out_fp, "unconditional avtab:\n");
+			display_avblock(DISPLAY_AVBLOCK_UNCOND_AVTAB,
+					&policydb, out_fp);
+			break;
+		case '2':
+			fprintf(out_fp, "conditional avtab:\n");
+			display_avblock(DISPLAY_AVBLOCK_COND_AVTAB,
+					&policydb, out_fp);
+			break;
+		case '3':
+			display_users(&policydb, out_fp);
+			break;
+		case '4':
+			display_bools(&policydb, out_fp);
+			break;
+		case '5':
+			if (hashtab_map
+			    (policydb.p_roles.table, role_display_callback,
+			     out_fp))
+				exit(1);
+			break;
+		case '6':
+			if (display_types(&policydb, out_fp)) {
+				fprintf(stderr, "Error displaying types\n");
+				exit(1);
+			}
+			break;
+		case '7':
+			fprintf(out_fp, "role transitions:\n");
+			display_avblock(DISPLAY_AVBLOCK_ROLE_TRANS,
+					&policydb, out_fp);
+			break;
+		case '8':
+			fprintf(out_fp, "role allows:\n");
+			display_avblock(DISPLAY_AVBLOCK_ROLE_ALLOW,
+					&policydb, out_fp);
+			break;
+		case '9':
+			display_policycon(out_fp);
+			break;
+		case '0':
+			display_initial_sids(&policydb, out_fp);
+			break;
+		case 'a':
+			fprintf(out_fp, "avrule block requirements:\n");
+			display_avblock(DISPLAY_AVBLOCK_REQUIRES,
+					&policydb, out_fp);
+			break;
+		case 'b':
+			fprintf(out_fp, "avrule block declarations:\n");
+			display_avblock(DISPLAY_AVBLOCK_DECLARES,
+					&policydb, out_fp);
+			break;
+		case 'c':
+			display_policycaps(&policydb, out_fp);
+			break;
+		case 'u':
+		case 'U':
+			display_handle_unknown(&policydb, out_fp);
+			break;
+		case 'f':
+			printf
+			    ("\nFilename for output (<CR> for screen output): ");
+			if (fgets(OutfileName, sizeof(OutfileName), stdin) == NULL) {
+				fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
+						strerror(errno));
+				break;
+			}
+			OutfileName[strlen(OutfileName) - 1] = '\0';	/* fix_string (remove LF) */
+			if (strlen(OutfileName) == 0)
+				out_fp = stdout;
+			else if ((out_fp = fopen(OutfileName, "w")) == NULL) {
+				fprintf(stderr, "Cannot open output file %s\n",
+					OutfileName);
+				out_fp = stdout;
+			}
+			if (out_fp != stdout)
+				printf("\nOutput to file: %s\n", OutfileName);
+			break;
+		case 'F':
+			fprintf(out_fp, "filename_trans rules:\n");
+			display_avblock(DISPLAY_AVBLOCK_FILENAME_TRANS,
+					&policydb, out_fp);
+			break;
+		case 'l':
+			link_module(&policydb, out_fp);
+			break;
+		case 'q':
+			policydb_destroy(&policydb);
+			exit(0);
+			break;
+		case 'm':
+			menu();
+			break;
+		default:
+			printf("\nInvalid choice\n");
+			menu();
+			break;
+
+		}
+	}
+	exit(EXIT_SUCCESS);
+}
diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c
new file mode 100644
index 0000000..86f5688
--- /dev/null
+++ b/checkpolicy/test/dispol.c
@@ -0,0 +1,539 @@
+
+/* Authors: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ *	This program is free software; you can redistribute it and/or modify
+ *  	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, version 2.
+ */
+
+/* 
+ * displaypol.c
+ *
+ * Test program to the contents of a binary policy in text
+ * form.  This program currently only displays the
+ * avtab (including conditional avtab) rules.
+ *
+ * 	displaypol binary_pol_file
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/util.h>
+#include <sepol/policydb/polcaps.h>
+#include <getopt.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+static policydb_t policydb;
+
+void usage(const char *progname)
+{
+	printf("usage:  %s binary_pol_file\n\n", progname);
+	exit(1);
+}
+
+int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p,
+		       FILE * fp)
+{
+	char *perm;
+	fprintf(fp, "{");
+	perm = sepol_av_to_string(p, key->target_class, mask);
+	if (perm)
+		fprintf(fp, "%s ", perm);
+	fprintf(fp, "}");
+	return 0;
+}
+
+int render_type(uint32_t type, policydb_t * p, FILE * fp)
+{
+	fprintf(fp, "%s", p->p_type_val_to_name[type - 1]);
+	return 0;
+}
+
+int render_key(avtab_key_t * key, policydb_t * p, FILE * fp)
+{
+	char *stype, *ttype, *tclass;
+	stype = p->p_type_val_to_name[key->source_type - 1];
+	ttype = p->p_type_val_to_name[key->target_type - 1];
+	tclass = p->p_class_val_to_name[key->target_class - 1];
+	if (stype && ttype)
+		fprintf(fp, "%s %s : %s ", stype, ttype, tclass);
+	else if (stype)
+		fprintf(fp, "%s %u : %s ", stype, key->target_type, tclass);
+	else if (ttype)
+		fprintf(fp, "%u %s : %s ", key->source_type, ttype, tclass);
+	else
+		fprintf(fp, "%u %u : %s ", key->source_type, key->target_type,
+			tclass);
+	return 0;
+}
+
+/* 'what' values for this function */
+#define	RENDER_UNCONDITIONAL	0x0001	/* render all regardless of enabled state */
+#define RENDER_ENABLED		0x0002
+#define RENDER_DISABLED		0x0004
+#define RENDER_CONDITIONAL	(RENDER_ENABLED|RENDER_DISABLED)
+
+int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t what,
+		   policydb_t * p, FILE * fp)
+{
+	if (!(what & RENDER_UNCONDITIONAL)) {
+		if (what != RENDER_CONDITIONAL && (((what & RENDER_ENABLED)
+						    && !(key->
+							 specified &
+							 AVTAB_ENABLED))
+						   || ((what & RENDER_DISABLED)
+						       && (key->
+							   specified &
+							   AVTAB_ENABLED)))) {
+			return 0;	/* doesn't match selection criteria */
+		}
+	}
+
+	if (!(what & RENDER_UNCONDITIONAL)) {
+		if (key->specified & AVTAB_ENABLED)
+			fprintf(fp, "[enabled] ");
+		else if (!(key->specified & AVTAB_ENABLED))
+			fprintf(fp, "[disabled] ");
+	}
+
+	if (key->specified & AVTAB_AV) {
+		if (key->specified & AVTAB_ALLOWED) {
+			fprintf(fp, "allow ");
+			render_key(key, p, fp);
+			render_access_mask(datum->data, key, p, fp);
+			fprintf(fp, ";\n");
+		}
+		if (key->specified & AVTAB_AUDITALLOW) {
+			fprintf(fp, "auditallow ");
+			render_key(key, p, fp);
+			render_access_mask(datum->data, key, p, fp);
+			fprintf(fp, ";\n");
+		}
+		if (key->specified & AVTAB_AUDITDENY) {
+			fprintf(fp, "dontaudit ");
+			render_key(key, p, fp);
+			/* We inverse the mask for dontaudit since the mask is internally stored
+			 * as a auditdeny mask */
+			render_access_mask(~datum->data, key, p, fp);
+			fprintf(fp, ";\n");
+		}
+	} else if (key->specified & AVTAB_TYPE) {
+		if (key->specified & AVTAB_TRANSITION) {
+			fprintf(fp, "type_transition ");
+			render_key(key, p, fp);
+			render_type(datum->data, p, fp);
+			fprintf(fp, ";\n");
+		}
+		if (key->specified & AVTAB_MEMBER) {
+			fprintf(fp, "type_member ");
+			render_key(key, p, fp);
+			render_type(datum->data, p, fp);
+			fprintf(fp, ";\n");
+		}
+		if (key->specified & AVTAB_CHANGE) {
+			fprintf(fp, "type_change ");
+			render_key(key, p, fp);
+			render_type(datum->data, p, fp);
+			fprintf(fp, ";\n");
+		}
+	} else if (key->specified & AVTAB_XPERMS) {
+		if (key->specified & AVTAB_XPERMS_ALLOWED)
+			fprintf(fp, "allowxperm ");
+		else if (key->specified & AVTAB_XPERMS_AUDITALLOW)
+			fprintf(fp, "auditallowxperm ");
+		else if (key->specified & AVTAB_XPERMS_DONTAUDIT)
+			fprintf(fp, "dontauditxperm ");
+		render_key(key, p, fp);
+		fprintf(fp, "%s;\n", sepol_extended_perms_to_string(datum->xperms));
+	} else {
+		fprintf(fp, "     ERROR: no valid rule type specified\n");
+		return -1;
+	}
+	return 0;
+}
+
+int display_avtab(avtab_t * a, uint32_t what, policydb_t * p, FILE * fp)
+{
+	unsigned int i;
+	avtab_ptr_t cur;
+
+	/* hmm...should have used avtab_map. */
+	for (i = 0; i < a->nslot; i++) {
+		for (cur = a->htable[i]; cur; cur = cur->next) {
+			render_av_rule(&cur->key, &cur->datum, what, p, fp);
+		}
+	}
+	fprintf(fp, "\n");
+	return 0;
+}
+
+int display_bools(policydb_t * p, FILE * fp)
+{
+	unsigned int i;
+
+	for (i = 0; i < p->p_bools.nprim; i++) {
+		fprintf(fp, "%s : %d\n", p->p_bool_val_to_name[i],
+			p->bool_val_to_struct[i]->state);
+	}
+	return 0;
+}
+
+void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp)
+{
+
+	cond_expr_t *cur;
+	for (cur = exp; cur != NULL; cur = cur->next) {
+		switch (cur->expr_type) {
+		case COND_BOOL:
+			fprintf(fp, "%s ",
+				p->p_bool_val_to_name[cur->bool - 1]);
+			break;
+		case COND_NOT:
+			fprintf(fp, "! ");
+			break;
+		case COND_OR:
+			fprintf(fp, "|| ");
+			break;
+		case COND_AND:
+			fprintf(fp, "&& ");
+			break;
+		case COND_XOR:
+			fprintf(fp, "^ ");
+			break;
+		case COND_EQ:
+			fprintf(fp, "== ");
+			break;
+		case COND_NEQ:
+			fprintf(fp, "!= ");
+			break;
+		default:
+			fprintf(fp, "error!");
+			break;
+		}
+	}
+}
+
+int display_cond_expressions(policydb_t * p, FILE * fp)
+{
+	cond_node_t *cur;
+	cond_av_list_t *av_cur;
+
+	for (cur = p->cond_list; cur != NULL; cur = cur->next) {
+		fprintf(fp, "expression: ");
+		display_expr(p, cur->expr, fp);
+		fprintf(fp, "current state: %d\n", cur->cur_state);
+		fprintf(fp, "True list:\n");
+		for (av_cur = cur->true_list; av_cur != NULL; av_cur = av_cur->next) {
+			fprintf(fp, "\t");
+			render_av_rule(&av_cur->node->key, &av_cur->node->datum,
+				       RENDER_CONDITIONAL, p, fp);
+		}
+		fprintf(fp, "False list:\n");
+		for (av_cur = cur->false_list; av_cur != NULL; av_cur = av_cur->next) {
+			fprintf(fp, "\t");
+			render_av_rule(&av_cur->node->key, &av_cur->node->datum,
+				       RENDER_CONDITIONAL, p, fp);
+		}
+	}
+	return 0;
+}
+
+int display_handle_unknown(policydb_t * p, FILE * out_fp)
+{
+	if (p->handle_unknown == ALLOW_UNKNOWN)
+		fprintf(out_fp, "Allow unknown classes and permisions\n");
+	else if (p->handle_unknown == DENY_UNKNOWN)
+		fprintf(out_fp, "Deny unknown classes and permisions\n");
+	else if (p->handle_unknown == REJECT_UNKNOWN)
+		fprintf(out_fp, "Reject unknown classes and permisions\n");
+	return 0;
+}
+
+int change_bool(char *name, int state, policydb_t * p, FILE * fp)
+{
+	cond_bool_datum_t *bool;
+
+	bool = hashtab_search(p->p_bools.table, name);
+	if (bool == NULL) {
+		fprintf(fp, "Could not find bool %s\n", name);
+		return -1;
+	}
+	bool->state = state;
+	evaluate_conds(p);
+	return 0;
+}
+
+static void display_policycaps(policydb_t * p, FILE * fp)
+{
+	ebitmap_node_t *node;
+	const char *capname;
+	char buf[64];
+	unsigned int i;
+
+	fprintf(fp, "policy capabilities:\n");
+	ebitmap_for_each_bit(&p->policycaps, node, i) {
+		if (ebitmap_node_get_bit(node, i)) {
+			capname = sepol_polcap_getname(i);
+			if (capname == NULL) {
+				snprintf(buf, sizeof(buf), "unknown (%d)", i);
+				capname = buf;
+			}
+			fprintf(fp, "\t%s\n", capname);
+		}
+	}
+}
+
+static void display_id(policydb_t *p, FILE *fp, uint32_t symbol_type,
+		       uint32_t symbol_value, const char *prefix)
+{
+	const char *id = p->sym_val_to_name[symbol_type][symbol_value];
+	fprintf(fp, " %s%s", prefix, id);
+}
+
+static void display_permissive(policydb_t *p, FILE *fp)
+{
+	ebitmap_node_t *node;
+	unsigned int i;
+
+	fprintf(fp, "permissive sids:\n");
+	ebitmap_for_each_bit(&p->permissive_map, node, i) {
+		if (ebitmap_node_get_bit(node, i)) {
+			fprintf(fp, "\t");
+			display_id(p, fp, SYM_TYPES, i - 1, "");
+			fprintf(fp, "\n");
+		}
+	}
+}
+
+static void display_role_trans(policydb_t *p, FILE *fp)
+{
+	role_trans_t *rt;
+
+	fprintf(fp, "role_trans rules:\n");
+	for (rt = p->role_tr; rt; rt = rt->next) {
+		display_id(p, fp, SYM_ROLES, rt->role - 1, "");
+		display_id(p, fp, SYM_TYPES, rt->type - 1, "");
+		display_id(p, fp, SYM_CLASSES, rt->tclass - 1, ":");
+		display_id(p, fp, SYM_ROLES, rt->new_role - 1, "");
+		fprintf(fp, "\n");
+	}
+}
+
+static void display_filename_trans(policydb_t *p, FILE *fp)
+{
+	filename_trans_t *ft;
+
+	fprintf(fp, "filename_trans rules:\n");
+	for (ft = p->filename_trans; ft; ft = ft->next) {
+		display_id(p, fp, SYM_TYPES, ft->stype - 1, "");
+		display_id(p, fp, SYM_TYPES, ft->ttype - 1, "");
+		display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":");
+		display_id(p, fp, SYM_TYPES, ft->otype - 1, "");
+		fprintf(fp, " %s\n", ft->name);
+	}
+}
+
+int menu(void)
+{
+	printf("\nSelect a command:\n");
+	printf("1)  display unconditional AVTAB\n");
+	printf("2)  display conditional AVTAB (entirely)\n");
+	printf("3)  display conditional AVTAG (only ENABLED rules)\n");
+	printf("4)  display conditional AVTAB (only DISABLED rules)\n");
+	printf("5)  display conditional bools\n");
+	printf("6)  display conditional expressions\n");
+	printf("7)  change a boolean value\n");
+	printf("8)  display role transitions\n");
+	printf("\n");
+	printf("c)  display policy capabilities\n");
+	printf("p)  display the list of permissive types\n");
+	printf("u)  display unknown handling setting\n");
+	printf("F)  display filename_trans rules\n");
+	printf("\n");
+	printf("f)  set output file\n");
+	printf("m)  display menu\n");
+	printf("q)  quit\n");
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	FILE *out_fp = stdout;
+	char ans[81], OutfileName[121];
+	int fd, ret;
+	struct stat sb;
+	void *map;
+	char *name;
+	int state;
+	struct policy_file pf;
+
+	if (argc != 2)
+		usage(argv[0]);
+
+	fd = open(argv[1], O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Can't open '%s':  %s\n",
+			argv[1], strerror(errno));
+		exit(1);
+	}
+	if (fstat(fd, &sb) < 0) {
+		fprintf(stderr, "Can't stat '%s':  %s\n",
+			argv[1], strerror(errno));
+		exit(1);
+	}
+	map =
+	    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+	if (map == MAP_FAILED) {
+		fprintf(stderr, "Can't map '%s':  %s\n",
+			argv[1], strerror(errno));
+		exit(1);
+	}
+
+	/* read the binary policy */
+	fprintf(out_fp, "Reading policy...\n");
+	policy_file_init(&pf);
+	pf.type = PF_USE_MEMORY;
+	pf.data = map;
+	pf.len = sb.st_size;
+	if (policydb_init(&policydb)) {
+		fprintf(stderr, "%s:  Out of memory!\n", argv[0]);
+		exit(1);
+	}
+	ret = policydb_read(&policydb, &pf, 1);
+	if (ret) {
+		fprintf(stderr,
+			"%s:  error(s) encountered while parsing configuration\n",
+			argv[0]);
+		exit(1);
+	}
+
+	fprintf(stdout, "binary policy file loaded\n\n");
+	close(fd);
+
+	menu();
+	for (;;) {
+		printf("\nCommand (\'m\' for menu):  ");
+		if (fgets(ans, sizeof(ans), stdin) == NULL) {
+			fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
+					strerror(errno));
+			continue;
+		}
+		switch (ans[0]) {
+
+		case '1':
+			display_avtab(&policydb.te_avtab, RENDER_UNCONDITIONAL,
+				      &policydb, out_fp);
+			break;
+		case '2':
+			display_avtab(&policydb.te_cond_avtab,
+				      RENDER_CONDITIONAL, &policydb, out_fp);
+			break;
+		case '3':
+			display_avtab(&policydb.te_cond_avtab, RENDER_ENABLED,
+				      &policydb, out_fp);
+			break;
+		case '4':
+			display_avtab(&policydb.te_cond_avtab, RENDER_DISABLED,
+				      &policydb, out_fp);
+			break;
+		case '5':
+			display_bools(&policydb, out_fp);
+			break;
+		case '6':
+			display_cond_expressions(&policydb, out_fp);
+			break;
+		case '7':
+			printf("name? ");
+			if (fgets(ans, sizeof(ans), stdin) == NULL) {
+				fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
+						strerror(errno));
+				break;
+			}
+			ans[strlen(ans) - 1] = 0;
+
+			name = malloc((strlen(ans) + 1) * sizeof(char));
+			if (name == NULL) {
+				fprintf(stderr, "couldn't malloc string.\n");
+				break;
+			}
+			strcpy(name, ans);
+
+			printf("state? ");
+			if (fgets(ans, sizeof(ans), stdin) == NULL) {
+				fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
+						strerror(errno));
+				break;
+			}
+			ans[strlen(ans) - 1] = 0;
+
+			if (atoi(ans))
+				state = 1;
+			else
+				state = 0;
+
+			change_bool(name, state, &policydb, out_fp);
+			free(name);
+			break;
+		case '8':
+			display_role_trans(&policydb, out_fp);
+			break;
+		case 'c':
+			display_policycaps(&policydb, out_fp);
+			break;
+		case 'p':
+			display_permissive(&policydb, out_fp);
+			break;
+		case 'u':
+		case 'U':
+			display_handle_unknown(&policydb, out_fp);
+			break;
+		case 'f':
+			printf
+			    ("\nFilename for output (<CR> for screen output): ");
+			if (fgets(OutfileName, sizeof(OutfileName), stdin) == NULL) {
+				fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
+						strerror(errno));
+				break;
+			}
+			OutfileName[strlen(OutfileName) - 1] = '\0';	/* fix_string (remove LF) */
+			if (strlen(OutfileName) == 0)
+				out_fp = stdout;
+			else if ((out_fp = fopen(OutfileName, "w")) == NULL) {
+				fprintf(stderr, "Cannot open output file %s\n",
+					OutfileName);
+				out_fp = stdout;
+			}
+			if (out_fp != stdout)
+				printf("\nOutput to file: %s\n", OutfileName);
+			break;
+		case 'F':
+			display_filename_trans(&policydb, out_fp);
+			break;
+		case 'q':
+			policydb_destroy(&policydb);
+			exit(0);
+			break;
+		case 'm':
+			menu();
+			break;
+		default:
+			printf("\nInvalid choice\n");
+			menu();
+			break;
+
+		}
+	}
+}
+
+/* FLASK */